INT 67 U - QEMM-386 v4.23+ - INSTALLATION CHECK AH = 3Fh CX = 5145h ("QE") DX = 4D4Dh ("MM") Return: AH = 00h if installed ES:DI -> QEMM API entry point Notes: if no other program has hooked INT 67, an alternate installation check is to test for the string "QUARTERDECK EXPANDED MEMORY MANAGER 386" at offset 14h in the INT 67 handler's segment; the word at offset 12h contains the offset in the handler's segment of the API entry point although this function is still undocumented, Quarterdeck has recently documented two alternate methods for determining the QEMM API entry point, as well as several of the API functions MICEMM (Micronics Expanded Memory Manager) versions 2.0C and 4D support the alternate QEMM installation check and entry point functions 00h, 02h, and 03h; version 4D only provides the signature string if the commandline argument "DV" is provided 386MAX v6.01 responds to this call, but DESQview 2.42 does not recognize the returned entry point as providing QEMM's capabilities because a) only functions 0Ch (different from QEMM 0Ch) and 1000h-1009h are supported, b) status is returned as for EMS functions, not QEMM funcs c) the protected-mode entry point returned by function 1000h only supports functions 0Ch, 1004h, 1005h, and 100Ah the string check mentioned above is not supported by 386MAX SeeAlso: AX=5BF0h,AH=DDh,AX=FFA5h,INT 15/AX=11DEh,INT 21/AX=4402h/SF=01h SeeAlso: INT 21/AX=4402h"QEMM",INT 21/AX=4402h"386MAX",INT 2F/AX=D201h/BX=5145h Call QEMM entry point with: AH = 00h get QEMM state (documented) Return: CF clear AL = QEMM state bit 0 set if QEMM turned OFF bit 1 set if in "Auto" mode AH = 01h set QEMM state (documented) AL = new state bit 0 set: place QEMM in OFF state Return: CF clear if successful CF set on error AH = 02h get ??? Return: CF clear AX = segment of ??? data structure Data Structure Offset Size Description 00h DWORD page table entry for ??? ??? AH = 03h get QEMM version (documented) Return: CF clear AX = BX = version in BCD Notes: the most recent official docs state that the version is returned in both AX and BX; older documentation only mentions BX MICEMM returns AX=0001h, BX unchanged AH = 04h allocate 4K page and set AUTO/ON mode Return: CF clear if successful DX = page number of a 4K page CF set if unable to allocate page Note: QEMM mode unchanged if not AUTO/OFF AH = 05h free 4K page and turn QEMM off DX = page number returned by function 04h Return: CF clear Note: QEMM mode unchanged if not AUTO/ON AH = 06h make new mapping context??? DX = page number of 4K page to hold page table Return: CF clear Note: copies page table into given page and then sets ??? page table entry to point at copy AH = 07h get mapping context Return: CF clear DX = page number of page table for current mapping context AH = 08h set mapping context??? DX = linear page number of page table Return: CF clear AH = 09h get linear page number for page table entry CX = page table index Return: CF clear DX = linear page number AH = 0Ah set linear page number for page table entry CX = page table index DX = linear page number Return: CF clear AH = 0Bh map 4K pages BX = number of pages CX = first page number (must be 0100h to allocate HMA) DX = EMS handle (memory belonging to EMS handle will be mapped into the address space beginning with the first page allocated to the handle) Return: AH = 00h AH = 0Ch get available memory Return: CF clear BX = 0001h CX = total 4K pages??? DX = number of 4K pages free AH = 0Dh ??? (related to callbacks) AL = 00h/01h/02h ??? Return: CF clear AH = 0Eh set ??? callbacks DS:BX -> FAR routine for ??? ES:DX -> FAR routine for ??? Return: CF clear Note: DS:BX callback should return BX=???; ES:DX is called with BX=???, and should set the ??? from which the other handler read the value of BX. BH and BL appear to be separate values. AH = 0Fh unmap 4K pages CX = first page number DX = number of pages Return: CF clear AL = 00h/01h if ??? Note: if CX=0100h and DX=0010h, the HMA is remapped to simulate a disabled A20 AX = 1000h get protected-mode interface DS:SI -> 16-byte buffer for two GDT entries ES:DI -> buffer for 4K page table Return: CF clear EAX = offset of protected-mode API entry point DS:SI buffer filled with two GDT descriptors first is QEMM code segment, second is data??? ES:DI buffer filled with 4K page table DI points to first unused page table entry SeeAlso: INT 67/AX=DE01h AX = 1001h get CPU debug registers ES:DI -> buffer for debug registers (8 DWORDs) Return: CF clear BL = INT01 handling (see function 1002h) ES:DI buffer filled AX = 1002h set CPU debug registers BL = INT01 handling 00h reflect all debugging exceptions as V86-mode INT 01's else convert debugging exceptions other than single-step into V86-mode INT 03's, single-step to INT 01's ES:DI -> buffer containing debug registers (8 DWORDs) Return: CF clear Notes: identical to INT 67/AX=DE09h if BL=01h the INT01 handling flag is set to 01h by the general- protection violation handler for certain privileged instructions AX = 1003h get machine status word CR0 Return: CF clear EAX = contents of CR0 SeeAlso: INT 67/AX=DE07h AX = 1004h allocate a 4K page Return: CF clear if successful EDX = linear address of allocated page CF set on error SeeAlso: INT 67/AX=DE04h AX = 1005h free 4K page EDX = linear address of page to free Return: CF clear SeeAlso: INT 67/AX=DE05h AX = 1006h NOP Return: CF set AX = 1007h get maximum physical memory address Return: CF clear EDX = physical address of highest 4K memory page SeeAlso: INT 67/AX=DE02h AX = 1008h get physical address of page in first megabyte CX = page number (linear address shifted right 12 bits) Return: CF clear EDX = linear address of page SeeAlso: function 1F00h AX = 1009h switch to protected mode ESI = linear address in first megabyte of system reg values (see INT 67/AX=DE0Ch) interrupts disabled Return: interrupts disabled GDTR, IDTR, LDTR, TR loaded SS:ESP must have at least 16 bytes space, and the entry point is required to set up a new stack before enabling interrupts EAX, ESI, DS, ES, FS, GS destroyed AX = 100Ah switch back to virtual-86 mode DS = selector for data segment from function 1000h SS:ESP in first megabyte of linear memory interrupts disabled STACK: QWORD return address from FAR call to 32-bit segment DWORD EIP DWORD CS DWORD reserved for EFLAGS DWORD ESP DWORD SS DWORD ES DWORD DS DWORD FS DWORD GS will switch to virtual86 mode with interrupts disabled, all segment registers loaded, and EAX destroyed. AH = 11h get memory type map AL = zero/nonzero ??? (set by QEMM.COM but apparently ignored by QEMM 6.00) ES:DI -> 256-byte buffer for memory types Return: CF clear BL = ??? ES:DI buffer filled Note: each byte of the buffer corresponds to a 4K page, and contains the type of that page: 00h = mappable, 02h = mapped ROM, 03h = high RAM, 04h = excluded, 05h = video, 06h = ROM, 07h = adapter ROM, 08h = split ROM, 09h = page frame, 0Ah = RAMmable, 0Bh = conventional AH = 12h get HIRAM chain Return: CF clear BX = segment of first MCB in high memory 0000h if no high memory AX = 1300h VIDRAMEGA??? BL = 00h copy ??? nonzero copy ??? (reverse) Return: CF clear AL = 00h if all pages clean = 01h if any page dirty AX = 1301h check if ??? DX:DI = start address of range to check ??? CX = length of range Return: CF clear CX = ??? (0000h or 1000h) AX = 1302h ??? BL = ??? BH = ??? CX = ??? SI = offset of ??? DI = offset of ??? ??? Return: CF clear ??? Note: disables certain interrupts at the two 8259 PICs during execution; also modifies CRT controller during execution under certain circumstances AX = 1303h initialize VIDRAM EMS BX = number of pages (less 1) of EMS to allocate Return: CF clear if successful DX = EMS handle CF set on error AX = 1304h shutdown VIDRAM EMS DX = EMS handle Return: CF clear AX = 1305h ??? (related to VIDRAM, changes memory mappings) CX = ??? Return: CF clear Note: disables certain interrupts at the two 8259 PICs during execution (see AX=130Ch) and runs inside a QEMM critical section AX = 1306h set DESQview critical section counter address ES:BX -> WORD DESQview critical section counter or 0000h:0000h Return: CF clear Note: also sets a pointer in the low-memory part of QEMM to the current value of INT 15 if ES:BX not 0000h:0000h AX = 1307h ??? (changes memory mappings) Return: CF clear Note: disables certain interrupts at the two 8259 PICs during execution (see AX=130Ch) and runs inside a QEMM critical section AX = 1308h set/reset ??? BL = ??? (zero/nonzero) Return: CF clear AX = 1309h Hercules mode-change support ES:BX -> new address for Hercules mode-change callback Return: CF clear Note: the callback function is called whenever the CRTC mode register is written, with AL set to the value written AX = 130Ah virtualize EGA/VGA I/O ports 03C8h/03C9h??? CX:DX -> buffer for storing CRTC register contents??? or 0000h:0000h to disable Return: CF clear AX = 130Bh ??? BL = ??? (??? or 00h) Return: CF clear ??? Note: calls AX=130Eh in some cases AX = 130Ch set interrupts to mask BX = interrupts to mask out during AX=1302h,AX=1307h,AX=1308h, AX=130Dh,AX=1310h (BL = master PIC, BH = slave PIC) Return: CF clear AX = 130Dh map EGA memory at A0000h ??? Return: CF clear Note: disables certain interrupts at the two 8259 PICs during execution (see AX=130Ch) and runs inside a QEMM critical section calls AX=1307h AX = 130Eh ??? (modifies CRT controller setup) ??? Return: CF clear AX = 130Fh reset ??? Return: CF clear AX = 1310h ??? ??? Return: CF clear Note: disables certain interrupts at the two 8259 PICs during execution (see AX=130Ch) and runs inside a QEMM critical section also calls AX=130Dh AX = 1311h set ??? BL = ??? Return: CF clear AX = 1312h (v6.02) NOP??? Note: called by DV 2.42, but appears to be a NOP in QEMM 6.02 AX = 1400h ??? ES:DI -> ??? data structure (at least 24 bytes) BL = ??? Return: AX = ??? Data structure Offset Size Description 00h WORD ??? 02h DWORD far pointer to ??? 06h DWORD far pointer to ??? pointer array (see below) 0Ah DWORD far pointer to ??? 0Eh DWORD ??? 12h WORD segment of ??? 14h DWORD far pointer to ??? Pointer array Offset Size Description 00h WORD number of pointers to follow 02h N DWORDs far pointers to ??? Note: QEMM converts the pointers into linear addresses in place AX = 1401h ??? Return: CF clear ??? AX = 1402h ??? BL = function 00h NOP 01h ??? 02h ??? other ??? ES:DI -> ??? Return: CF clear ??? Data structure Offset Size Description 00h WORD segment of ??? (X, word at X:0136h set to X) 02h WORD segment of ??? (word at X:0124h set to this) 04h WORD number of paragraphs of ??? 06h 3 WORDs ??? (copied to X:0000h) 0Ch WORD ??? AX = 1403h add ??? to list and ??? (execute func 1406h) ES:DI -> ??? structure added to end of ??? list (at least 31 bytes, DWORD at offset 06h used for storing pointer to next struc, WORD at offset 00h seems to be a key or index) Return: CF clear AX = 1404h NOP AX = 1405h remove ??? from ??? list BX = key??? Return: CF clear AX = 1406h ??? ??? Return: CF clear ??? AX = 1407h ??? ??? Return: CF clear ??? AX = 1408h ??? ??? Return: CF clear ??? AX = 1409h ??? ??? Return: CF clear ??? AX = 140Ah ??? BX = ??? Return: CF clear ??? AX = 140Bh ??? BX = ??? Return: CF clear SI = segment of 256-byte buffer??? AH = 15h ??? ES:BX -> ??? or 0000h:0000h Return: CF clear ---QEMM v5.00+ --- AX = 1600h get memory access status ES:DI -> 256-byte buffer Return: ES:DI buffer filled Note: each byte of the buffer indicates the status of a 4K page (bit 0 set if read, bit 1 set if written) AX = 1601h set memory access status ES:DI -> 256-byte buffer containing access statuses (see above) AH = 17h get memory usage statistics ES:DI -> 81-byte buffer for memory statistics (see below) Return: CF clear ---QEMM v5.11+ --- AH = 18h check whether conventional memory mapped into address range ES:BX = starting address CX = number of 4K pages Return: CF clear AL = 00h one or more pages is remapped 01h all pages in range are conventional memory (physical address == virtual address) AH = 19h NOP Return: CF set AH = 1Ah I/O port access AL = subfunction 00h get byte from I/O port Return: BL = port value 01h send byte to I/O port BL = value to send 02h send byte to I/O port, get byte from following port BH = value to send Return: BL = value read 03h send bytes to two consecutive I/O ports BH = value for first I/O port (DX) BL = value for second I/O port (DX+1) DX = port number Return: CF clear AH = 1Bh MS Windows 3.x support AL = subfunction 00h get EMM Import Structure address ES:DI -> buffer for EMM import data structure Return: CF set on error CF clear if successful EMM Import data structure: Offset Size Description 00h DWORD physical address of EMM import struct 04h BYTE major version (v6.00 sets to 01h) 05h BYTE minor version (v6.00 sets to 00h/0Bh) SeeAlso: INT 21/AX=4402h/SF=01h 01h ??? Return: CF set on error CF clear if successful 02h ??? Return: CF set on error CF clear if successful 03h MS Windows initializing CX = segment from which Windows init broadcast made??? DL = Windows startup flags??? DI = Windows version number (major in upper byte) Return: ??? SeeAlso: INT 2F/AX=1605h 04h MS Windows terminating Return: CF clear 05h determine whether program is driver??? DS:DX -> ASCIZ filename Return: CF clear AL = 01h if string ends in ".DRV" = FFh if string ends in "GDI.EXE" = 00h otherwise 06h ??? CX = length of data pointed at by DS:DX DS:DX -> ??? Return: CF clear 07h BUG: QEMM 6.00-7.01 accept this and branch randomly else Return: CF set AH = 1Ch protected-mode hardware interrupt handlers ??? AL = subfunction 00h restore??? IRQ0-7 handlers 01h set??? IRQ0-7 handlers ES:DI -> 8 DWORDs containing ??? 02h restore??? IRQ8-15 handlers 03h set??? IRQ8-15 handlers ES:DI -> 8 DWORDs containing ??? BUG: although the jump table only contains four entries, QEMM 6.00 will attempt to use it for any value of AL between 00h and 2Ah, thus branching unpredictably for AL=04h-2Ah; QEMM v7.01 behaves similarly for AL=04h-1Bh ---QEMM v6.00+ --- AH = 1Dh Stealth interrupts AL = subfunction 00h switch to pre-Stealth interrupt vector table Note: also switches VGA Save table pointer (0040h:00A8h) and overwrites the vectors currently assigned for use by the two interrupt controllers (see INT 67/AX=DE0Ah) with the vectors for INT 08-0F and 70-77 (to avoid crashing the system). 01h restore user interrupt vector table Notes: interrupts should be disabled around the AX=1D00h and AX=1D01h calls because QEMM does not modify the memory maps to map in ROM, so an interrupt could be disastrous clears any pending IRQ7 at end of function else Return: CF set Note: functions 1Dxxh are not supported by QEMM v7.01, and always return CF set AH = 1Eh Stealth information (documented) AL = subfunction 00h "QEMM_GET_INFO" get Stealth configuration Return: BL = flags (documented as "reserved") bit 0: conventional memory sorted bit 1: conventional memory filled bit 2: ??? bit 3: ??? bit 4: expanded memory is in use bit 5: ??? BH = reserved (always 00h for v6.00) CL = stealth type (00h none,46h Frame,4Dh Map) CH = suspend/resume interrupt (00h none) DX = reserved (always 0000h for v6.00) SI = reserved (always 0000h for v6.00) DI = reserved (always 0000h for v6.00) 01h "QEMM_GET_STEALTH_COUNT" get number of Stealth'ed ROMs Return: CF clear BX = number of Stealth'ed ROMs 02h "QEMM_GET_STEALTH_LIST" get Stealth'ed ROM info ES:DI -> buffer for Stealth ROM info (see below) Return: CF clear BX = number of Stealth'ed ROMs ES:DI buffer filled else Return: CF set AH = 1Fh page table manipulation (documented) AL = subfunction 00h "QEMM_GET_PTE" get page table entry CX = page number Return: EDX = page table entry CF clear 01h "QEMM_SET_PTE" set page table entry CX = page number EDX = new page table entry Return: CF clear SeeAlso: function 1008h else Return: CF set AH = 20h asynchronous disk access support (documented) AL = subfunction 00h "QEMM_GET_VHI_INFO" get VirtualHDIRQ information Return: CF clear BL = flags bit 7: VirtualHDIRQ setting respected (set if Stealth active) bits 6-1 reserved bit 0: VirtualHDIRQ currently enabled (INT 15/AH=90h suppressed when enabled) 01h "QEMM_SET_VHI_FINO" set VirtualHDIRQ state BL bit 0 = new VirtualHDIRQ state Return: CF clear BL = old VHI setting (bits 0 and 7, see above) else Return: CF set AH = 21h Stealth support (documented) AL = subfunction 00h "QEMM_COPY_STEALTH_ROMS" copy data from Stealthed addr DS:SI -> start address of hidden memory to copy ES:DI -> buffer for copied data ECX = number of bytes to copy Return: CF clear if successful CF set on error (DS:SI < C000h:0000h or DS:SI + ECX > 1M) else Return: CF set ---QEMM v6.03+ --- AH = 22h DESQview/X support AL = subfunction 00h get ??? Return: CF clear ES:DI -> ??? 01h set ??? ES:DI -> ??? or 0000h:0000h Return: CF clear if successful CF set on error ---QEMM v6.04+ --- AH = 23h ??? AL = subfunction 00h get ??? BX = which ??? to get (must be 0000h for v6.04) Return: CF clear if successful ES:DI -> ??? CF set on error 01h set ??? BX = which ??? to set (must be 0000h for v6.04) ES:DI -> ??? Return: CF clear if successful CF set on error 02h clear specified ??? BX = which ??? to clear (must be 0000h for v6.04) Return: CF clear if successful CF set on error FFh clear all ??? else Return: CF set ---QEMM v7.01 only--- AH = 24h ST-DBL support AL = subfunction 00h set ??? EDX -> information table (EDX = segment SHL 16 + offset) 01h ??? other Return: CF set Format of QEMM 6.0 memory statistics: Offset Size Description 00h BYTE 01h if Shadow RAM found, 00h otherwise 01h DWORD initial conventional memory in bytes 05h DWORD initial extended memory in bytes 09h DWORD initial expanded memory in bytes 0Dh DWORD initial "top" or "shadow" memory in bytes 11h DWORD Unavailable conventional memory in bytes 15h DWORD Unavailable extended memory in bytes 19h DWORD Unavailable expanded memory in bytes 1Dh DWORD Unavailable "top" or "shadow" memory in bytes Add to offset 49h for Total unavailable top/shadow. 21h DWORD QEMM code size in bytes 25h DWORD QEMM data size in bytes 29h DWORD bytes used for TASKS= 2Dh DWORD DMA buffer size 31h DWORD bytes used for MAPS= 35h DWORD bytes of high RAM 39h DWORD bytes used by mapped ROMs 3Dh DWORD bytes of conventional memory provided by QEMM 41h DWORD bytes of extended memory NOT converted by QEMM (EXT=xxx) 45h DWORD bytes of EMS/XMS pool memory provided by QEMM 49h DWORD Unavailable "top" or "shadow" memory in bytes Add to offset 1Dh for Total unavailable top/shadow. 4Dh DWORD conventional memory overhead in bytes (set to 0 by QEMM.COM prior to call) Format of Stealth ROM info [array]: Offset Size Description 00h WORD starting segment of ROM 02h WORD length of ROM in paragraphs .