D3X(tm) DOS-Extender v0.90 unleash `g' alpha
the doc
*
Copyright © 1998-2001 Borca Daniel
*
dborca@yahoo.com
http://www.geocities.com/dborca

##### Motto:
Combining unlimited control
with unmatched efficiency...

0. Table of contents

0. Table of contents
1. Description
2. Legal stuff
3. Download & install
4. Getting started
5. Tech stuff
6. Closing bytes, words, doublewords...

1. Description

D3X (DOS 32bit eXtender) is a 32bit ring 0 protected mode DOS extender; it comes as a stub for 32bit applications: Assembly, DJGPP or WATCOM.
The extender is written in 100% assembler, for Assembly freaks...

2. Legal stuff

The term D3X is a shorthand and holds no connection with potential owners of registered trademarks or other rights.
All product names, trademarks and registered trademarks contained in this document are the property of their respective holders.
The "Software", below, refers to the complete contents of the D3X archive.

1. License agreement:

   Software is provided `as is' and without any warranty; there is no warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose.

   Software is freely redistributable as long as this licence is kept with the Software. Charging a fee for the Software is prohibited.

   Software, or parts thereof, may be incorporated into other free software (that may be obtained free of charge) without requiring permission from the author, as long as those parts of the Software that are used remain under this licence, as long as due credit is given to the author of the Software in the resulting work, and as long as the author is informed of this action.

   Modified forms of the Software may be created and distributed, as long as the resulting work remains under this licence, as long as the modified form of the Software is distributed with documentation which still gives credit to the original author of the Software, as long as the modified form of the Software is distributed with a clear statement that it is not the original form of the Software as distributed by the author, and as long as the author is informed of this action.

   Software, or parts thereof, may be incorporated into other software which is not free (for which a fee is charged) as long as permission is granted from the author of the Software. The author reserves the right to grant permission only for a fee, which may at his option take the form of royalty payments. The author also reserves the right to refuse to grant permission if he deems it necessary.

   The author of the Software explicitly lay no claim to, and assert no rights over, any programs written by other people and extended by the Software (that is, executables carrying the extender). Such programs do not fall under this licence at all, and may be placed under any licence.

   No other licence applies to the Software, and nothing else grants you any permission to copy, modify, sublicence or distribute the Software in any way.

3. Download & install

Unzip the archive, preserving the directory structure.

1. Requirements:

   - 386 or higher CPU
   - DOS v3.0 or later

2. Rebuilding:

   This baby was make'd (from D3X\SRC directory) using:

   NASM v0.98bf | nasm.sourceforge.net
   ALINK v1.6 | alink.home.dhs.org
   DJGPP v2.04 | www.delorie.com (gcc v3.2, make v3.79.1)
   UPX v1.23d (optional) | upx.sourceforge.net

   Note: using different versions and/or completely different tools might or might not yield satisfactory results.

3. Distribution:

       	D3X
           |   src.zip			 41060
           +---BIN
           |       stubx.exe		 56840	(112640)
           \---DOC
                   d3x.htm			 32227
                   d3x.txt			 29423

4. History:

   0.90.g:
     - sign extend ESI and EDI on the mouse callback
     - some minor package changes
   0.90.f:
     - first "official" release...

4. Getting started

D3X supports RAW/XMS/VCPI/DPMI platforms, but the optimal (read: safest and fastest) configuration is a plain DOS system with XMS.

1. Raw images (Assembly):

   Any MZ-EXE can be extended provided it contains 32bit code, defines a stack and has no relocations. Also, to ease things, the pretty sophisticated MZ-EXE header is replaced with the very simple D3X1 header. But alas! I hear you cry. Worry not, the dirty job is done by StubX, which is able to process both D3X1 and MZ-EXE; just type:

       	> StubX -s my_MZapp.exe

   or

       	> StubX -s my_D3X1.exe

   and voila! the dream comes true...

   The D3X1 specifications:

   1. D3X1 header:

          	d3x1_hdr	struc
                  sign	dd	?	;signature 'D3X1'
                  hdrsize	dd	?	;header size (bytes)
                  binsize	dd	?	;binary size (bytes)
                  admsize	dd	?	;additional memory (bytes)
                  entry	dd	?	;entry point
                  tos	dd	?	;top of stack
              d3x1_hdr	ends

   2. Interface to D3X1:

          	eflags		?202h
              cs,ds,ss	program block sel (cs = code32, ds=ss = data32)
              es		selector for transferbuffer (es:0 -> stubinfo)
              fs		flat data selector
              gs		flat code selector
              eip,esp		according to header
              .admsize	zeroed
              <others>	undefined

   3. Stubinfo area:

          	[00h] (byte[])	=	'd3x1stub vM.mm'
              [10h] (dword)	=	size of stubinfo
              [14h] (dword)	=	<unused>
              [18h] (dword)	=	memory block handle
              [1ch] (dword)	=	initial size (.binsize+.admsize)
              [20h] (word)	=	transferbuffer size
              [22h] (word)	=	transferbuffer data32 selector
              [24h] (word)	=	transferbuffer data segment
              [26h] (word)	=	PSP selector
              [28h] (word)	=	transferbuffer code16 selector
              [2ah] (word)	=	environment size
              [2ch] (dword)	=	platform (0=RAW, 1=XMS, 2=VCPI, 3=DPMI)

2. DJGPP images (v2 only):

   The simplest thing ever done:

       	> StubX -s my_DJapp.exe

3. WATCOM images:

   Welcome to hell! Usually, the WATCOM images require an extended INT21h API. For most programs out there, the provided API and the DPMI host is more than sufficient. Also note that 16bit objects are loaded high, not low.
   The LE-EXE patching is a bit more complicated, but, again, have no fear; just run StubX on such nasty monsters:

       	> StubX -s my_LEapp.exe

5. Tech stuff

Although D3X does not support swapping, it has the capability to use paging even under XMS/RAW (through the VCPI allocation scheme); it is somehow slower and the pagetables might grow very high if physical RAM is high. On the other hand, it catches any illegal memory access through page faults. Introduced for future virtual memory support, this not-so-tested feature requires rebuilding.

1. Interrupt engine:

   D3X doesn't relocate PIC at all. The algorithm it uses is:
   - under DPMI: the DPMI host handles IRQs (D3X does nothing)
   - under VCPI: D3X reads PIC from VCPI(DE0A) and uses it as is
   - under RAW/XMS: D3X uses default IRQs, regardless of current mappings. For this, default IRQs must be called through real mode chaining (i.e. HBREAK 5.2 sets the first PIC to int50h, but int08h is still issued). This is necessary because some extenders when in XMS/RAW mode map 1st PIC to default (no matter where PIC actually is) without letting anyone know, and everything gets f#*%d up. The only thing that remains safe is default location of PIC.
   When issuing an interrupt, be sure you have a valid stack with at least 64 bytes on it. The internal interrupt engine is based on the user stack (for speed) and if there's no stack space you have 100% chances to get a frozen reboot or a DoubleException.
   Some exception identification relies on that FLAGS can't resemble a valid code selector. If this happens, exceptions with error code would be treated as interrupts (which is wrong). Intel compatible CPUs won't allow this, because Bit1==1 in FLAGS and we run at ring 0. However, various specifications can use this bit, making it clearable. Thus, the simplest way to stay clear is to keep IOPL!=0 (bits 12-13 in FLAGS). Sane users shouldn't mess with this s#!t. That is, you can still f#*k the system, but don't come back to me crying. Also, if a TRAP/ABORT exception w/o error code occurs right after an instruction which ends with CD??, where ?? is the exception number, you'll get an interrupt:

               push	dword 3302h
               popfd
               mov	ax,01cdh
                       <- int01h, not debug exception

   If an exception handler is installed, it will be called in a DPMI compliant manner: with the exception structure on the stack. You can alter *ONLY* those fields DPMI says you can, and nothing else. Anyway, there are two deviations from the rule:
   - exception 0fh will be passed through the regular int chain; this is because of a nice feature of the interrupt controller being able to generate spurious IRQ7's. However, exception 0fh does not exist (by my knowledge).
   - the client will be shut down if the exception is not raised from user task or if the DPMI locked stack is exhausted, possibly due to nested exceptions!
   When terminating due to unhandled exception, the returned DOS error code is: e0h + exception number.

2. DPMI host:

   1. DPMI functions:

      Func. | Mode(s) | Ver | Description
      --- | --- | --- | ---
      0000h | P | 0.9 | Allocate LDT descriptors
      0001h | r | 0.9+ | Free LDT descriptor
      0003h | P | 0.9 | Get huge pointer increment
      0006h | P | 0.9 | Get segment base address
      0007h | P | 0.9+ | Set segment base address
      0008h | P | 0.9+ | Set segment limit
      0009h | P | 0.9+ | Set descriptor access rights
      000Ah | P | 0.9 | Create alias descriptor
      000Bh | P | 0.9 | Get descriptor
      000Ch | P | 0.9+ | Set descriptor
      0100h | r | 0.9 | Allocate DOS memory
      0101h | r | 0.9+ | Free DOS memory
      0102h | r | 0.9 | Resize DOS memory
      0200h | P | 0.9 | Get real-mode interrupt vector
      0201h | P | 0.9 | Set real-mode interrupt vector
      0202h | P | 0.9 | Get exception vector
      0203h | P | 0.9 | Set exception vector
      0204h | P | 0.9 | Get protected-mode int vector
      0205h | P | 0.9 | Set protected-mode int vector
      0300h | r | 0.9 | Simulate real-mode interrupt
      0301h | r | 0.9 | Call real-mode procedure (RETF)
      0302h | r | 0.9 | Call real-mode procedure (IRET)
      0303h | P | 0.9 | Allocate real mode call-back
      0304h | P | 0.9 | Free real mode call-back
      0400h | P | 0.9 | Get version
      0500h | P/r | 0.9 | Get free memory information
      0501h | P/r | 0.9 | Allocate memory block
      0502h | P/r | 0.9 | Free memory block
      0503h | P/r | 0.9 | Resize memory block
      0600h | P | bogus | Lock memory
      0601h | P | bogus | Unlock memory
      0604h | P | bogus | Get page size
      0800h | P | 0.9 | Map physical address
      0900h | P | 0.9 | Disable interrupts
      0901h | P | 0.9 | Enable interrupts
      0902h | P | 0.9 | Get interrupt state

   2. Allocation strategy:

      RAW | - kb granular | (best fit)
      XMS | - kb granular | (???)
      VCPI | - 4k granular | (first fit)
      DPMI | - ??? | (???)

   3. DPMI 0.90 deviation list:
      - int24h is not handled at all
      - D3X doesn't change stacks at IRQs for speed reasons.
      - The selector modification functions don't allow non-present selectors to prevent severe exceptions.
      - The <0.9+> functions act like <1.0>, but they never return an error code.
   4. Tips & tricks:
      - D3X checks for the presence of a DPMI host first. In that case your program talks to the DPMI host and not D3X. As discussed above, D3X doesn't support all DPMI 0.9 features, so if you develop under a DPMI host be sure you sometimes test with no DPMI!
      - Some DPMI functions are *BOGUS* (i.e. locking functions), because D3X doesn't have virtual memory and pages are never swapped on disk. Though, these functions are useful when running under another DPMI host (that uses virtual memory), and therefore they return ok.
      - In RAW mode, all extended memory is allocated (internally) and if you run another app in shell mode, no extended memory will be available. Sorry, may get fixed someday.

3. INT21 extended API (WATCOM version only):

           1.DOS/09h - Write String to Standard Output:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 09h
           DS:EDX -> '$' terminated string to write

           Out: always successful
           ---------------------------------------------------------------------------

           2.DOS/1Ah - Set Disk Transfer Area:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 1Ah
           DS:EDX -> buffer for DTA

           Out: always successful
           ---------------------------------------------------------------------------

           3.DOS/1Bh - Get Allocation Information for Default Drive:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 1Bh

           Out: always successful:
               AL	= sectors per cluster
               ECX	= bytes per sector
               EDX	= total number of clusters
               DS:EBX -> media ID byte
           ---------------------------------------------------------------------------

           4.DOS/1Ch - Get Allocation Information for Specific Drive:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 1Ch
           DL	= drive number

           Out: if successful:
               same as DOS/1Bh
            if failed:
               AL	= FFh (invalid drive)
           ---------------------------------------------------------------------------

           5.DOS/1Fh - Get Drive Parameter Block for Default Drive:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 1Fh

           Out: if successful:
               DS:EBX -> drive parameter block
            if failed:
               AL	= FFh (invalid drive)
           ---------------------------------------------------------------------------

           6.DOS/25h - Set Interrupt Vector:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 25h
           AL	= interrupt number
           DS:EDX -> interrupt routine

           Out: if successful:
               carry flag clear
            if failed:
               carry flag set
           ---------------------------------------------------------------------------

           7.DOS/2Fh - Get Disk Transfer Area:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 2Fh

           Out: always successful:
               ES:EBX -> DTA
           ---------------------------------------------------------------------------

           8.DOS/32h - Get Drive Parameter Block for Specific Drive:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 32h
           DL	= drive number

           Out: if successful:
               AL	= 0
               DS:EBX -> drive parameter block
            if failed:
               AL	= FFh (invalid drive)
           ---------------------------------------------------------------------------

           9.DOS/34h - Get Address of InDOS Flag:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 34h

           Out: always successful:
               ES:EBX -> InDOS flag
           ---------------------------------------------------------------------------

           10.DOS/35h - Get Interrupt Vector:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 35h
           AL	= interrupt number

           Out: always successful:
               ES:EBX -> interrupt routine
           ---------------------------------------------------------------------------

           11.DOS/39h - Create Subdirectory:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 39h
           DS:EDX -> ASCIIZ path name

           Out: if successful:
               carry flag clear
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           12.DOS/3Ah - Remove Subdirectory:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 3Ah
           DS:EDX -> ASCIIZ path name

           Out: if successful:
               carry flag clear
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           13.DOS/3Bh - Set Directory:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 3Bh
           DS:EDX -> ASCIIZ path name

           Out: if successful:
               carry flag clear
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           14.DOS/3Ch - Create File:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 3Ch
           CX	= attribute
           DS:EDX -> ASCIIZ path name

           Out: if successful:
               carry flag clear
               EAX	= handle
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           15.DOS/3Dh - Open File:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 3Dh
           AL	= open code
           DS:EDX -> ASCIIZ path name

           Out: if successful:
               carry flag clear
               EAX	= handle
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           16.DOS/3Fh - Read From File:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	 = 3Fh
           BX	 = file handle
           ECX	 = number of bytes to read
           DS:EDX -> buffer to read to

           Out: if successful:
               carry flag clear
               EAX	= number of bytes read
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           17.DOS/40h - Write To File:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	 = 40h
           BX	 = file handle
           ECX	 = number of bytes to write
           DS:EDX -> buffer to write from

           Out: if successful:
               carry flag clear
               EAX	= number of bytes written
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           18.DOS/41h - Delete File:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	 = 41h
           DS:EDX -> ASCIIZ path name

           Out: if successful:
               carry flag clear
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           19.DOS/43h - Get/Set File Attributes:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	 = 43h
           AL	 = function code
           CX	 = desired attributes
           DS:EDX -> ASCIIZ path name

           Out: if successful:
               carry flag clear
               CX	= current attributes
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           20.DOS/47h - Get Directory Path:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 47h
           DL	= drive number
           DS:ESI -> buffer for path

           Out: if successful:
               carry flag clear
               buffer pointed to by DS:ESI is filled with the path
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           21.DOS/48h - Allocate Memory Block:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 48h
           BX	= paragraphs to allocate

           Out: if successful:
               carry flag clear
               EAX	= selector for memory block
            if failed:
               carry flag set
               EAX	= error code
               EBX	= maximum paragraphs available
           ---------------------------------------------------------------------------

           22.DOS/49h - Free Memory Block:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 49h
           ES	= selector for memory block

           Out: if successful:
               carry flag clear
               ES	= NULL selector (to prevent loading invalid selector)
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           23.DOS/4Ah - Resize Memory Block:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 4Ah
           BX	= total paragraphs to allocate
           ES	= selector

           Out: if successful:
               carry flag clear
            if failed:
               carry flag set
               EAX	= error code
               EBX	= maximum paragraphs available for specified block
           ---------------------------------------------------------------------------

           24.DOS/4Bh - Sub-Function 00h - Load and Execute Program:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 4Bh
           AL	= 00h
           DS:EDX -> path name
           ES:EBX -> parameter block

           Out: if successful:
               carry flag clear
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           25.DOS/4Eh - Search for First Filename Match:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 4Eh
           CX	= file attribute
           DS:EDX -> ASCIIZ path name

           Out: if successful:
               carry flag clear
               EAX	= 0
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           26.DOS/4Fh - Search for Next Filename Match:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 4Fh

           Out: if successful:
               carry flag clear
               EAX	= 0
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           27.DOS/56h - Rename File:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 56h
           DS:EDX -> old filename
           ES:EDI -> new filename

           Out: if successful:
               carry flag clear
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           28.DOS/5Bh - New File:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 5Bh
           CX	= attribute
           DS:EDX -> ASCIIZ path name

           Out: if successful:
               carry flag clear
               EAX	= handle
            if failed:
               carry flag set
               EAX	= error code
           ---------------------------------------------------------------------------

           29.DOS/62h - Get PSP:
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AH	= 62h

           Out: always successful:
               EBX	PSP selector
           ---------------------------------------------------------------------------

4. INT33 extended API (WATCOM version only): carry flag is always set on error

           1.MOUSE/0009h - Set graphics pointer shape
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AX	= 0009h
           BX	= hot spot (horizontal)
           CX	= hot spot (vertical)
           DS:EDX -> pointer shape

           Out: none
           ---------------------------------------------------------------------------

           2.MOUSE/000Ch - Set event handler
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AX	= 000Ch
           CX	= event mask
           DS:EDX -> event handler code

           Out: none
           ---------------------------------------------------------------------------

           3.MOUSE/0016h - Save driver state
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AX	= 0016h
           DS:EDX -> buffer for driver state

           Out: none
           ---------------------------------------------------------------------------

           4.MOUSE/0017h - Load driver state
           - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
           In:	AX	= 0017h
           DS:EDX -> buffer containing state

           Out: none
           ---------------------------------------------------------------------------

5. D3X errors:

   In some cases, the extender generates an error (`D3X: error 0x??'), and the program will exit with proper error code:
   D3X: error 0xff: need 386+ CPU
     You need 32bit PM. Buy a 386!
   D3X: error 0xfe: need DOS 3.0+
     This is needed for file I/O. Upgrade!
   D3X: error 0xfd: no DOS memory
     The extender could not initialize. Free up some low memory, use XMS/RAW (no pagetables), or decrease transferbuffer (min 2k).
   D3X: error 0xfc: DPMI host error
     An external DPMI host is present and unable to provide full services, or is 16bit. Remove the foreign host.
   D3X: error 0xfb: VCPI server error
     A VCPI server is present and unable to provide full services. Reboot without EMM (or update your Expanded Memory Manager).
   D3X: error 0xfa: V86 but no DPMI/VCPI
     Either the memory manager is in AUTO mode, or a strange virtual mode provider lies in the background. Stop it!
   D3X: error 0xf9: A20 gate failure
     The extender cannot take control over the A20 line. Either is a hardware error, or the memory manager is stupid.
   D3X: error 0xf8: unable to spawn image
     Cannot load the application file; it may be missing, corrupted or unsupported type.
   D3X: error 0xf7: no DPMI memory
     Failed allocating memory through (either internal or external) DPMI host.

6. Closing bytes, words, doublewords...

D3X is dedicated to all those who love the Art of Assembler.

The DOC files for D3X may be not complete, as I'm working on this alone and there are things I can't figure out for now... If you have something decent to comment/ask/suggest, do not hesitate to do so.

Creditz:

    	Adam Seychell     (DOS32 v0.1)		- idea and basics
        CW Sandmann       (CWSDPMI v0.90+ r4)	- task and int handling
        Matthias Grimrath (PMODE/DJ v1.2)	- VCPI setup
        Michael Tippach   (WDOSX v0.96 beta 1)	- LE loader

Greetz:

    	Gerula ~ AG (Gfx/Code/Muzak) - happy new games, if ever...

...done by GrayWolf ~ Access Granted