home *** CD-ROM | disk | FTP | other *** search
/ For Beginners & Professional Hackers / cd.iso / docum / advdos.doc / s1c11 < prev    next >
Encoding:
Text File  |  1992-04-21  |  45.4 KB  |  983 lines

  1. ────────────────────────────────────────────────────────────────────────────
  2. Chapter 11  Memory Management
  3.  
  4.   Current versions of MS-DOS can manage as much as 1 megabyte of contiguous
  5.   random-access memory. On IBM PCs and compatibles, the memory occupied by
  6.   MS-DOS and other programs starts at address 0000H and may reach as high as
  7.   address 09FFFFH; this 640 KB area of RAM is sometimes referred to as
  8.   conventional memory. Memory above this address is reserved for ROM
  9.   hardware drivers, video refresh buffers, and the like. Computers that are
  10.   not IBM compatible may use other memory layouts.
  11.  
  12.   The RAM area under the control of MS-DOS is divided into two major
  13.   sections:
  14.  
  15.   ■  The operating-system area
  16.  
  17.   ■  The transient-program area
  18.  
  19.   The operating-system area starts at address 0000H──that is, it occupies
  20.   the lowest portion of RAM. It holds the interrupt vector table, the
  21.   operating system proper and its tables and buffers, any additional
  22.   installable drivers specified in the CONFIG.SYS file, and the resident
  23.   part of the COMMAND.COM command interpreter. The amount of memory occupied
  24.   by the operating-system area varies with the version of MS-DOS used, the
  25.   number of disk buffers, the size of installed device drivers, and so
  26.   forth.
  27.  
  28.   The transient-program area (TPA), sometimes called the memory arena, is
  29.   the remainder of memory above the operating-system area. The memory arena
  30.   is dynamically allocated in blocks called arena entries. Each arena entry
  31.   has a special control structure called an arena header, and all of the
  32.   arena headers are chained together. Three MS-DOS Int 21H functions allow
  33.   programs to allocate, resize, and release blocks of memory from the TPA:
  34.  
  35.   Function                 Action
  36.   ──────────────────────────────────────────────────────────────────────────
  37.   48H                     Allocate memory block.
  38.   49H                     Release memory block.
  39.   4AH                     Resize memory block.
  40.   ──────────────────────────────────────────────────────────────────────────
  41.  
  42.   MS-DOS itself uses these functions when loading a program from disk at the
  43.   request of COMMAND.COM or another program. The EXEC function, which is the
  44.   MS-DOS program loader, calls Int 21H Function 48H to allocate a memory
  45.   block for the loaded program's environment and another for the program
  46.   itself and its program segment prefix. It then reads the program from the
  47.   disk into the assigned memory area. When the program terminates, MS-DOS
  48.   calls Int 21H Function 49H to release all memory owned by the program.
  49.  
  50.   Transient programs can also employ the MS-DOS memory-management functions
  51.   to dynamically manage the memory available in the TPA. Proper use of these
  52.   functions is one of the most important criteria of whether a program is
  53.   well behaved under MS-DOS. Well-behaved programs are most likely to be
  54.   portable to future versions of the operating system and least likely to
  55.   cause interference with other processes under multitasking user interfaces
  56.   such as Microsoft Windows.
  57.  
  58.  
  59. Using the Memory-Allocation Functions
  60.  
  61.   The memory-allocation functions have two common uses:
  62.  
  63.   ■  To shrink a program's initial memory allocation so that there is enough
  64.      room to load and execute another program under its control.
  65.  
  66.   ■  To dynamically allocate additional memory required by the program and
  67.      to release the same memory when it is no longer needed.
  68.  
  69. Shrinking the Initial Memory Allocation
  70.  
  71.   Although many MS-DOS application programs simply assume they own all
  72.   memory, this assumption is a relic of MS-DOS version 1 (and CP/M), which
  73.   could support only one active process at a time. Well-behaved MS-DOS
  74.   programs take pains to modify only memory that they actually own and to
  75.   release any memory that they don't need.
  76.  
  77.   Unfortunately, under current versions of MS-DOS, the amount of memory that
  78.   a program will own is not easily predicted in advance. It turns out that
  79.   the amount of memory allocated to a program when it is first loaded
  80.   depends upon two factors:
  81.  
  82.   ■  The type of file the program is loaded from
  83.  
  84.   ■  The amount of memory available in the TPA
  85.  
  86.   MS-DOS always allocates all of the largest available memory block in the
  87.   TPA to programs loaded from .COM (memory-image) files. Because .COM
  88.   programs contain no file header that can pass segment and memory-use
  89.   information to MS-DOS, MS-DOS simply assumes the worst case and gives such
  90.   a program everything. MS-DOS will load the program as long as there is an
  91.   available memory block as large as the size of the file plus 256 bytes for
  92.   the PSP and 2 bytes for the stack. The .COM program, when it receives
  93.   control, must determine whether enough memory is available to carry out
  94.   its functions.
  95.  
  96.   MS-DOS uses more complicated rules to allocate memory to programs loaded
  97.   from .EXE files. First, of course, a memory block large enough to hold the
  98.   declared code, data, and stack segments must be available in the TPA. In
  99.   addition, the linker sets two fields in a .EXE file's header to inform
  100.   MS-DOS about the program's memory requirements. The first field,
  101.   MIN_ALLOC, defines the minimum number of paragraphs required by the
  102.   program, in addition to those for the code, data, and stack segments. The
  103.   second, MAX_ALLOC, defines the maximum number of paragraphs of additional
  104.   memory the program would use if they were available.
  105.  
  106.   When loading a .EXE file, MS-DOS first attempts to allocate the number of
  107.   paragraphs in MAX_ALLOC plus the number of paragraphs required by the
  108.   program itself. If that much memory is not available, MS-DOS assigns all
  109.   of the largest available block to the program, provided that this is at
  110.   least the amount specified by MIN_ALLOC plus the size of the program
  111.   image. If that condition is not satisfied, the program cannot be executed.
  112.  
  113.   After a .COM or .EXE program is loaded and running, it can use Int 21H
  114.   Function 4AH (Resize Memory Block) to release all the memory it does not
  115.   immediately need. This is conveniently done right after the program
  116.   receives control from MS-DOS, by calling the resize function with the
  117.   segment of the program's PSP in the ES register and the number of
  118.   paragraphs that the program requires to run in the BX register (Figure
  119.   11-1).
  120.  
  121.   ──────────────────────────────────────────────────────────────────────────
  122.           .
  123.           .
  124.           .
  125.           org     100h
  126.  
  127.   main    proc    near            ; entry point from MS-DOS
  128.                                   ; DS, ES = PSP address
  129.  
  130.           mov     sp,offset stk   ; COM program must move
  131.                                   ; stack to safe area
  132.  
  133.                                   ; release extra memory...
  134.           mov     ah,4ah          ; function 4Ah =
  135.                                   ; resize memory block
  136.                                   ; BX = paragraphs to keep
  137.           mov     bx,(offset stk - offset main + 10FH) / 16
  138.           int     21h             ; transfer to MS-DOS
  139.           jc      error           ; jump if resize failed
  140.           .
  141.           .
  142.           .
  143.   main    endp
  144.  
  145.           .
  146.           .
  147.           .
  148.  
  149.           dw      64 dup (?)      ; new stack area
  150.   stk     equ     $               ; new base of stack
  151.  
  152.           end     main            ; defines entry point
  153.   ──────────────────────────────────────────────────────────────────────────
  154.  
  155.   Figure 11-1.  An example of a .COM program releasing excess memory after
  156.   it receives control from MS-DOS. Int 21H Function 4AH is called with ES
  157.   pointing to the program's PSP and BX containing the number of paragraphs
  158.   that the program needs to execute. In this case, the new size for the
  159.   program's memory block is calculated as the program image size plus the
  160.   size of the PSP (256 bytes), rounded up to the next paragraph. .EXE
  161.   programs use similar code.
  162.  
  163. Dynamic Allocation of Additional Memory
  164.  
  165.   When a well-behaved program needs additional memory space──for an I/O
  166.   buffer or an array of intermediate results, for example──it can call Int
  167.   21H Function 48H (Allocate Memory Block) with the desired number of
  168.   paragraphs. If a sufficiently large block of unallocated memory is
  169.   available, MS-DOS returns the segment address of the base of the assigned
  170.   area and clears the carry flag (0), indicating that the function was
  171.   successful.
  172.  
  173.   If no unallocated block of sufficient size is available, MS-DOS sets the
  174.   carry flag (1), returns an error code in the AX register, and returns the
  175.   size (in paragraphs) of the largest block available in the BX register
  176.   (Figure 11-2). In this case, no memory has yet been allocated. The
  177.   program can use the value returned in the BX register to determine whether
  178.   it can continue in a "degraded" fashion, with less memory. If it can, it
  179.   must call Int 21H Function 48H again to allocate the smaller memory
  180.   block.
  181.  
  182.   When the MS-DOS memory manager is searching the chain of arena headers to
  183.   satisfy a memory-allocation request, it can use one of the following
  184.   strategies:
  185.  
  186.   ■  First fit: Use the arena entry at the lowest address that is large
  187.      enough to satisfy the request.
  188.  
  189.   ■  Best fit: Use the smallest arena entry that will satisfy the request,
  190.      regardless of its location.
  191.  
  192.   ■  Last fit: Use the arena entry at the highest address that is large
  193.      enough to satisfy the request.
  194.  
  195.   ──────────────────────────────────────────────────────────────────────────
  196.                 .
  197.                 .
  198.                 .
  199.                 mov   ah,48h                 ; function 48h = allocate mem block
  200.                 mov   bx,0800h               ; 800h paragraphs = 32 KB
  201.                 int   21h                    ; transfer to MS-DOS
  202.                 jc    error                  ; jump if allocation failed
  203.                 mov   buff_seg,ax            ; save segment of allocated block
  204.                 .
  205.                 .
  206.                 .
  207.                 mov   es,buff_seg            ; ES:DI = address of block
  208.                 xor   di,di
  209.                 mov   cx,08000h              ; store 32,768 bytes
  210.                 mov   al,0ffh                ; fill buffer with -1s
  211.                 cld
  212.                 rep   stosb                  ; now perform fast fill
  213.                 .
  214.                 .
  215.                 .
  216.                 mov   cx,08000h              ; length to write, bytes
  217.                 mov   bx,handle              ; handle for prev opened file
  218.                 push  ds                     ; save our data segment
  219.                 mov   ds,buff_seg            ; let DS:DX = buffer address
  220.                 mov   dx,0
  221.                 mov   ah,40h                 ; function 40h = write
  222.                 int   21h                    ; transfer to MS-DOS
  223.                 pop   ds                     ; restore our data segment
  224.                 jc    error                  ; jump if write failed
  225.                 .
  226.                 .
  227.                 .
  228.                 mov   es,buff_seg            ; ES = seg of prev allocated block
  229.                 mov   ah,49h                 ; function 49h = release mem block
  230.                 int   21h                    ; transfer to MS-DOS
  231.                 jc    error                  ; jump if release failed
  232.                 .
  233.   error:        .
  234.                 .
  235.   handle        dw    0                      ; file handle
  236.   buff_seg      dw    0                      ; segment of allocated block
  237.                 .
  238.                 .
  239.                 .
  240.   ──────────────────────────────────────────────────────────────────────────
  241.  
  242.   Figure 11-2.  Example of dynamic memory allocation. The program requests a
  243.   32 KB memory block from MS-DOS, fills it with -1s, writes it to disk, and
  244.   then releases it.
  245.  
  246.   If the arena entry selected is larger than the size requested, MS-DOS
  247.   divides it into two parts: one block of the size requested, which is
  248.   assigned to the program that called Int 21H Function 48H, and an unowned
  249.   block containing the remaining memory.
  250.  
  251.   The default MS-DOS allocation strategy is first fit. However, under MS-DOS
  252.   versions 3.0 and later, an application program can change the strategy
  253.   with Int 21H Function 58H.
  254.  
  255.   When a program is through with an allocated memory block, it should use
  256.   Int 21H Function 49H to release the block. If it does not, MS-DOS will
  257.   automatically release all memory allocations for the program when it
  258.   terminates.
  259.  
  260.  
  261. Arena Headers
  262.  
  263.   Microsoft has not officially documented the internal structure of arena
  264.   headers for the outside world at present. This is probably to deter
  265.   programmers from trying to manipulate their memory allocations directly
  266.   instead of through the MS-DOS functions provided for that purpose.
  267.  
  268.   Arena headers have identical structures in MS-DOS versions 2 and 3. They
  269.   are 16 bytes (one paragraph) and are located immediately before the memory
  270.   area that they control (Figure 11-3). An arena header contains the
  271.   following information:
  272.  
  273.   ■  A byte signifying whether the header is a member or the last entry in
  274.      the entire chain of such headers
  275.  
  276.   ■  A word indicating whether the area it controls is available or whether
  277.      it already belongs to a program (if the latter, the word points to the
  278.      program's PSP)
  279.  
  280.   ■  A word indicating the size (in paragraphs) of the controlled memory
  281.      area (arena entry)
  282.  
  283.   MS-DOS inspects the chain of arena headers whenever the program requests a
  284.   memory-block allocation, modification, or release function, or when a
  285.   program is EXEC'd or terminated. If any of the blocks appear to be
  286.   corrupted or if the chain is broken, MS-DOS displays the dreaded message
  287.  
  288.   Memory allocation error
  289.  
  290.   and halts the system.
  291.  
  292.   In the example illustrated in Figure 11-3, COMMAND.COM originally loaded
  293.   PROGRAM1.COM into the TPA and, because it was a .COM file, COMMAND.COM
  294.   allocated it all of the TPA, controlled by arena header #1. PROGRAM1.COM
  295.   then used Int 21H Function 4AH (Resize Memory Block) to shrink its memory
  296.   allocation to the amount it actually needed to run and loaded and executed
  297.   PROGRAM2.EXE with the EXEC function (Int 21H Function 4BH). The EXEC
  298.   function obtained a suitable amount of memory, controlled by arena header
  299.   #2, and loaded PROGRAM2.EXE into it. PROGRAM2.EXE, in turn, needed some
  300.   additional memory to store some intermediate results, so it called Int 21H
  301.   Function 48H (Allocate Memory Block) to obtain the area controlled by
  302.   arena header #3. The highest arena header (#4) controls all of the
  303.   remaining TPA that has not been allocated to any program.
  304.  
  305.   ┌─────────────────────────────────────────────────┐ Top of RAM
  306.   │       Unowned RAM controlled by header #4       │  controlled by MS-DOS
  307.   ├─────────────────────────────────────────────────┤
  308.   │                 Arena header #4                 │
  309.   ├─────────────────────────────────────────────────┤
  310.   │ Memory area controlled by header #3; additional │
  311.   │  storage dynamically allocated by PROGRAM2.EXE  │
  312.   ├─────────────────────────────────────────────────┤
  313.   │                 Arena header #3                 │
  314.   ├─────────────────────────────────────────────────┤
  315.   │      Memory area controlled by header #2,       │
  316.   │             containing PROGRAM2.EXE             │
  317.   ├─────────────────────────────────────────────────┤
  318.   │                 Arena header #2                 │
  319.   ├─────────────────────────────────────────────────┤
  320.   │      Memory area controlled by header #1,       │
  321.   │             containing PROGRAM1.COM             │
  322.   ├─────────────────────────────────────────────────┤
  323.   │                 Arena header #1                 │
  324.   └─────────────────────────────────────────────────┘ Bottom of transient-
  325.                                                        program area
  326.  
  327.   Figure 11-3.  An example diagram of MS-DOS arena headers and the
  328.   transient-program area. The environment blocks and their associated
  329.   headers have been omitted from this figure to increase its clarity.
  330.  
  331.  
  332. Lotus/Intel/Microsoft Expanded Memory
  333.  
  334.   When the IBM Personal Computer and MS-DOS were first released, the 640 KB
  335.   limit that IBM placed on the amount of RAM that could be directly managed
  336.   by MS-DOS seemed almost unimaginably huge. But as MS-DOS has grown in both
  337.   size and capabilities and the popular applications have become more
  338.   powerful, that 640 KB has begun to seem a bit crowded. Although personal
  339.   computers based on the 80286 and 80386 have the potential to manage up to
  340.   16 megabytes of RAM under operating systems such as MS OS/2 and XENIX,
  341.   this is little comfort to the millions of users of 8086/8088-based
  342.   computers and MS-DOS.
  343.  
  344.   At the spring COMDEX in 1985, Lotus Development Corporation and Intel
  345.   Corporation jointly announced the Expanded Memory Specification 3.0 (EMS),
  346.   which was designed to head off rapid obsolescence of the older PCs because
  347.   of limited memory. Shortly afterward, Microsoft announced that it would
  348.   support the EMS and would enhance Microsoft Windows to use the memory made
  349.   available by EMS hardware and software. EMS versions 3.2 and 4.0, released
  350.   in fall 1985 and summer 1987, expanded support for multitasking operating
  351.   systems.
  352.  
  353.   The LIM EMS (as it is usually known) has been an enormous success. EMS
  354.   memory boards are available from scores of manufacturers, and "EMS-aware"
  355.   software──especially spreadsheets, disk caches, and terminate-and-stay-
  356.   resident utilities──has become the rule rather than the exception.
  357.  
  358. What Is Expanded Memory?
  359.  
  360.   The Lotus/Intel/Microsoft Expanded Memory Specification is a functional
  361.   definition of a bank-switched memory-expansion subsystem. It consists of
  362.   hardware expansion modules and a resident driver program specific to those
  363.   modules. In EMS versions 3.0 and 3.2, the expanded memory is made
  364.   available to application software as 16 KB pages mapped into a contiguous
  365.   64 KB area called the page frame, somewhere above the main memory area
  366.   used by MS-DOS/PC-DOS (0─640 KB). The exact location of the page frame is
  367.   user configurable, so it need not conflict with other hardware options. In
  368.   EMS version 4.0, the pages may be mapped anywhere in memory and can have
  369.   sizes other than 16 KB.
  370.  
  371.   The EMS provides a uniform means for applications to access as much as 8
  372.   megabytes of memory (32 megabytes in EMS 4.0). The supporting software,
  373.   which is called the Expanded Memory Manager (EMM), provides a
  374.   hardware-independent interface between application software and the
  375.   expanded memory board(s). The EMM is supplied in the form of an
  376.   installable device driver that you link into the MS-DOS/PC-DOS system by
  377.   adding a line to the CONFIG.SYS file on the system boot disk.
  378.  
  379.   Internally, the Expanded Memory Manager consists of two major portions,
  380.   which may be referred to as the driver and the manager. The driver portion
  381.   mimics some of the actions of a genuine installable device driver, in that
  382.   it includes initialization and output status functions and a valid device
  383.   header. The second, and major, portion of the EMM is the true interface
  384.   between application software and the expanded-memory hardware. Several
  385.   classes of services are provided:
  386.  
  387.   ■  Verification of functionality of hardware and software modules
  388.  
  389.   ■  Allocation of expanded-memory pages
  390.  
  391.   ■  Mapping of logical pages into the physical page frame
  392.  
  393.   ■  Deallocation of expanded-memory pages
  394.  
  395.   ■  Support for multitasking operating systems
  396.  
  397.   Application programs communicate with the EMM directly, by means of
  398.   software Int 67H. MS-DOS versions 3.3 and earlier take no part in (and in
  399.   fact are completely oblivious to) any expanded-memory manipulations that
  400.   may occur. MS-DOS version 4.0 and Microsoft Windows, on the other hand,
  401.   are "EMS-aware" and can use the EMS memory when it is available.
  402.  
  403.   Expanded memory should not be confused with extended memory. Extended
  404.   memory is the term used by IBM to refer to the memory at physical
  405.   addresses above 1 megabyte that can be accessed by an 80286 or 80386 CPU
  406.   in protected mode. Current versions of MS-DOS run the 80286 and 80386 in
  407.   real mode (8086-emulation mode), 'nd extended memory is therefore not
  408.   directly accessible.
  409.  
  410. Checking for Expanded Memory
  411.  
  412.   An application program can use either of two methods to test for the
  413.   existence of the Expanded Memory Manager:
  414.  
  415.   ■  Issue an open request (Int 21H Function 3DH) using the guaranteed
  416.      device name of the EMM driver: EMMXXXX0. If the open function succeeds,
  417.      either the driver is present or a file with the same name
  418.      coincidentally exists on the default disk drive. To rule out the
  419.      latter, the application can use IOCTL (Int 21H Function 44H)
  420.      subfunctions 00H and 07H to ensure that EMM is present. In either case,
  421.      the application should then use Int 21H Function 3EH to close the
  422.      handle that was obtained from the open function, so that the handle can
  423.      be reused for another file or device.
  424.  
  425.   ■  Use the address that is found in the Int 67H vector to inspect the
  426.      device header of the presumed EMM. Interrupt handlers and device
  427.      drivers must use this method. If the EMM is present, the name field at
  428.      offset 0AH of the device header contains the string EMMXXXX0. This
  429.      approach is nearly foolproof and avoids the relatively high overhead of
  430.      an MS-DOS open function. However, it is somewhat less well behaved
  431.      because it involves inspection of memory that does not belong to the
  432.      application.
  433.  
  434.   These two methods of testing for the existence of the Expanded Memory
  435.   Manager are illustrated in Figures 11-4 and 11-5.
  436.  
  437.   ──────────────────────────────────────────────────────────────────────────
  438.             .
  439.             .
  440.             .
  441.                                  ; attempt to "open" EMM...
  442.             mov  dx,seg emm_name ; DS:DX = address of name
  443.             mov  ds,dx           ; of Expanded Memory Manager
  444.             mov  dx,offset emm_name
  445.             mov  ax,3d00h        ; function 3dh, mode = 00h
  446.                                  ; = open, read only
  447.             int  21h             ; transfer to MS-DOS
  448.             jc   error           ; jump if open failed
  449.  
  450.                                  ; open succeeded, be sure
  451.                                  ; it was not a file...
  452.             mov  bx,ax           ; BX = handle from open
  453.             mov  ax,4400h        ; function 44h subfunction 00h
  454.                                  ; = IOCTL get device information
  455.             int  21h             ; transfer to MS-DOS
  456.             jc   error           ; jump if IOCTL call failed
  457.             and  dx,80h          ; bit 7 = 1 if character device
  458.             jz   error           ; jump if it was a file
  459.  
  460.                                  ; EMM is present, be sure
  461.                                  ; it is available...
  462.                                  ; (BX still contains handle)
  463.             mov  ax,4407h        ; function 44h subfunction 07h
  464.                                  ; = IOCTL get output status
  465.             int  21h             ; transfer to MS-DOS
  466.             jc   error           ; jump if IOCTL call failed
  467.             or   al,al           ; test device status
  468.             jz   error           ; if AL = 0 EMM is not available
  469.                                  ; now close handle ...
  470.                                  ; (BX still contains handle)
  471.             mov  ah,3eh          ; function 3eh = close
  472.             int  21h             ; transfer to MS-DOS
  473.             jc   error           ; jump if close failed
  474.             .
  475.             .
  476.             .
  477.   emm_name  db   'EMMXXXX0',0    ; guaranteed device name for
  478.                                  ; Expanded Memory Manager
  479.   ──────────────────────────────────────────────────────────────────────────
  480.  
  481.   Figure 11-4.  Testing for the Expanded Memory Manager by means of the
  482.   MS-DOS open and IOCTL functions.
  483.  
  484.   ──────────────────────────────────────────────────────────────────────────
  485.   emm_int   equ  67h            ; Expanded Memory Manager
  486.                                 ; software interrupt
  487.             .
  488.             .
  489.             .
  490.                                 ; first fetch contents of
  491.                                 ; EMM interrupt vector...
  492.             mov  al,emm_int     ; AL = EMM int number
  493.             mov  ah,35h         ; function 35h = get vector
  494.             int  21h            ; transfer to MS-DOS
  495.                                 ; now ES:BX = handler address
  496.  
  497.                                 ; assume ES:0000 points
  498.                                 ; to base of the EMM...
  499.             mov  di,10          ; ES:DI = address of name
  500.                                 ; field in device header
  501.                                 ; DS:SI = EMM driver name
  502.             mov  si,seg emm_name
  503.             mov  ds,si
  504.             mov  si,offset emm_name
  505.             mov  cx,8           ; length of name field
  506.             cld
  507.             repz cmpsb          ; compare names...
  508.             jnz  error          ; jump if driver absent
  509.             .
  510.             .
  511.             .
  512.  
  513.  
  514.   emm_name  db   'EMMXXXX0'     ; guaranteed device name for
  515.                                 ; Expanded Memory Manager
  516.   ──────────────────────────────────────────────────────────────────────────
  517.  
  518.   Figure 11-5.  Testing for the Expanded Memory Manager by inspection of the
  519.   name field in the driver's device header.
  520.  
  521.  
  522. Using Expanded Memory
  523.  
  524.   After establishing that the memory-manager software is present, the
  525.   application program communicates with it directly by means of the "user
  526.   interrupt" 67H, bypassing MS-DOS/PC-DOS. The calling sequence for the EMM
  527.   is as follows:
  528.  
  529.   ──────────────────────────────────────────────────────────────────────────
  530.                     mov  ah,function            ; AH determines service type
  531.                     .                           ; load other registers with
  532.                     .                           ; values specific to the
  533.                     .                           ; requested service
  534.                     int  67h
  535.   ──────────────────────────────────────────────────────────────────────────
  536.  
  537.   In general, AH contains the EMM function number, AL holds the subfunction
  538.   number (if any), BX holds a number of pages (if applicable), and DX
  539.   contains an EMM handle. Registers DS:SI and ES:DI are used to pass the
  540.   addresses of arrays or buffers. Section 4 of this book,
  541.   "Lotus/Intel/Microsoft EMS Functions Reference," details each of the
  542.   expanded memory functions.
  543.  
  544.   Upon return from an EMM function, the AH register contains zero if the
  545.   function was successful; otherwise, it contains an error code with the
  546.   most significant bit set (Figures 11-6 and 11-7). Other values are
  547.   typically returned in the AL and BX registers or in a user-specified
  548.   buffer.
  549.  
  550.  
  551.   Error code         Meaning
  552.   ──────────────────────────────────────────────────────────────────────────
  553.   00H                Function successful.
  554.  
  555.   80H                Internal error in Expanded Memory Manager software
  556.                      (could be caused by corrupted memory image of driver).
  557.  
  558.   81H                Malfunction in expanded-memory hardware.
  559.  
  560.   82H                Memory manager busy.
  561.  
  562.   83H                Invalid handle.
  563.  
  564.   84H                Function requested by application not defined.
  565.  
  566.   85H                No more handles available.
  567.  
  568.   86H                Error in save or restore of mapping context.
  569.  
  570.   87H                Allocation request specified more logical pages than
  571.                      physically available in system; no pages allocated.
  572.  
  573.   88H                Allocation request specified more logical pages than
  574.                      currently available in system (request does not exceed
  575.                      physical pages that exist, but some are already
  576.                      allocated to other handles); no pages allocated.
  577.  
  578.                      Zero pages; cannot be allocated.
  579.  
  580.   8AH                Logical page requested to be mapped located outside
  581.                      range of logical pages assigned to handle.
  582.  
  583.   8BH                Illegal physical page number in mapping request (not in
  584.                      range
  585.  
  586.                      0─3).
  587.  
  588.   8CH                Page-mapping hardware-state save area full.
  589.  
  590.   8DH                Save of mapping context failed; save area already
  591.                      contains context associated with requested handle.
  592.  
  593.   8EH                Restore of mapping context failed; save area does not
  594.                      contain context for requested handle.
  595.  
  596.   8FH                Subfunction parameter not defined.
  597.   ──────────────────────────────────────────────────────────────────────────
  598.  
  599.  
  600.   Figure 11-6.  Expanded Memory Manager error codes common to EMS versions
  601.   3.0, 3.2, and 4.0. After a call to EMM, the AH register contains zero if
  602.   the function was successful or an error code in the range 80H through 8FH
  603.   if the function failed.
  604.  
  605.  
  606.   Error code         Meaning
  607.   ──────────────────────────────────────────────────────────────────────────
  608.   90H                Attribute type not defined.
  609.  
  610.   91H                Feature not supported.
  611.  
  612.   92H                Source and destination memory regions have same handle
  613.                      and overlap; requested move was performed, but part of
  614.                      source region was overwritten.
  615.  
  616.   93H                Specified length for source or destination memory
  617.                      region is longer than actual allocated length.
  618.  
  619.   94H                Conventional-memory region and expanded-memory region
  620.                      overlap.
  621.  
  622.   95H                Specified offset is outside logical page.
  623.  
  624.   96H                Region length exceeds 1 MB.
  625.  
  626.   97H                Source and destination memory regions have same handle
  627.                      and overlap; exchange cannot be performed.
  628.  
  629.   98H                Memory source and destination types undefined.
  630.  
  631.   99H                This error code currently unused.
  632.  
  633.   9AH                Alternate map or DMA register sets supported, but the
  634.                      alternate register set specified is not supported.
  635.  
  636.   9BH                Alternate map or DMA register sets supported, but all
  637.                      alternate register sets currently allocated.
  638.  
  639.   9CH                Alternate map or DMA register sets not supported, and
  640.                      specified alternate register set not zero.
  641.  
  642.   9DH                Alternate map or DMA register sets supported, but
  643.                      alternate register set specified is either not defined
  644.                      or not allocated.
  645.  
  646.                      Dedicated DMA channels not supported.
  647.  
  648.   9FH                Dedicated DMA channels supported, but specified DMA
  649.                      channel not supported.
  650.  
  651.   A0H                No handle found for specified name.
  652.  
  653.   A1H                Handle with this name already exists.
  654.  
  655.   A2H                Memory address wrap; sum of the source or destination
  656.                      region base address and length exceeds 1 MB.
  657.  
  658.   A3H                Invalid pointer passed to function, or contents of
  659.                      source array corrupted.
  660.  
  661.   A4H                Access to function denied by operating system.
  662.   ──────────────────────────────────────────────────────────────────────────
  663.  
  664.  
  665.   Figure 11-7.  Expanded Memory Manager error codes unique to EMS version
  666.   4.0. Most of these errors are related to the EMS functions for use by
  667.   operating systems and would not normally be encountered by application
  668.   programs.
  669.  
  670.   An application program that uses expanded memory should regard that memory
  671.   as a system resource, like a file or a device, and employ only the
  672.   documented EMM services to allocate, access, and release expanded-memory
  673.   pages. Such a program can use the following general strategy:
  674.  
  675.   1.  Establish the presence of the Expanded Memory Manager by one of the
  676.       two methods demonstrated in Figures 11-4 and 11-5.
  677.  
  678.   2.  After the driver is known to be present, check its operational status
  679.       with EMS Function 40H.
  680.  
  681.   3.  Check the version number of EMM with EMS Function 46H, to ensure that
  682.       all services the application will request are available.
  683.  
  684.   4.  Obtain the segment of the page frame used by EMM with EMS Function
  685.       41H.
  686.  
  687.   5.  Allocate the desired number of expanded-memory pages with EMS Function
  688.       43H. If the allocation is successful, EMM returns a handle that the
  689.       application can use to refer to the expanded-memory pages that it
  690.       owns. This step is exactly analogous to opening a file and using the
  691.       handle obtained from the open function for read/write operations on
  692.       the file.
  693.  
  694.   6.  If the requested number of pages are not available, the application
  695.       can query EMM for the actual number of pages available (EMS Function
  696.       42H) and determine whether it can continue.
  697.  
  698.   7.  After the application has successfully allocated the needed number of
  699.       expanded-memory pages, it uses EMS Function 44H to map logical pages
  700.       in and out of the physical page frame in order to store and retrieve
  701.       data in expanded memory.
  702.  
  703.   8.  When the program finishes using its expanded-memory pages, it must
  704.       release them by calling EMS Function 45H. Otherwise, the pages will
  705.       be lost to use by other programs until the system is restarted.
  706.  
  707.   Figure 11-8 shows a skeleton program that illustrates this general
  708.   approach.
  709.  
  710.   An interrupt handler or device driver that uses EMS follows the same
  711.   general procedure outlined in steps 1 through 8, with a few minor
  712.   variations. It may need to acquire an EMS handle and allocate pages before
  713.   the operating system is fully functional; in particular, you cannot assume
  714.   that the MS-DOS Open File or Device, IOCTL, and Get Interrupt Vector
  715.   functions are available. Thus, such a handler or driver must use a
  716.   modified version of the "get interrupt vector" technique (Figure 11-5) to
  717.   test for the existence of EMM, fetching the contents of the Int 67H vector
  718.   directly.
  719.  
  720.   A device driver or interrupt handler typically owns its expanded-memory
  721.   pages permanently (until the system is restarted) and never deallocates
  722.   them. Such a program must also take care to save and restore EMM's
  723.   page-mapping context (EMS Functions 47H and 48H) whenever it accesses
  724.   expanded memory, so that use of EMS by a foreground program will not
  725.   be disturbed.
  726.  
  727.   The EMM relies on the good behavior of application software to avoid the
  728.   corruption of expanded memory. If several applications that use expanded
  729.   memory are running under a multitasking manager such as Microsoft Windows
  730.   and one or more of them does not abide strictly by EMM conventions, the
  731.   data of some or all of the applications may be destroyed.
  732.  
  733.   ──────────────────────────────────────────────────────────────────────────
  734.             .
  735.             .
  736.             .
  737.             mov  ah,40h         ; test EMM status
  738.             int  67h
  739.             or   ah,ah
  740.             jnz  error          ; jump if bad status from EMM
  741.  
  742.             mov  ah,46h         ; check EMM version
  743.             int  67h
  744.             or   ah,ah
  745.             jnz  error          ; jump if couldn't get version
  746.  
  747.             cmp  al,030h        ; make sure at least ver 3.0
  748.             jb   error          ; jump if wrong EMM version
  749.             mov  ah,41h         ; get page frame segment
  750.             int  67h
  751.             or   ah,ah
  752.             jnz  error          ; jump if failed to get frame
  753.             mov  page_frame,bx  ; save segment of page frame
  754.  
  755.             mov  ah,42h         ; get number of available pages
  756.             int  67h
  757.             or   ah,ah
  758.             jnz  error          ; jump if get pages error
  759.             mov  total_pages,dx ; save total EMM pages
  760.             mov  avail_pages,bx ; save available EMM pages
  761.             or   bx,bx
  762.             jz   error          ; abort if no pages available
  763.  
  764.             mov  ah,43h         ; try to allocate EMM pages
  765.             mov  bx,needed_pages
  766.             int  67h            ; if allocation is successful
  767.             or   ah,ah
  768.             jnz  error          ; jump if allocation failed
  769.  
  770.             mov  emm_handle,dx  ; save handle for allocated pages
  771.  
  772.             .
  773.             .                   ; now we are ready for other
  774.             .                   ; processing using EMM pages
  775.             .
  776.                                 ; map in EMS memory page...
  777.             mov  bx,log_page    ; BX <- EMS logical page number
  778.             mov  al,phys_page   ; AL <- EMS physical page (0-3)
  779.             mov  dx,emm_handle  ; EMM handle for our pages
  780.             mov  ah,44h         ; function 44h = map EMS page
  781.             int  67h
  782.             or   ah,ah
  783.             jnz  error          ; jump if mapping error
  784.  
  785.             .
  786.             .
  787.             .                   ; program ready to terminate,
  788.                                 ; give up allocated EMM pages...
  789.             mov  dx,emm_handle  ; handle for our pages
  790.             mov  ah,45h         ; EMS function 45h = release pages
  791.             int  67h
  792.             or   ah,ah
  793.             jnz  error          ; jump if release failed
  794.             .
  795.             .
  796.             .
  797.   ──────────────────────────────────────────────────────────────────────────
  798.  
  799.   Figure 11-8.  A program illustrating the general strategy for using
  800.   expanded memory.
  801.  
  802.  
  803. Extended Memory
  804.  
  805.   Extended memory is RAM storage at addresses above 1 megabyte (100000H)
  806.   that can be accessed by an 80286 or 80386 processor running in protected
  807.   mode. IBM PC/AT─ and PS/2─compatible machines can (theoretically) have as
  808.   much as 15 MB of extended memory installed, in addition to the usual 1 MB
  809.   of conventional memory.
  810.  
  811.   Protected-mode operating systems such as Microsoft XENIX or MS OS/2 can
  812.   use extended memory for execution of programs. MS-DOS, on the other hand,
  813.   runs in real mode on an 80286 or 80386, and programs running under its
  814.   control cannot ordinarily execute from extended memory or even address
  815.   that memory for storage of data. However, the ROM BIOS contains two
  816.   routines that allow real-mode programs restricted access to extended
  817.   memory:
  818.  
  819.   ROM BIOS function                    Action
  820.   ──────────────────────────────────────────────────────────────────────────
  821.   Int 15H Function 87H                Move extended-memory block.
  822.   Int 15H Function 88H                Get extended-memory size.
  823.   ──────────────────────────────────────────────────────────────────────────
  824.  
  825.   These routines can be used by electronic disks (RAMdisks) and by other
  826.   programs that want to use extended memory for fast storage and retrieval
  827.   of information that would otherwise have to be written to a slower
  828.   physical disk drive. Section 3 of this book, "IBM ROM BIOS and Mouse
  829.   Functions Reference," documents both of these functions.
  830.  
  831.   You should use these ROM BIOS routines with caution. Data stored in
  832.   extended memory is, of course, volatile; it is lost if the machine is
  833.   turned off. The transfer of data to or from extended memory involves a
  834.   switch from real mode to protected mode and back, which is a relatively
  835.   slow process on 80286-based machines; in some cases it is only marginally
  836.   faster than actually reading the data from a fixed disk. In addition,
  837.   programs that use the ROM BIOS extended-memory functions are not
  838.   compatible with the MS-DOS compatibility mode of MS OS/2.
  839.  
  840.   Finally, a major deficit in these ROM BIOS functions is that they do not
  841.   make any attempt to arbitrate between two or more programs or drivers that
  842.   are using extended memory for temporary storage. For example, if an
  843.   application program and an installed RAMdisk driver attempt to put data in
  844.   the same area of extended memory, no error will be returned to either
  845.   program, but the data of one or both may be destroyed.
  846.  
  847.   Figure 11-9 shows an example of the code necessary to transfer data to
  848.   and from extended memory.
  849.  
  850.   ──────────────────────────────────────────────────────────────────────────
  851.   bmdt    db      30h dup (0)     ; block move descriptor table
  852.  
  853.   buff1   db      80h dup ('?')   ; source buffer
  854.   buff2   db      80h dup (0)     ; destination buffer
  855.  
  856.           .
  857.           .
  858.           .
  859.  
  860.                                   ; copy 'buff1' to extended-
  861.                                   ; memory address 100000h
  862.           mov     dx,10h          ; DX:AX = destination
  863.           mov     ax,0            ; extended-memory address
  864.           mov     bx,seg buff1    ; DS:BX = source conventional-
  865.           mov     ds,bx           ; memory address
  866.           mov     bx,offset buff1
  867.           mov     cx,80h          ; CX = bytes to move
  868.           mov     si,seg bmdt     ; ES:SI = block move
  869.           mov     es,si           ; descriptor table
  870.           mov     si,offset bmdt
  871.           call    putblk          ; request transfer
  872.  
  873.  
  874.                                   ; fill buff2 from extended-
  875.                                   ; memory address 100000h
  876.           mov     dx,10h          ; DX:AX = source extended-
  877.           mov     ax,0            ; memory address
  878.           mov     bx,seg buff2    ; DS:BX = destination
  879.           mov     ds,bx           ; conventional-memory address
  880.           mov     bx,offset buff2
  881.           mov     cx,80h          ; CX = bytes to move
  882.           mov     si,seg bmdt     ; ES:SI = block move
  883.           mov     es,si           ; descriptor table
  884.           mov     si,offset bmdt
  885.           call    getblk          ; request transfer
  886.  
  887.           .
  888.           .
  889.           .
  890.   getblk  proc    near            ; transfer block from extended
  891.                                   ; memory to real memory
  892.                                   ; call with
  893.                                   ; DX:AX = source linear 32-bit
  894.                                   ;         extended-memory address
  895.                                   ; DS:BX = segment and offset
  896.                                   ;         destination address
  897.                                   ; CX    = length in bytes
  898.                                   ; ES:SI = block move descriptor
  899.                                   ;         table
  900.                                   ; returns
  901.                                   ; AH    = 0 if transfer OK
  902.  
  903.           mov     es:[si+10h],cx  ; store length into descriptors
  904.           mov     es:[si+18h],cx
  905.  
  906.                                   ; store access rights bytes
  907.           mov     byte ptr es:[si+15h],93h
  908.           mov     byte ptr es:[si+1dh],93h
  909.  
  910.           mov     es:[si+12h],ax  ; source extended-memory address
  911.           mov     es:[si+14h],dl
  912.  
  913.                                   ; convert destination segment
  914.                                   ; and offset to linear address
  915.           mov     ax,ds           ; segment * 16
  916.           mov     dx,16
  917.           mul     dx
  918.           add     ax,bx           ; + offset -> linear address
  919.           adc     dx,0
  920.  
  921.           mov     es:[si+1ah],ax  ; store destination address
  922.           mov     es:[si+1ch],dl
  923.  
  924.           shr     cx,1            ; convert length to words
  925.           mov     ah,87h          ; int 15h function 87h = block move
  926.           int     15h             ; transfer to ROM BIOS
  927.  
  928.           ret                     ; back to caller
  929.  
  930.   getblk  endp
  931.   putblk  proc    near            ; transfer block from real
  932.                                   ; memory to extended memory
  933.                                   ; call with
  934.                                   ; DX:AX = dest linear 32-bit
  935.                                   ;         extended-memory address
  936.                                   ; DS:BX = segment and offset
  937.                                   ;         source address
  938.                                   ; CX    = length in bytes
  939.                                   ; ES:SI = block move descriptor
  940.                                   ;         table
  941.                                   ; returns
  942.                                   ; AH    = 0 if transfer OK
  943.  
  944.           mov     es:[si+10h],cx  ; store length into descriptors
  945.           mov     es:[si+18h],cx
  946.  
  947.                                   ; store access rights bytes
  948.           mov     byte ptr es:[si+15h],93h
  949.           mov     byte ptr es:[si+1dh],93h
  950.  
  951.           mov     es:[si+1ah],ax  ; store destination extended-
  952.           mov     es:[si+1ch],dl  ; memory address
  953.  
  954.                                   ; convert source segment and
  955.                                   ; offset to linear address
  956.           mov     ax,ds           ; segment * 16
  957.           mov     dx,16
  958.           mul     dx
  959.           add     ax,bx           ; + offset -> linear address
  960.           adc     dx,0
  961.           mov     es:[si+12h],ax  ; store source address
  962.           mov     es:[si+14h],dl
  963.  
  964.           shr     cx,1            ; convert length to words
  965.           mov     ah,87h          ; int 15h function 87h = block move
  966.           int     15h             ; transfer to ROM BIOS
  967.  
  968.           ret                     ; back to caller
  969.  
  970.   putblk  endp
  971.   ──────────────────────────────────────────────────────────────────────────
  972.  
  973.   Figure 11-9.  Moving blocks of data between conventional memory and
  974.   extended memory, using the ROM BIOS extended-memory functions. For
  975.   additional information on the format of the block move descriptor table,
  976.   see the entry for Int 15H Function 87H in Section 3 of this book, "IBM
  977.   ROM BIOS and Mouse Functions Reference." Note that you must specify the
  978.   extended-memory address as a 32-bit linear address rather than as a
  979.   segment and offset.
  980.  
  981.  
  982.  
  983.