A Comparison of EMS 4.0 with EMS and EEMS 3.2 Report by Stephen T. Satchell Revision B, September 17, 1987 ____________________________________________________________ Copyright 1987 Satchell Evaluations. Permission is granted to all persons to freely duplicate and distribute this information with the following restrictions: (1) This document is transferred unmofigirf, with all notices in place. (2) No fee may be directly or indirectly charged for this information EXCEPT by (a) on-line services and bulletin board systems that charge for access so long as no surcharge applied to this file, and (b) by professional computer societies (ACM, IEEE Computer and the like) which regularly publish a journal or magazine. User groups and for-profit groups are specifically prohibited from selling media (paper or machine readable) containing this information. Permission for other uses may be requested from Satchell Evaluations, 16 Searing Avenue, Morristown NJ 07960. The author asks that people using any exerpt from this report contact him to insure the information is accurate to the author's best knowledge before publication. This document is the result of the author's own initiative, and is not work for hire. This work is derived from three published documents: (1) _The Lotus/Intel/Microsoft Expanded Memory Specification_ Version 3.20 September 1985, (2) _Enhanced Expanded Memory Specification Version 3.20 June 1986, and (3) _Lotus/Intel/Microsoft Expanded Memory Specification_ Version 4.0 August 1987 (final printed version) The prior revision of this document was based on a laser printed manuscript. Another document mentioned here is the _Generic Accelerator Card Driver (GACD) Specification_ available from AST Research Inc. Intel is a trademark of Intel Corporation. Lotus is a trademark of Lotus Development Corporation. Microsoft is a trademark of Microsoft Corporation. ____________________________________________________________ Preface to Revision B: ---------------------- The original version of this document was based on the EMS 4.0 specification handed out to the press at the August 19th announcement. Since then, Intel informed the author that this copy of the specification was preliminary and contained several errors that are corrected in the final printed version of the specification. Unfortunately, both documents carry the same version, part number and date. The ONLY difference is that the correct document is in the 5x8.5 format, while the document containing errors is 8.5x11. The original of this document was in two pieces: the comparision and a separate error/problem sheet. These two pieces are now combined into the single document as the elimination of the typos "correct" the problems found. Programmers are urged to consider that some of the driver implementers are human, and might read things into the specification that simply are not true. IN SHORT, WATCH OUT FOR BOUNDARY VIOLATIONS BY ENHANCED MEMORY MANAGERS. The author understands the difference between physical and logical pages, but in some parts of the prior version of this document the author got mixed up and swapped terms. This has been corrected. A physical page is a 16 KB location in the 1 MB address space of the 80x86 system, while a logical page is a block of RAM that can be mapped into a physical page. 'Nuff said. Sorry. The section on limits has been expanded considerably, based on documents from both Intel and AST. Other sections have been expanded as well, including minor corrections. Buried in the back of the specification, this statement appears: ``To support generic accelerator cards, the support of Function 34, as defined by AST, is encouraged.'' Unfortunately, all copies of the AST EEMS specification in my posession do not have any concrete description of this function, and Intel didn't include this information. Interested persons should contact AST and ask for a copy of the _Generic Accelerator Card Driver (GACD) Specification_. I will attempt to obtain a copy of this and include the information in a future revision of this document. ____________________________________________________________ INTRODUCTION ------------ On August 19, 1987, the new version of the Expanded Memory Specification (EMS) was announced by Lotus, Intel and Microsoft. This new version of the specification includes many features of the Enhanced Expanded Memory Specification (EEMS) originally developed by AST Reserach, Quadram and Ashton-Tate, although the three original sponsoring companies elected not to make the new specification upward compatible with EEMS. AST Research indicated in a separate statement that they would endorse EMS 4.0 without reservation. An important aside unrelated to this document is that Lotus Development Corporation has stated that pure software implementations of EMS 4.0 (those that do not use either dedicated memory hardware, PS/2 T-RAM or 80386 page mapping) will not be supported by Lotus products. This paper attempts to compare EMS 4.0 with both EMS 3.2 and EEMS 3.2 specifications, by looking at each function. This is not intended to republish the specification -- interested parties are urged to contact Intel Corporation at (800) 538-3373 and ask for the "EMS 4.0 Developers Kit". The functions will be listed by hexidemical code, not by abstract function number. This is of more use to developers since they tend to think of the functions based on the value loaded into the registers, not by an index. Where subfunctions are defined (such as in function 4Eh "Page Map Functions" the function and subfunction will be separated by a slash. Within the body of the text, I will indicate whether the EMS 4.0 function is upwardly compatible with the older specifications. This document can also serve as a quick reference to those programmers already familiar with the EMS 4.0 specification and wanting a synopsis of the calling sequences for EMS operations. Programmers and interested parties wishing to fully understand the implications of each function is urged to examine the Base Document, _Lotus/Intel/Microsoft Expanded Memory Specification_ Version 4.0, available from Intel by calling (800) 538-3373 and asking for the EMS 4.0 Developers Kit. MAJOR DIFFERENCES ----------------- One significant change is that the total amount of memory managed by an Expanded Memory Manager (EMM) has grown from 8 megabytes to "full-tilt-boogy" 32 megabytes (to quote a recent _InfoWorld_ article) -- 512 pages to 2048 pages of 16 KB each. In this author's opinion, there is no reason a programmer should assume this is the absolute limit. THAT is dictated by the use of 16 bit signed values for page numbers, capping capacity at 32768 pages of 16 KB each -- 512 megabytes of RAM. Programs can interrogate the EMM for the actual amount available and tailor operations accordingly. Note the developers do not indicate whether the word values used for pages are signed or unsigned. If the values are intended to be unsigned, then 65535 (with page value FFFFh treated as a special value) can exist, or 16 KB short of one gigabyte of RAM in a single system. DEFINITION OF LIMITS -------------------- This is the worst part of the specification, since in no single place does the spec writers completely list the assumptions about limits, let alone future directions concerning those limits. Here is the author's ideas of the limits that drive the specification. Where possible the author has erred toward the more inclusive. Maximum RAM: 32 MB today, future 512 MB Minimum number of logical pages: 4 (64 KB). Maximum number of logical pages: 2048 today, future 32768. Minimum number of physical pages: 4 (64 KB). Maximum number of physical pages: 64 (full 1 MB space). Minimum number of handles: 64 (includes OS handle 00h). Maximum number of handles: 255 (includes OS handle 00h). Minimum # EMS 3.2 page maps: one per handle Maximum # EMS 3.2 page maps: unbounded Maximum size of mem reg array: 254 bytes The "page maps" refer to contexts saved by functions 47h and 48h, Save Page Map and Restore Page Map. The number of logical pages in a particular system can be obtained using function 42h; this also has the useful side effect of telling you the number of free pages as well. The number of physical pages in a particular system can be obtained by using function 58h/01h and the particular mapping by using function 58h/00h. Should this function fail, you can assume you have four pages starting at the segment returned by function 41h. The maximum number of handles that can be defined is 255. For those implementations that do not do any mapping in conventional memory, you can have 255 user handles. For those implementations that map into conventional memory, you can have 254 user handles and the special operating system handle. Note that handle values can range from 01h to FFh in the first case, or from 00h to FEh in the second. The maximum number of handles in a particular system can be obtained by using function 54h/02h. Should this function fail, you can make no assumptions about the number of handles available. GOTCHAS ------- This section is what was left from the errata file in the prior version. If you prefer to work with possibly incorrect implementations of the EMS specification, pay particular heed to the comments here, as they can save you untold grief when you (and other programs in a system) stretch an expanded memory manager to the limit and beyond. The author makes NO claim that he has found all of these; if you discover another, please let the author know so he can add your new gotcha to the next revision (and you will receive credit for your contribution). 46h -- Get Version [7] === There exists some confusion whether the version returned is the specification supported or the version number of the driver. Programmers are united in stating this should be the specification version supported, while at least one vendor (Intel) is known to use this function to return the software version of the particular implementation. The wording of the description indicates that the vendor revision is intended, and thus is useless to programmers wishing to be able to adapt to the environment they encounter. The author considers this a severe weakness in the specification. Either a different function should be provided for returning vendor specific version information or other means for obtaining the current implementation version should be provided and documented by each vendor. Function 4Dh, Get All Handles [14] ============ BX is specified to have a maximum value of 255. A non-conforming implementation could indeed allow 256 handles, assuming that since handles can range in value from 00h to FFh that the full range should be implemented. Consider allowing for 256 entries in the array instead of the 255 entries as indicated in the example for this function. There is also a problem with identifying the difference between a raw handle and a standard handle. Currently there is no facility to make this determination. Obviously the program making the allocation needs to keep this straight, but another program happening onto a raw handle (such as a debug program) has no way of really knowing. Unfortunate oversight, especially since the specification makes no comment about whether the page count is EMS pages, raw pages, or a funny number. Function 54h Subfunction 00h, Get Handle Directory [21/0] ============ Consider allow for 256 names in the handle directory array instead of 255 should a particular implementation violate the limit set up in the specification. Function 56h Subfunctions 00h/01h, Alter Page Map and Call [23] ============ The function description indicates that register and flag contents (except for AX) are preserved going to the called function. This means that BX, CX, DI, and ES are available for passing values to the called function. Although not explicit, the flags and all registers EXCEPT AX are unmodified when returning from the remotely called function. Since many compilers use AX to return integer values from functions, there needs to be examples showing how to preserve the value when making EMS calls. This may indeed require direct compiler support...something that will not happen overnight. The specification does not indicate whether the EMM handle passed in DX must describe pages contained by both calling and called routines, or whether there can be two different handles involved as well. MISSING ======= A function to return the current logical->physical mapping in a vendor-independent manner. This would be exceedingly useful in debuggers. FUNCTIONS DEFINED IN EMS 3.2 SPECIFICATION ------------------------------------------ 40h -- Get Status [1] === On call: AH = 40h On return: AH = error status Error Status: 00h, 80h, 81h, 84h Upward and downward compatible with both EMS and EEMS 3.2. 41h -- Get Page Frame Segment Address [2] === On call: AH = 41h On return: AH = error status BX = page frame segment address Error Status: 00h, 80h, 81h, 84h Upward and downward compatible with both EMS and EEMS 3.2. 42h -- Get Unallocated Page Count [3] === On call: AH = 42h On return: AH = error status BX = number of unallocated pages DX = number of total pages Error Status: 00h, 80h, 81h, 84h Upward and downward compatible with both EMS and EEMS 3.2. Note that EMS and EEMS 3.2 had no mechanism to return the maximum number of handles that can be allocated by programs. This is handled by the EMS 4.0 new function 54h/02h. 43h -- Allocate Pages [4] === On call: AH = 43h BX = number of 16 KB pages requested (zero OK) On return: AH = error status DX = handle Error Status: 00h, 80h, 81h, 84h, 85h, 87h, 88h Upward compatible with both EMS and EEMS 3.2; EMS and EEMS 3.2 do not allow the allocation of zero pages (returns error status 89h). EMS 4.0 does allow zero pages to be requested for a handle, allocating pages later using function 51h, Reallocate Pages. 44h -- Map/Unmap Handle Page [5] === On call: AH = 44h AL = physical page to be mapped BX = logical page to be mapped (-1 to unmap) DX = handle On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Ah, 8Bh Upward compatible with both EMS and EEMS 3.2; EMS and EEMS 3.2 do not support unmap (logical page FFFFh) capability. Also, E/EMS 3.2 specified there were precisely four physical pages; EMS 4.0 uses the subfunctions of function 58h to return the permitted number of physical pages. This incorporates the functionality of function 69h ("function 42") of EEMS. 45h -- Deallocate Pages [6] === On call: AH = 45h DX = handle On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 86h Upward and downward compatible with both EMS and EEMS 3.2. 46h -- Get Version [7] === On call: AH = 46h On return: AH = error status AL = version number Error Status: 00h, 80h, 81h, 84h Upward and downward compatible with both EMS and EEMS 3.2. See the GOTCHA section for a discussion about a problem with this function. It appears that the intended use for this function is to return the version of the vendor implementation of the expanded memory manager instead of the specification version. In short, this function is useless to the vendor-independant programmer as defined. 47h -- Save Page Map [8] === On call: AH = 47h DX = caller's EMM handle (NOT current EMM handle) On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Ch, 8Dh Upward and downward compatible with both EMS and EEMS 3.2. This only saves the context saved in EMS 3.2 specification; if a driver, interrupt routine or TSR needs to do more, functions 4Eh (Page Map functions) or 4Fh (Partial Page Map functions) should be used. The specification is silent about the number of save contexts to provide. AST recommends in their Rampage AT manual one save context for each handle plus one per possible interrupt (5 + ). In the LIMITS section of the document the minimum number of save contexts is the number of handles. 48h -- Restore Page Map [9] === On call: AH = 48h DX = caller's EMM handle (NOT current EMM handle) On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Eh Upward and downward compatible with both EMS and EEMS 3.2. This only restores the context saved in EMS 3.2 specification; if a driver, interrupt routine or TSR needs to do more, functions 4Eh (Page Map functions) or 4Fh (Partial Page Map functions) should be used. 49h -- (reserved) [10] === This function formerly returned the page mapping register I/O port array. Use of this function is discouraged, and in EMS 4.0 may conflict with the use of the new functions (4Fh through 5Dh). 4Ah -- (reserved) [11] === This function formerly returned the page translation array. Use of this function is discouraged, and in EMS 4.0 may conflict with the use of the new functions (4Fh through 5Dh). It is odd that no function presents in a vendor-independent manner the current mapping of logical pages to physical pages. This would be exceedingly handy in a debugging environment (such as Periscope or CodeView) in trying to track down bugs in programs using expanded memory. 4Bh -- Get Handle Count [12] === On call: AH = 4Bh On return: AH = error status BX = handle count Error Status: 00h, 80h, 81h, 84h Upward and downward compatible with EMS and EEMS 3.2. 4Ch -- Get Handle Pages [13] === On call: AH = 4Ch DX = handle On return: AH = status BX = pages allocated to handle Error Status: 00h, 80h, 81h, 83h, 84h This function is upward compatible with EMS and EEMS 3.2. It is interesting to note how foolish the spec writers were, in that the E/EMS 3.2 spec writers state that "[the contents of BX] never exceeds 512 because the EMM allows, at most, 512 pages of expanded memory." EMS 4.0 makes a lie of this statement, yet falls into the same trap by stating that the contents of BX will never exceed 2048. DON'T BELIEVE IT. This author suspects that future versions of the spec will make the EMS 4.0 specification lie, too. The programmer should make no assumptions about the order handles appear in the array. Paranoid programmers (like the author) should compare the number returned in BX with the maximum number of pages returned by function 42h register DX, total number of EMM pages. This should be an UNSIGNED comparison, just in case the spec writers decide to use 16 bit unsigned numbers (for a maximum space of one gigabyte) instead of signed numbers (for a maximum space of 512 megabytes). Unsigned comparisons will work properly in either case, and the author recommends the use of unsigned comparisons. 4Dh -- Get All Handle Pages [14] === On call: AH = 4Dh DI = offset to 1020 byte array ES = segment selector for 1020 byte array On return: AH = error status BX = number of active handles (1-255) Error Status: 00h, 80h, 81h, 84h NOT COMPATIBLE with EMS or EEMS 3.2, since the new special OS handle 0000h is returned as part of the array. Unless benign use of this information is used (such as displaying the handle and count of pages associated with the handle) code should be changed to only work with handles between 01h and FFh and to specifically ignore handle 00h. The array consists of an array of 255 elements. The first word of each element is the handle number, the second word contains the number of pages allocated. PROBLEM: There are two types of handles, "standard" and "raw". The specification does not talk about how this function works when both raw and standard handles exist in a given system. There currently is NO way to differentiate between a standard handle and a raw handle in EMS 4.0 that the author can find. Ooops. This is particularly painful in debuggers when the hardware and EMM support raw pages whose size differs from the 16 KB standard page size. 4Eh -- Page Map Functions [15] === This group of four sub-functions are provided for context switching required by operating environments and systems. These functions are upward and downward compatible with both EMS and EEMS 3.2; in addition, these functions now include the functionality of EEMS function 6Ah ("function 43") involving all pages. The size and contents of the mag register (map reg) array will vary from system to system based on hardware vendor, software vendor, number of boards and the capacity of each board in the system. Note the array size can be determined by function 4Eh/03h. 4Eh/00h -- Get Page Map [15/0] On call: AH = 4Eh AL = 00h DI = offset to target array ES = segment selector for target array On return: AH = error status Error Status: 00h, 80h, 81h, 84h, 8Fh 4Eh/01h -- Set Page Map [15/1] On call: AH = 4Eh AL = 01h SI = offset to source array DS = segment selector for source array On return: AH = error status Error Status: 00h, 80h, 81h, 84h, 8Fh, A3h 4Eh/02h -- Get and Set Page Map [15/2] On call: AH = 4Eh AL = 02h SI = offset to source array (new context) DI = offset to target array (old context) DS = segment selector for source array ES = segment selector for target array On return: AH = error status Error Status: 00h, 80h, 81h, 84h, 8Fh, A3h 4Eh/03h -- Get Size of Page Map Save Array [15/3] On call: AH = 4Eh AL = 03h On return: AH = error status AL = size in bytes of array Error Status: 00h, 80h, 81h, 84h, 8Fh FUNCTIONS NEW TO EMS 4.0 ------------------------ 4Fh -- Partial Page Map Functions [16] === This group of four sub-functions are provided for context switching required by interrupt routines, operating environments and systems. This set of functions provides extended functionality over the EEMS function 6Ah ("function 43") involving subsets of pages. In EEMS, a subset of pages could be specified by starting position and number of pages; in this function a list of pages is specified, which need not be contiguous. Interrupt routines can use this function in place of functions 47h and 48h, especially if the interrupt routine wants to use more than the standard four physical pages. The page map is a structure of words. The first word indicate the number of pages specified. The remaining words contain the segment selector (NOT the physical page number) for each page. Translation from physical page number to segment selectors can be performed using function 58h/00h, Get Mappable Physical Address Array. The size and contents of the mag register (map reg) array will vary from system to system based on hardware vendor, software vendor, number of boards and the capacity of each board in the system. Note the array size can be determined by function 4Fh/02h. NOTE: there is no equivelant to 4Eh/02h, Get And Set, in this group of functions. From the point of view of system maintenance, the author would have preferred that subfunction 02h be reserved and the get-size command be subfunction 03h. Unfortunatly the die is cast. 4Fh/00h -- Get Partial Page Map [16/0] On call: AH = 4Fh AL = 00h SI = offset of page specification array DI = offset of target map reg array DS = segment selector of page spec array ES = segment selector of target map reg array On return: AH = error status Error Status: 00h, 80h, 81h, 84h, 8Bh, 8Fh, A3h 4Fh/01h -- Set Partial Page Map On call: AH = 4Fh AL = 01h SI = offset of source map reg array DS = segment selector of source map reg array On return: AH = error status Error Status: 00h, 80h, 81h, 84h, 8Fh, A3h 4Fh/02h -- Get Size of Partial Page Map Save Array On call: AH = 4Fh BX = number of pages in page spec array On return: AH = error status AL = size in bytes of mag reg array Error Status: 00h, 80h, 81h, 84h, 8Bh, 8Fh 50h -- Map/Unmap Multiple Pages [17/0][17/1] === On call: AH = 50h AL = 00h (by physical page) or 01h (by seg#) CX = number of mapping word pairs in array DX = handle SI = offset of source map array DS = segment selector of source map array On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Ah, 8Bh, 8F New function permits multiple logical-to-physical assignments to be made in a single call. The source map array is an array of word pairs. The first word of a pair contains the logical page to map (FFFFh if the physical page is to be totally unmapped) and the second word of a pair contains the physical page number (subfunction 00h) or the segment selector (subfunction 01h) of the physical page in which the logical page shall be mapped. A map of available physical pages (by physical page number and segment selectors) can be obtained using function 58h/00h, Get Mappable Physical Address Array. 51h -- Reallocate pages [18] === On call: AH = 51h BX = number of pages desired at return DX = handle On return: AH = error status BX = number of pages now associated with handle Error Status: 00h, 80h, 81h, 83h, 84h, 87h, 88h New function which permits the number of pages associated with a handle to be decreased or increased. 52h -- Handle Attribute Functions [19] === Something new added to the EMS specification is the ability to mark a handle and pages assoicated with a handle as non-volatile -- preserved across a warm boot of the system. The specification indicates that few if any EMS systems will support such a feature since the EMS hardware must insure the data remains valid throughout the warm boot sequence. Currently the only attribute supported is non-volatile handles and pages, indicate by the least significant bit. 52h/00h -- Get Handle Attribute [19/0] On call: AH = 52h AL = 00h DX = handle On return: AH = error status AL = handle attribute Error Status: 00h, 80h, 81h, 83h, 84h, 8Fh, 91h 52h/01h -- Set Handle Attribute [19/1] On call: AH = 52h AL = 01h BL = new attribute value DX = handle On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Fh, 90h, 91h 52h/02h -- Get Handle Attribute Capability [19/2] On call: AH = 52h AL = 02h On return: AH = error status AL = attribute capability Error Status: 00h, 80h, 81h, 83h, 84h, 8Fh 53h -- Handle Name Functions [20] === EMS handles may have names associated with them. Each name can be any eight characters. Functions 53h and 54h provide a way of setting and interrogating the names associated with a particular handle. Function 53h manipulates names by number. A name of eight nulls is special, and indicates a handle has no name. Note, by the way, that nulls have no special significance, and they can appear in the middle of the name. In short, the handle name is 64 bits of binary information so far as the expanded memory manager is concerned. The author recommends that when defining a handle name that the selected name be padded on the right with spaces, ASCII graphic characters be used, and that control codes and hi-bit-set characters be avoided to make a debugger's life easier. 53h/00h -- Get Handle Name [20/0] On call: AH = 53h AL = 00h DX = handle DI = offset to eight byte target ES = segment selector of eight byte target On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Fh 53h/01h -- Set Handle Name [20/1] On call: AH = 53h AL = 01h DX = handle SI = offset to eight byte source DS = segment selector to eight byte source On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Fh, A1h 54h -- Handle Directory Functions [21] === Function 54h manipulates handles by name. 54h/00h -- Get Handle Directory [21/0] On call: AH = 54h AL = 00h DI = offset to 2550 byte target array ES = segment selector to 2550 byte target array On return: AH = error status AL = number of active handles Error Status: 00h, 80h, 81h, 84h, 8Fh The name array consists of 10 byte entries; each entry has a word containing the handle number, followed by the eight byte (64 bit) name. 54h/01h -- Search for Named Handle [21/1] On call: AH = 54h AL = 01h SI = offset to 8 byte array with name DS = segment selector to 8 byte array On return: AH = error status DX = handle [number] Error Status: 00h, 80h, 81h, 84h, 8Fh, A0h, A1h 54h/02h -- Get Total Handles [21/2] On call: AH = 54h AL = 02h On return: AH = error status BX = maximum number of handles Error Status: 00h, 80h, 81h, 84h, 8Fh This is NOT the current number of handles defined, but the maximum number of handles that can be supported in the current environment. 55h -- Alter Page Map and Jump (cross page branch) [22] === On call: AH = 55h AL = 00h (by physical page) or 01h (by seg#) DX = handle SI = offset to jump target and mapping table DS = segment selector for target/map table On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Ah, 8Bh, 8Fh Flags and all registers except AX are preserved across the jump. One of the problems plaguing programmers in paged systems is being able to place code in paged memory. This function allows for an unstructured branch from code in one bank to code in potentially another bank without defining a bank manager in conventional memory. Thus several applications do not have to duplicate code. Note that code should follow the call to handle any error conditions that may arise. The programmer SHOULD NOT ASSUME the jump will always work. Graceful crashes are always preferable to sloppy ones... 56h -- Alter Page Map and Call (cross page call) [23/0][23/1] === On call: AH = 56h AL = 00h (by physical page) or 01h (by seg#) DX = handle SI = offset to jump target and mapping table DS = segment selector for target/map table On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Ah, 8Bh, 8Fh Flags and all registers except AX are preserved to the called routine. On return, flags and all registers except AX are preserved; AL is set to zero and AX is undefined. One common calling convention is useless with this function: indicating an error by incrementing the return address before issuing a RET instruction. Obviously the return address is within the expanded memory manager, and if you increment the address "the results are undefined" to quote an ANSI language standards document. "Sloppy crash" is probably more accurate. PROBLEM: AX is not preserved on the return leg of the call. This is a particular pain to C and PASCAL programmers since the most common way to return integer values is in AX. The amount of stack space required by the function call cannot be determined at compile time. It CAN be determined at run time, using function 56h/02h, so at least the parameter frame can be located. Unfortunately this plays hob with using BP for both parameters and local storage. The best thing is to define a series of assembler wrapper routines that (1) copies the parameter stack to the new function and (2) preserves AX on return. This means redesigning functions to pass structures and the size of structures instead of individual parameters, a performance problem. 56h/02h -- Get Page Map Stack Space Size [23/2] On call: AH = 56h AL = 02h On return: AH = error status BX = number of bytes of stack used per call Error Status: 00h, 80h, 81h, 84h, 8Fh The author assumes the value returned in BX is even, to match the requirements of the 80x86 architecture. Implementers should check to be sure they follow this important guideline. 57h -- Memory Manipulation [24] === The request block is a structure with the following format: doubleword: region length in bytes byte: 0=source in conventional; 1=source in expanded word: source handle word: source offset in page or selector word: source logical page (exp.) or selector (conv.) byte: 0=target in conventional; 1=target in expanded word: target handle word: target offset in page or selector word: target logical page (exp.) or selector (conv.) Expanded memory allocated to a handle is considered to be a linear array, starting from logical page 0 and progressing through logical page 1, 2, ... n, n+1, ... up to the last logical page in the handle. 57h/00h -- Move Memory Region [24/0] On call: AH = 57h AL = 00h SI = offset to request block DS = segment selector to request block On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Ah, 8Fh, 92h, 93h, 94h, 95h, 96h, 98h, A2h Moves data between two memory areas. Includes moves between paged and non-pages areas, or between two different paged areas. 57h/01h -- Exchange Memory Region [24/1] On call: AH = 57h AL = 01h SI = offset to request block DS = segment selector to request block On return: AH = error status Error Status: 00h, 80h, 81h, 83h, 84h, 8Ah, 8Fh, 93h, 94h, 95h, 96h, 97h, 98h, A2h Exchanges data between two memory areas. Includes exchanges between paged and non-pages areas, or between two different paged areas. 58h -- Mappable Physical Address Array [25] === These functions let you obtain a complete map of the way physical memory is laid out in a vendor independent manner. This is a functional equivalent of EEMS function 68h ("function 41"). EEMS function 60h ("function 33") is a subset call of 68h. 58h/00h -- Get Array [25/0] On call: AH = 58h AL = 00h DI = offset to target array ES = segment selector to target array On return: AH = error status CX = entries in target array Error Status: 00h, 80h, 81h, 84h, 8Fh The information returned is in an array composed of word pairs. The first word is the physical page's segment selector, the second word the physical page number. Note that values are not necessarily returned in a particular order, either ascending/decending segment selector values or as ascending/decending physical page number. For compatibility with earlier EMS specifications, physical page zero contains the segment selector value returned by function 41h, and physical pages 1, 2 and 3 return segment selector values that corrospond to the physical 16 KB blocks immediately following physical page zero. 58h/01h -- Get Array Entries [25/1] On call: AH = 58h AL = 01h On return: AH = error status CX = number of entries returned by 58h/00h Error Status: 00h, 80h, 81h, 84h, 8Fh Multiply CX by 4 for the byte count. 59h -- Hardware Information [26] === These functions return information specific to a given hardware implementation and to use of raw pages as opposed to standard pages. The intent is that only operating system code ever need use these functions. 59h/00h -- Get EMS Hardware Info [26/0] On call: AH = 59h AL = 00h DI = offset of target array (10 bytes) ES = segment selector of target array On return: AH = error status Error Status: 00h, 80h, 81h, 84h, 8Fh, A4h The target array has the following format: word: raw page size in paragraphs (multiples of 16 bytes) word: number of alternate register sets word: size of page maps (function 4Eh [15]) word: number of alternate registers sets for DMA word: DMA operation -- see full specification 59h/01h -- Get Unallocated Raw Page Count [26/1] On call: AH = 59h AL = 01h On return: AH = error status BX = unallocated raw pages DX = total raw pages Error Status: 00h, 80h, 81h, 84h, 8Fh 5Ah -- Allocate Raw Pages [27] === On call: AH = 5Ah BX = raw page count On return: AH = error status DX = handle Error Status: 00h, 80h, 81h, 84h, 85h, 87h, 88h It is intended this call be used only by operating systems. 5Bh -- Alternate Map Register Set [28] === Some boards support multiple sets of mapping registers, some for the specific purpose of performing DMA. These functions access the special features if they are available. It is intended these functions be used only by an operating system. This set of functions performs the same functions at EEMS function 6Ah subfunctions 04h and 05h ("function 43"). In the interests of brevity, the calls are not detailed here. For more information, please refer to the base document. 5Bh/00h -- Get Alternate Map Register Set [28/0] 5Bh/01h -- Set Alternate Map Register Set [28/1] 5Bh/02h -- Get Alternate Map Save Array Size [28/2] 5Bh/03h -- Allocate Alternate Map Register Set [28/3] 5Bh/04h -- Deallocate Alternate Map Register Set [28/4] 5Bh/05h -- Allocate DMA Register Set [28/5] 5Bh/06h -- Enable DMA on Alternate Map Register Set [28/6] 5Bh/07h -- Disable DMA on Alternate Map Register Set [28/7] 5Bh/08h -- Deallocate DMA Register Set [28/8] 5Ch -- Prepare EMS Hardware for Warm Boot [29] === On call: AH = 5Ch On return: AH = error status Error Status: 00h, 80h, 81h, 84h Provided for those hardware implementations that must be set up to preserve contents across a warm boot. 5Dh -- Operating System / Environment function control [30] === Security feature for operating systems and operating environment use. For brevity, the calls are not detailed here. 5Dh/00h -- Enable OS/E Function Set [30/0] 5Dh/01h -- Disable OS/E Function Set [30/1] 5Dh/02h -- Return OS/E Access Key [30/2] 61h -- Generic Accelerator Card Support [34] === For more information, contact AST Research for a copy of the _Generic Accelerator Card Driver (GACD) Specification_. ERROR RETURNS ------------- 00h -- Successful Completion 80h -- Software Error 81h -- Hardware Error 82h -- EMM busy (dropped in E/EMS 3.2) 83h -- Unknown EMM handle. 84h -- Unknown function code in AH. 85h -- All EMM handles are in use. 86h -- Page save/restore context error. 87h -- More pages requested than exist. 88h -- Not enough free pages to satisfy allocation request. 89h -- Zero page allocate request (dropped in EMS 4.0) 8Ah -- Logical page out of range 8Bh -- Physical page out of range 8Ch -- No room in the map context save area 8Dh -- Page context already saved 8Eh -- No page context to restore 8Fh -- Unknown sub-function 90h -- Attribute type undefined (new) 91h -- Warm boot data save not implemented (new) 92h -- Move overlaps memory (new) 93h -- Move/exchange larger than allocated region (new) 94h -- Conventional/expanded regions overlap (new) 95h -- Logical page offset outside of logical page (new) 96h -- Region larger than 1 MB. (new) 97h -- exchange source/destination overlap (new) 98h -- source/destination undefined or not supported (new) 99h -- (no status assigned) 9Ah -- Alt. Map Reg. Sets supported, specified set is not (new) 9Bh -- All alternate map & DMA registers sets allocated (new) 9Ch -- Alternate Map & DMA register sets not supported (new) 9Dh -- Alt Map Reg or DMA set no defined, allocated or is currently defined set (new) 9Eh -- Dedicated DMA channels not supported (new) 9Fh -- Dedicated DMA channels supported; specifed channel is not (new) A0h -- Named handle could not be found (new) A1h -- Handle Name already exists (new) A2h -- Move/exchange wraps around 1 MB boundry (new) A3h -- Data structure contains corrupted data (new) A4h -- Access denied (new)