DOS32 Version 3.0 Applications Program Interface (API) 10th March 1995 Copyright (C) 1994 Adam Seychell, All Rights Reserved. This document contains detailed information of the DOS32 API with each function obeying the following rules. 1) All services are invoked from software interrupts 31h or 21h. 2) All parameters are passed through registers. 3) All services will preserve registers which are not returned with any value. 4) Each function listed here has the minimum DOS32 version number needed on the right hand side of it's heading. 5) Never call a service in a protected mode interrupt handler unless otherwise said it is safe to do so. The Interrupt 31h services. The following list of services are called from a INT 31h with AX containing the function number. GET DOS32 VERSION AND SELECTOR VALUES V3.0+ IN: AX = EE00h OUT: AL = minor version ( BCD ) currently 00 AH = major version ( BCD ) " 03 DL = system type 1 = raw DOS 2 = XMS 4 = VCPI 8 = DPMI BX = Selector of 4GB data segment with zero base address. Notes: o This function may be called in a protected mode interrupt handler. GET DOS32 ADDRESS INFORMATION V3.0+ IN: AX = EE02h OUT: EBX = 32bit linear address of the program segment EDX = Total size in bytes of the programs .EXE file after linking. ESI = Offset address of PSP ( Program Segment Prefix ) EDI = Offset address of Program Environment ECX = Offset address of the programs .EXE file name and path ( in ASCIZ format, i.e. terminates with a zero ) Notes: o All offset addresses returned are relative to the main program segment. o The .EXE file size is generally used for loading extra data appended to the original application's .EXE file. o The .EXE file name pointed by ECX is actually the file name contained in the last string of the Environment segment pointed to by EDI. o The PSP address points to the original PSP set up by DOS. Thus pointers stored in here still contain real mode (segment:offset) values. Also this PSP address may not be the same address returned by DOSs Int 21h AH=62h (Get PSP) since DOS32 may of been loaded by a parent stub program. o This function may be called in a protected mode interrupt handler. GET A REAL MODE CALL BACK ADDRESS WITH IRET OR RETF STACK FRAME V3.0+ This service will return a real mode address which when called (in real mode) will in turn call a protected mode procedure. The real mode address may either be called with a REFF or IRET stack frame, i.e far CALL or an interrupt. Expects: AX = EE20h ( for an RETF frame ) AX = EE21h ( for an IRET frame ) ESI -> Offset address of the protected mode procedure to be invoked when the real mode address is called. The procedure must exit with a FAR return. Returns: If function was successful: Carry flag is clear. CX:DX = The real mode far pointer ( SEG:OFFSET ) to call the protected mode procedure. If function was not successful: Carry flag is set. Notes: o This function will fail if it's called more than 30 times. o The protected mode procedure must exit with a FAR return instruction. o The procedure is called undefined selectors in all segment register ( ES,DS,FS,GS & SS ) and must preserve any segment registers it modifies. o EAX, EBX, ECX, EDX, ESI, EDI, EBP registers and flags will be preserved across the mode switch. o This function can be used to hook a Real Mode interrupt by setting the real mode interrupt vector to point to the real mode address (CX:DX) returned by this function. See examples on how this may be done. TERMINATE AND STAY RESIDENT v3.0+ This service will terminate the application to DOS but leaving it resident in memory. IN: AX = EE30h OUT: Never returns Notes: o All memory allocated from functions AX=0EE42h ( memory block ) and AX=EE41h ( DMA buffer ) will not be freed and stay allocated. o This service may come in handy. Now.... what could you write with a multi megabyte TSR ?? UNDO PREVIOUS MEMORY ALLOCATION or DMA BUFFER v3.0+ This function will free the previously allocated memory block ( function AX =EE41h ) or DMA buffer ( function AX=EE42h ). If this function is called multiple times then memory will be deallocated in reverse order to when allocated. For example, if a memory block was allocated followed by a DMA buffer then at first time this function is called the DMA buffer would be freed, a second call to this function will free the memory block, a third call will return an error ( Carry set ) because at this point no memory is being allocated. IN: AX = EE40h OUT: If function successful carry flag is cleared If unsuccessful the carry flag is set Notes: o This function will fail if there is no memory allocated. o All memory will automatically be freed when then application terminates. 16KB BLOCK ALLOCATION FOR DMA CONTROLLER V3.0+ This function allocates a DMA buffer allowing the application to do DMA transfers of up to 16KB at a time. Expects: AX = EE41h Returns: If function was successful: Carry flag is clear. EBX = Physical address of a contiguous 16KB memory block that dose not cross a 64KB boundary and has a physical address in the lower 16MB. EDX = Near pointer to the base address of the block relative to the main program segment. If function was not successful: Carry flag is set. NOTES: o The 16Kb block will not cross a physical 64KB boundary and will have a base address aligned on a 4 byte boundary. This is just what DMA needs!. o If the carry flag is set then there was not enough memory to allocate the DMA block otherwise the carry flag is cleared. o If the application needs to do use more than one DMA channel at the same time ( e.g reading floppy disk at the same time as sending music to a sound card ) then a buffer should be allocated for each channel used. o If all the memory was allocated by the Allocate Memory service ( AX=0EE42h ) then this function will fail. Your application should allocate it's DMA buffers before is tries to allocate large blocks with the AX=0EE42h function. o If you need to send large amounts of memory via DMA to a device then it will have to be done in 16KB blocks. I know this sounds very inefficient but I done tests and found that I could not even measure the speed increase between 1Kb blocks to 128Kb blocks. Only a noticeable slow down occurred when transferring with blocks of 100 bytes or less. In fact the time it takes to program the DMA controller and move a 16KB block to the buffer ( using REP MOVSD ) is under %1 of the DMA transfer time. In other words, it will be less than %1 slower using a buffer as opposed to transferring DMA directly to/from the data area. ALLOCATE A MEMORY BLOCK V3.0+ The entire application code,data and stack is initially contained in one large memory block. This service here is used for allocating extra memory blocks for the application. IN: AX = EE42h EDX = Size of the memory block requested to allocate in bytes. OUT: EAX = The actual allocated size of the memory block in bytes EDX = Near pointer to the base address of the block relative to the main program segment. If the returned size was less than the requested size then the Carry flag is set otherwise the carry flag is cleared. Notes: o The value expected in EDX will be rounded off to the next 4KB boundary. Example, allocating 51001h bytes will actually allocate 52000h bytes. o Never call this function in a interrupt handler or after using the terminated and stay resident function ( AX=EE30h ). o If EAX is returned with zero then no memory was allocated and contents of EDX are undefined. o The function will fail if the requested size is zero. o If your system happens to have 4Gb of RAM installed then only about 4032Mb of it can ever be allocated (sorry for those people:) o No more than 64 allocations can be made. o When not running under a DPMI server ( i.e Raw,XMS or VCPI ) then extended memory is allocated before conventional memory is. For example, if there is no more extended memory free then conventional memory will be allocated. In either case DOS32 sets up the 386 page tables such that the allocated memory is addressed in a straight linear block when it may actually be physically scattered throughout RAM. The Interrupt descriptor table services These services allow the application to get and set vectors of the protected mode interrupt descriptor table. The hardware interrupt vectors will always be set the default values. i.e IRQs 0..7 map onto CPU interrupts 8..15 and IRQs 8..15 map onto CPU interrupts 70h..77h. All protected mode interrupt vectors will initially reflect to the same interrupt in real mode. In other words a switched to and from real mode is automatically made when a protected mode interrupt is called. The registers EAX,ECX,EDX,EBX,EBP,ESI,EDI and flags will be preserved across the mode switch. The exception to this rule are protected mode interrupts 0,1,3,4,5,6 and 7. These are exceptions and will terminate the program reporting with an error on the screen. Hardware interrupt handlers will be called with undefined selectors in all data segment registers. The interrupt handler must preserve all modified general registers and segment registers before it returns from the interrupt. The application is responsible for returning the original interrupt vectors before the application terminates. It is only necessary do to this when running under a DPMI server. However, for reliability, ALL modified interrupt vectors should be restored to their original value. GET PROTECTED MODE INTERRUPT VECTOR V3.0+ IN: AX = 0204h BL = interrupt OUT: EDX = The 32 bit Offset of the vector CX = Selector of vector SET PROTECTED MODE INTERRUPT VECTOR V3.0+ IN: AX = 0205h BL = interrupt EDX = The 32 bit Offset of the vector CX = Selector of vector ( must be a code selector ) OUT: nothing Real Mode Call Services The following three services are used for calling real mode programs (e.g a DOS call or a device driver). Each of these services expects a pointer to a real mode call structure whish is used to passing all registers to and from the real mode switch. The format of the structure is defined as: Offset Register 00h EDI 04h ESI 08h EBP 0Ch Reserved by system 10h EBX 14h EDX 18h ECX 1Ch EAX 20h Flags 22h ES 24h DS 26h FS 28h GS 2Ah IP 2Ch CS 2Eh SP 30h SS ----------------------------------------------------------------------------- Simulate a Real Mode interrupt V3.0+ IN: AX = 0300h BL = Interrupt number BH = Flags Bit 0 = 1 resets the interrupt controller and A20 line Other flags reserved and must be 0 CX = Number of words to copy from protected mode to real mode stack ES:EDI = Selector:Offset of real mode call structure OUT: If function was successful: Carry flag is clear. ES:(E)DI = Selector:Offset of modified real mode call structure If function was not successful: Carry flag is set. ----------------------------------------------------------------------------- Call Real Mode Procedure With Far Return Stack Frame V3.0+ IN: AX = 0301h BH = Flags Bit 0 = 1 resets the interrupt controller and A20 line Other flags reserved and must be 0 CX = Number of words to copy from protected mode to real mode stack ES:EDI = Selector:Offset of real mode call structure OUT: If function was successful: Carry flag is clear. ES:EDI = Selector:Offset of modified real mode call structure If function was not successful: Carry flag is set. ----------------------------------------------------------------------------- Call Real Mode Procedure With IRET Stack Frame V3.0+ IN: AX = 0302h BH = Flags Bit 0 = 1 resets the interrupt controller and A20 line Other flags reserved and must be 0 CX = Number of words to copy from protected mode to real mode stack ES:EDI = Selector:Offset of real mode call structure OUT: If function was successful: Carry flag is clear. ES:EDI = Selector:Offset of modified real mode call structure If function was not successful: Carry flag is set. The 32 bit DOS type services The following services are like a protected mode version of DOS's services. They are called the same way as in real mode where AH=function and invoked with INT 21h. These services work exactly the same as calling the DOS services in real mode except 32bit registers and protected mode far pointers ( selector:offset ) are used. For a more detailed description of how the services work please refer to DOS programming documentation. The description below is only to show the use of 32 bit registers. NOTE: If an INT 21h function is called and is not described here then the interrupt is done in real mode with all the registers passed to from the call. This is also the case for any other protected mode interrupt, not just INT 21h!. ----------------------------------------------------------------------------- WRITE STRING TO STANDARD OUTPUT V3.0+ AH = 09h DS:EDX -> '$'-terminated string ----------------------------------------------------------------------------- CREATE SUBDIRECTORY V3.0+ AH = 39h DS:EDX -> Selector:Offset of ASCIZ pathname Return: CF clear if successful AX destroyed CF set on error AX = error code (03h,05h) ----------------------------------------------------------------------------- REMOVE SUBDIRECTORY V3.0+ AH = 3Ah DS:EDX -> Selector:Offset ASCIZ pathname of directory to be removed Return: CF clear if successful AX destroyed CF set on error AX = error code (03h,05h,06h,10h) ----------------------------------------------------------------------------- CHANGE SUBDIRECTORY V3.0+ AH = 3Bh DS:EDX -> ASCIZ pathname to become current directory (max 64 bytes) Return: CF clear if successful AX destroyed CF set on error AX = error code (03h) ----------------------------------------------------------------------------- CREATE OR TRUNCATE FILE V3.0+ AH = 3Ch CX = file attributes DS:EDX -> Selector:Offset ASCIZ filename Return: CF clear if successful AX = file handle CF set on error AX = error code (03h,04h,05h) ----------------------------------------------------------------------------- OPEN EXISTING FILE V3.0+ AH = 3Dh AL = access and sharing modes DS:EDX -> Selector:Offset ASCIZ filename CL = attribute mask of files to look for (server call only) Return: CF clear if successful AX = file handle CF set on error AX = error code (01h,02h,03h,04h,05h,0Ch,56h) ----------------------------------------------------------------------------- READ FROM FILE OR DEVICE V3.0+ AH = 3Fh BX = file handle ECX = number of bytes to read ( may be zero ) DS:EDX -> Selector:Offset buffer for data Return: CF clear if successful EAX = number of bytes actually read (0 if at EOF before call) CF set on error AX = error code (05h,06h) ----------------------------------------------------------------------------- WRITE TO FILE OR DEVICE V3.0+ AH = 40h BX = file handle ECX = number of bytes to write DS:EDX -> Selector:Offset data to write Return: CF clear if successful EAX = number of bytes actually written CF set on error AX = error code (05h,06h) ----------------------------------------------------------------------------- DELETE FILE V3.0+ AH = 41h DS:EDX -> Selector:Offset ASCIZ filename (no wildcards ) Return: CF clear if successful CF set on error AX = error code (02h,03h,05h) ----------------------------------------------------------------------------- SET CURRENT FILE POSITION V3.0+ AH = 42h AL = origin of move 00h start of file 01h current file position 02h end of file BX = file handle EDX = offset from origin of new file position Return: CF clear if successful EAX = new file position in bytes from start of file CF set on error AX = error code (01h,06h) Notes: The normal real mode DOS function uses CX:DX as the position of the file to seek and returns DX:AX with the new value of the position. This protected mode version uses EDX in place of CX:DX and uses EAX in place of DX:AX. ----------------------------------------------------------------------------- GET FILE ATTRIBUTES V3.0+ AX = 4300h DS:EDX -> Selector:Offset ASCIZ filename Return: CF clear if successful CX = file attributes AX = CX (DR-DOS 5.0) CF set on error AX = error code (01h,02h,03h,05h) ----------------------------------------------------------------------------- SET FILE ATTRIBUTES V3.0+ AX = 4301h CX = new file attributes DS:EDX -> Selector:Offset ASCIZ filename Return: CF clear if successful AX destroyed CF set on error AX = error code (01h,02h,03h,05h) ----------------------------------------------------------------------------- GET CURRENT DIRECTORY V3.0+ AH = 47h DL = drive number (00h = default, 01h = A:, etc) DS:ESI -> Selector:Offset 64-byte buffer for ASCIZ pathname Return: CF clear if successful AX = 0100h (undocumented) CF set on error AX = error code (0Fh) ----------------------------------------------------------------------------- LOAD AND/OR EXECUTE PROGRAM V3.0+ AH = 4Bh AL = type of load 00h load and execute 01h load but do not execute DS:EDX -> ASCIZ program name (must include extension) DS:EDI -> Program environment to copy for child process (copy caller's environment if EDI = zero ) DS:ESI -> pointer to command tail to be copied into child's PSP Return: CF clear if successful CF set on error AX = error code (01h,02h,05h,08h,0Ah,0Bh) Notes: Unlike DOS's 4Bh function this does not require a parameter block to be set up. The environment and command tail are pointed to by DS:EDI and DS:ESI respectively. See the examples distributed with DOS32 on how this function may be used. ----------------------------------------------------------------------------- TERMINATE WITH RETURN CODE V3.0+ AH = 4Ch AL = return code Return: never returns Notes: o DOS32 applications MUST ALWAYS terminate with this call. o All memory allocated ( including DMA buffers ) will automatically be freed when the application terminates with this call. ----------------------------------------------------------------------------- FIND FIRST MATCHING FILE V3.0+ AH = 4Eh CX = file attribute mask DS:EDX -> ASCIZ file specification (may include path and wildcards) Returns: CF clear if successful The DTA ( Disk Transfer Area ) is filled with file information. CF set on error AX = Error code (02h, 03h, or 12h) Notes: The DTA is set to the default area which is at offset 80h in the Program Segment Prefix (PSP). See function INT 31h AX=EE02h for obtaining the PSP address. ----------------------------------------------------------------------------- RENAME FILE V3.0+ AH = 56h DS:EDX -> ASCIZ filename of existing file (no wildcards ) ES:EDI -> ASCIZ new filename (no wildcards) CL = attribute mask Return: CF clear if successful CF set on error AX = error code (02h,03h,05h,11h) ----------------------------------------------------------------------------- CREATE TEMPORARY FILE V3.0+ AH = 5Ah CX = file attribute DS:EDX -> ASCIZ path ending with a '\' + 13 zero bytes to receive the generated filename Return: CF clear if successful AX = file handle opened for read/write in compatibility mode DS:EDX pathname extended with generated name for temporary file CF set on error AX = error code (03h,04h,05h) ----------------------------------------------------------------------------- CREATE NEW FILE V3.0+ AH = 5Bh CX = file attribute DS:EDX -> ASCIZ filename Return: CF clear if successful AX = file handle opened for read/write in compatibility mode CF set on error AX = error code (03h,04h,05h,50h)