summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm')
-rw-r--r--src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm973
1 files changed, 973 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm b/src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm
new file mode 100644
index 00000000..b27fcd0f
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm
@@ -0,0 +1,973 @@
+; $Id: SUPDrvA-os2.asm $
+;; @file
+; VBoxDrv - OS/2 assembly file, the first file in the link.
+;
+
+;
+; Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+;
+; Permission is hereby granted, free of charge, to any person
+; obtaining a copy of this software and associated documentation
+; files (the "Software"), to deal in the Software without
+; restriction, including without limitation the rights to use,
+; copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of the Software, and to permit persons to whom the
+; Software is furnished to do so, subject to the following
+; conditions:
+;
+; The above copyright notice and this permission notice shall be
+; included in all copies or substantial portions of the Software.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+; OTHER DEALINGS IN THE SOFTWARE.
+;
+
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%define RT_INCL_16BIT_SEGMENTS
+%include "iprt/asmdefs.mac"
+
+
+;*******************************************************************************
+;* Structures and Typedefs *
+;*******************************************************************************
+;;
+; Request packet header.
+struc PKTHDR
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+endstruc
+
+
+;;
+; Init request packet - input.
+struc PKTINITIN
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+
+ .data_1 resb 1
+ .fpfnDevHlp resd 1
+ .fpszArgs resd 1
+ .data_2 resb 1
+endstruc
+
+;;
+; Init request packet - output.
+struc PKTINITOUT
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+
+ .cUnits resb 1 ; block devs only.
+ .cbCode16 resw 1
+ .cbData16 resw 1
+ .fpaBPBs resd 1 ; block devs only.
+ .data_2 resb 1
+endstruc
+
+;;
+; Open request packet.
+struc PKTOPEN
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+ .sfn resw 1
+endstruc
+
+;;
+; Close request packet.
+struc PKTCLOSE
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+ .sfn resw 1
+endstruc
+
+;;
+; IOCtl request packet.
+struc PKTIOCTL
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+
+ .cat resb 1
+ .fun resb 1
+ .pParm resd 1
+ .pData resd 1
+ .sfn resw 1
+ .cbParm resw 1
+ .cbData resw 1
+endstruc
+
+;;
+; Read/Write request packet
+struc PKTRW
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+
+ .media resb 1
+ .PhysTrans resd 1
+ .cbTrans resw 1
+ .start resd 1
+ .sfn resw 1
+endstruc
+
+
+
+;;
+; The two device headers.
+segment DATA16
+
+; Some devhdr.inc stuff.
+%define DEVLEV_3 0180h
+%define DEV_30 0800h
+%define DEV_CHAR_DEV 8000h
+%define DEV_16MB 0002h
+%define DEV_IOCTL2 0001h
+
+; Some dhcalls.h stuff.
+%define DevHlp_VirtToLin 05bh
+%define DevHlp_SAVE_MESSAGE 03dh
+%define DevHlp_PhysToVirt 015h
+
+; Fast IOCtl category, also defined in SUPDrvIOC.h
+%define SUP_CTL_CATEGORY_FAST 0c1h
+
+
+;*******************************************************************************
+;* External Symbols *
+;*******************************************************************************
+extern KernThunkStackTo32
+extern KernThunkStackTo16
+extern DOS16OPEN
+extern DOS16CLOSE
+extern DOS16WRITE
+extern NAME(VBoxDrvInit)
+extern NAME(VBoxDrvOpen)
+extern NAME(VBoxDrvClose)
+extern NAME(VBoxDrvIOCtl)
+extern NAME(VBoxDrvIOCtlFast)
+
+
+;;
+; Device headers. The first one is the one we'll be opening and the
+; latter is only used for 32-bit initialization.
+GLOBALNAME g_VBoxDrvHdr1
+ dw NAME(g_VBoxDrvHdr2) wrt DATA16 ; NextHeader.off
+ dw DATA16 ; NextHeader.sel
+ dw DEVLEV_3 | DEV_30 | DEV_CHAR_DEV; SDevAtt
+ dw NAME(VBoxDrvEP) wrt CODE16 ; StrategyEP
+ dw 0 ; InterruptEP
+ db 'vboxdrv$' ; DevName
+ dw 0 ; SDevProtCS
+ dw 0 ; SDevProtDS
+ dw 0 ; SDevRealCS
+ dw 0 ; SDevRealDS
+ dd DEV_16MB | DEV_IOCTL2 ; SDevCaps
+
+align 4
+GLOBALNAME g_VBoxDrvHdr2
+ dd 0ffffffffh ; NextHeader (NIL)
+ dw DEVLEV_3 | DEV_30 | DEV_CHAR_DEV; SDevAtt
+ dw NAME(VBoxDrvInitEP) wrt CODE16 ; StrategyEP
+ dw 0 ; InterruptEP
+ db 'vboxdr1$' ; DevName
+ dw 0 ; SDevProtCS
+ dw 0 ; SDevProtDS
+ dw 0 ; SDevRealCS
+ dw 0 ; SDevRealDS
+ dd DEV_16MB | DEV_IOCTL2 ; SDevCaps
+
+
+;; Tristate 32-bit initialization indicator [0 = need init, -1 = init failed, 1 init succeeded].
+; Check in the open path of the primary driver. The secondary driver will
+; open the primary one during it's init and thereby trigger the 32-bit init.
+GLOBALNAME g_fInitialized
+ db 0
+
+align 4
+;; Pointer to the device helper service routine
+; This is set during the initialization of the 2nd device driver.
+GLOBALNAME g_fpfnDevHlp
+ dd 0
+
+
+;; Where we write to the log.
+GLOBALNAME g_offLogHead
+ dw 0
+;; Where we read from the log.
+GLOBALNAME g_offLogTail
+ dw 0
+;; The size of the log. (power of two!)
+%define LOG_SIZE 16384
+GLOBALNAME g_cchLogMax
+ dw LOG_SIZE
+;; The log buffer.
+GLOBALNAME g_szLog
+ times LOG_SIZE db 0
+
+
+;
+; The init data.
+;
+segment DATA16_INIT
+GLOBALNAME g_InitDataStart
+
+;; Far pointer to the device argument.
+g_fpszArgs:
+ dd 0
+
+%if 0
+;; Message table for the Save_Message device helper.
+GLOBALNAME g_MsgTab
+ dw 1178 ; MsgId - 'MSG_REPLACEMENT_STRING'.
+ dw 1 ; cMsgStrings
+ dw NAME(g_szInitText) ; MsgStrings[0]
+ dw seg NAME(g_szInitText)
+%else
+;; Far pointer to DOS16WRITE (corrected set before called).
+; Just a temporary hack to work around a wlink issue.
+GLOBALNAME g_fpfnDos16Write
+ dw DOS16WRITE
+ dw seg DOS16WRITE
+%endif
+
+;; Size of the text currently in the g_szInitText buffer.
+GLOBALNAME g_cchInitText
+ dw 0
+;; The max size of text that can fit into the g_szInitText buffer.
+GLOBALNAME g_cchInitTextMax
+ dw 512
+;; The init text buffer.
+GLOBALNAME g_szInitText
+ times 512 db 0
+
+;
+; The 16-bit code segment.
+;
+segment CODE16
+
+
+;;
+; The strategy entry point (vboxdrv$).
+;
+; ss:bx -> request packet
+; ds:si -> device header
+;
+; Can clobber any registers it likes except SP.
+;
+BEGINPROC VBoxDrvEP
+ push ebp
+ mov ebp, esp
+ push es ; bp - 2
+ push bx ; bp - 4
+ and sp, 0fffch
+
+ ;
+ ; Check for the most frequent first.
+ ;
+ cmp byte [es:bx + PKTHDR.cmd], 10h ; Generic IOCtl
+ jne near VBoxDrvEP_NotGenIOCtl
+
+
+ ;
+ ; Generic I/O Control Request.
+ ;
+VBoxDrvEP_GenIOCtl:
+
+ ; Fast IOCtl?
+ cmp byte [es:bx + PKTIOCTL.cat], SUP_CTL_CATEGORY_FAST
+ jne VBoxDrvEP_GenIOCtl_Other
+
+ ;
+ ; Fast IOCtl.
+ ; DECLASM(int) VBoxDrvIOCtlFast(uint16_t sfn, uint8_t iFunction)
+ ;
+VBoxDrvEP_GenIOCtl_Fast:
+ ; function.
+ movzx edx, byte [es:bx + PKTIOCTL.fun]
+ push edx ; 04h
+
+ ; system file number.
+ movzx eax, word [es:bx + PKTIOCTL.sfn]
+ push eax ; 00h
+
+ ; go to the 32-bit code
+ ;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Fast_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvEP_GenIOCtl_Fast_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvEP_GenIOCtl_Fast_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; call the C code (don't cleanup the stack).
+ call NAME(VBoxDrvIOCtlFast)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Fast_16) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvEP_GenIOCtl_Fast_16) wrt CODE16
+ dw CODE16
+segment CODE16
+GLOBALNAME VBoxDrvEP_GenIOCtl_Fast_16
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near VBoxDrvEP_GeneralFailure
+
+ ; setup output stuff.
+ xor eax, eax
+ mov [es:bx + PKTIOCTL.cbParm], eax ; update cbParm and cbData.
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+
+ mov sp, bp
+ pop ebp
+ retf
+
+ ;
+ ; Other IOCtl (slow)
+ ;
+VBoxDrvEP_GenIOCtl_Other:
+ mov eax, [es:bx + PKTIOCTL.cbParm] ; Load cbParm and cbData
+ push eax ; 1eh - in/out data size.
+ ; 1ch - in/out parameter size.
+ push edx ; 18h - pointer to data size (filled in later).
+ push ecx ; 14h - pointer to param size (filled in later).
+
+ ; pData (convert to flat 32-bit)
+ mov ax, word [es:bx + PKTIOCTL.pData + 2] ; selector
+ cmp ax, 3 ; <= 3 -> nil selector...
+ jbe .no_data
+ movzx esi, word [es:bx + PKTIOCTL.pData] ; offset
+ mov dl, DevHlp_VirtToLin
+ call far [NAME(g_fpfnDevHlp)]
+ jc near VBoxDrvEP_GeneralFailure
+ jmp .finish_data
+.no_data:
+ xor eax, eax
+.finish_data:
+ push eax ; 10h
+
+ ; pParm (convert to flat 32-bit)
+ mov ax, word [es:bx + PKTIOCTL.pParm + 2] ; selector
+ cmp ax, 3 ; <= 3 -> nil selector...
+ jbe .no_parm
+ movzx esi, word [es:bx + PKTIOCTL.pParm] ; offset
+ mov dl, DevHlp_VirtToLin
+ call far [NAME(g_fpfnDevHlp)]
+ jc near VBoxDrvEP_GeneralFailure
+ jmp .finish_parm
+.no_parm:
+ xor eax, eax
+.finish_parm:
+ push eax ; 0ch
+
+ ; function.
+ movzx edx, byte [es:bx + PKTIOCTL.fun]
+ push edx ; 08h
+
+ ; category.
+ movzx ecx, byte [es:bx + PKTIOCTL.cat]
+ push ecx ; 04h
+
+ ; system file number.
+ movzx eax, word [es:bx + PKTIOCTL.sfn]
+ push eax ; 00h
+
+ ; go to the 32-bit code
+ ;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Other_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvEP_GenIOCtl_Other_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvEP_GenIOCtl_Other_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; update in/out parameter pointers
+ lea eax, [esp + 1ch]
+ mov [esp + 14h], eax
+ lea edx, [esp + 1eh]
+ mov [esp + 18h], edx
+
+ ; call the C code (don't cleanup the stack).
+ call NAME(VBoxDrvIOCtl)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Other_16) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvEP_GenIOCtl_Other_16) wrt CODE16
+ dw CODE16
+segment CODE16
+GLOBALNAME VBoxDrvEP_GenIOCtl_Other_16
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near VBoxDrvEP_GeneralFailure
+
+ ; setup output stuff.
+ mov edx, esp
+ mov eax, [ss:edx + 1ch] ; output sizes.
+ mov [es:bx + PKTIOCTL.cbParm], eax ; update cbParm and cbData.
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+
+ mov sp, bp
+ pop ebp
+ retf
+
+
+ ;
+ ; Less Performance Critical Requests.
+ ;
+VBoxDrvEP_NotGenIOCtl:
+ cmp byte [es:bx + PKTHDR.cmd], 0dh ; Open
+ je VBoxDrvEP_Open
+ cmp byte [es:bx + PKTHDR.cmd], 0eh ; Close
+ je VBoxDrvEP_Close
+ cmp byte [es:bx + PKTHDR.cmd], 00h ; Init
+ je VBoxDrvEP_Init
+ cmp byte [es:bx + PKTHDR.cmd], 04h ; Read
+ je near VBoxDrvEP_Read
+ jmp near VBoxDrvEP_NotSupported
+
+
+ ;
+ ; Open Request. w/ ring-0 init.
+ ;
+VBoxDrvEP_Open:
+ cmp byte [NAME(g_fInitialized)], 1
+ jne VBoxDrvEP_OpenOther
+
+ ; First argument, the system file number.
+ movzx eax, word [es:bx + PKTOPEN.sfn]
+ push eax
+
+ ; go to the 32-bit code
+ ;jmp far dword NAME(VBoxDrvEP_Open_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvEP_Open_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvEP_Open_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; call the C code.
+ call NAME(VBoxDrvOpen)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvEP_Open_32) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvEP_Open_16) wrt CODE16
+ dw CODE16
+segment CODE16
+GLOBALNAME VBoxDrvEP_Open_16
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near VBoxDrvEP_GeneralFailure
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ jmp near VBoxDrvEP_Done
+
+ ; Initializing or failed init?
+VBoxDrvEP_OpenOther:
+ cmp byte [NAME(g_fInitialized)], 0
+ jne VBoxDrvEP_OpenFailed
+
+ mov byte [NAME(g_fInitialized)], -1
+ call NAME(VBoxDrvRing0Init)
+ cmp byte [NAME(g_fInitialized)], 1
+ je VBoxDrvEP_Open
+
+VBoxDrvEP_OpenFailed:
+ mov word [es:bx + PKTHDR.status], 0810fh ; error, done, init failed.
+ jmp near VBoxDrvEP_Done
+
+
+ ;
+ ; Close Request.
+ ;
+VBoxDrvEP_Close:
+ ; First argument, the system file number.
+ movzx eax, word [es:bx + PKTOPEN.sfn]
+ push eax
+
+ ; go to the 32-bit code
+ ;jmp far dword NAME(VBoxDrvEP_Close_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvEP_Close_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvEP_Close_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; call the C code.
+ call NAME(VBoxDrvClose)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvEP_Close_32) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvEP_Close_16) wrt CODE16
+ dw CODE16
+segment CODE16
+GLOBALNAME VBoxDrvEP_Close_16
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near VBoxDrvEP_GeneralFailure
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ jmp near VBoxDrvEP_Done
+
+
+ ;
+ ; Init Request.
+ ; The other driver header will do this.
+ ;
+VBoxDrvEP_Init:
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ mov byte [es:bx + PKTINITOUT.cUnits], 0
+ mov word [es:bx + PKTINITOUT.cbCode16], NAME(g_InitCodeStart) wrt CODE16
+ mov word [es:bx + PKTINITOUT.cbData16], NAME(g_InitDataStart) wrt DATA16
+ mov dword [es:bx + PKTINITOUT.fpaBPBs], 0
+ jmp near VBoxDrvEP_Done
+
+
+ ;
+ ; Read Request.
+ ; Return log data.
+ ;
+VBoxDrvEP_Read:
+ ; Any log data available?
+ xor dx, dx
+ mov ax, [NAME(g_offLogTail)]
+ cmp ax, [NAME(g_offLogHead)]
+ jz near .log_done
+
+ ; create a temporary mapping of the physical buffer. Docs claims it trashes nearly everything...
+ push ebp
+ mov cx, [es:bx + PKTRW.cbTrans]
+ push cx
+ mov ax, [es:bx + PKTRW.PhysTrans + 2]
+ mov bx, [es:bx + PKTRW.PhysTrans]
+ mov dh, 1
+ mov dl, DevHlp_PhysToVirt
+ call far [NAME(g_fpfnDevHlp)]
+ pop bx ; bx = cbTrans
+ pop ebp
+ jc near .log_phystovirt_failed
+ ; es:di -> the output buffer.
+
+ ; setup the copy operation.
+ mov ax, [NAME(g_offLogTail)]
+ xor dx, dx ; dx tracks the number of bytes copied.
+.log_loop:
+ mov cx, [NAME(g_offLogHead)]
+ cmp ax, cx
+ je .log_done
+ jb .log_loop_before
+ mov cx, LOG_SIZE
+.log_loop_before: ; cx = end offset
+ sub cx, ax ; cx = sequential bytes to copy.
+ cmp cx, bx
+ jbe .log_loop_min
+ mov cx, bx ; output buffer is smaller than available data.
+.log_loop_min:
+ mov si, NAME(g_szLog)
+ add si, ax ; ds:si -> the log buffer.
+ add dx, cx ; update output counter
+ add ax, cx ; calc new offLogTail
+ and ax, LOG_SIZE - 1
+ rep movsb ; do the copy
+ mov [NAME(g_offLogTail)], ax ; commit the read.
+ jmp .log_loop
+
+.log_done:
+ les bx, [bp - 4] ; Reload the packet pointer.
+ mov word [es:bx + PKTRW.cbTrans], dx
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ jmp near VBoxDrvEP_Done
+
+.log_phystovirt_failed:
+ les bx, [bp - 4] ; Reload the packet pointer.
+ jmp VBoxDrvEP_GeneralFailure
+
+
+ ;
+ ; Return 'unknown command' error.
+ ;
+VBoxDrvEP_NotSupported:
+ mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
+ jmp VBoxDrvEP_Done
+
+ ;
+ ; Return 'general failure' error.
+ ;
+VBoxDrvEP_GeneralFailure:
+ mov word [es:bx + PKTHDR.status], 0810ch ; error, done, general failure.
+ jmp VBoxDrvEP_Done
+
+ ;
+ ; Non-optimized return path.
+ ;
+VBoxDrvEP_Done:
+ mov sp, bp
+ pop ebp
+ retf
+ENDPROC VBoxDrvEP
+
+
+;;
+; The helper device entry point.
+;
+; This is only used to do the DosOpen on the main driver so we can
+; do ring-3 init and report failures.
+;
+GLOBALNAME VBoxDrvInitEP
+ ; The only request we're servicing is the 'init' one.
+ cmp word [es:bx + PKTHDR.cmd], 0
+ je near NAME(VBoxDrvInitEPServiceInitReq)
+
+ ; Ok, it's not the init request, just fail it.
+ mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
+ retf
+
+
+;
+; The 16-bit init code.
+;
+segment CODE16_INIT
+GLOBALNAME g_InitCodeStart
+
+;; The device name for DosOpen.
+g_szDeviceName:
+ db '\DEV\vboxdrv$', 0
+
+; icsdebug can't see where stuff starts otherwise. (kDevTest)
+int3
+int3
+int3
+int3
+int3
+int3
+
+;;
+; The Ring-3 init code.
+;
+BEGINPROC VBoxDrvInitEPServiceInitReq
+ push ebp
+ mov ebp, esp
+ push es ; bp - 2
+ push sp ; bp - 4
+ push -1 ; bp - 6: hfOpen
+ push 0 ; bp - 8: usAction
+ and sp, 0fffch
+
+ ; check for the init package.
+ cmp word [es:bx + PKTHDR.cmd], 0
+ jne near .not_init
+
+ ;
+ ; Copy the data out of the init packet.
+ ;
+ mov eax, [es:bx + PKTINITIN.fpfnDevHlp]
+ mov [NAME(g_fpfnDevHlp)], eax
+ mov edx, [es:bx + PKTINITIN.fpszArgs]
+ mov [g_fpszArgs], edx
+
+ ;
+ ; Open the first driver, close it, and check status.
+ ;
+
+ ; APIRET _Pascal DosOpen(PSZ pszFname, PHFILE phfOpen, PUSHORT pusAction,
+ ; ULONG ulFSize, USHORT usAttr, USHORT fsOpenFlags,
+ ; USHORT fsOpenMode, ULONG ulReserved);
+ push seg g_szDeviceName ; pszFname
+ push g_szDeviceName
+ push ss ; phfOpen
+ lea dx, [bp - 6]
+ push dx
+ push ss ; pusAction
+ lea dx, [bp - 8]
+ push dx
+ push dword 0 ; ulFSize
+ push 0 ; usAttr = FILE_NORMAL
+ push 1 ; fsOpenFlags = FILE_OPEN
+ push 00040h ; fsOpenMode = OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY
+ push dword 0 ; ulReserved
+ call far DOS16OPEN
+
+ push ax ; Quickly flush any text.
+ call NAME(VBoxDrvInitFlushText)
+ pop ax
+
+ or ax, ax
+ jnz .done_err
+
+ ; APIRET APIENTRY DosClose(HFILE hf);
+ mov cx, [bp - 6]
+ push cx
+ call far DOS16CLOSE
+ or ax, ax
+ jnz .done_err ; This can't happen (I hope).
+
+ ;
+ ; Ok, we're good.
+ ;
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ mov byte [es:bx + PKTINITOUT.cUnits], 0
+ mov word [es:bx + PKTINITOUT.cbCode16], NAME(g_InitCodeStart) wrt CODE16
+ mov word [es:bx + PKTINITOUT.cbData16], NAME(g_InitDataStart) wrt DATA16
+ mov dword [es:bx + PKTINITOUT.fpaBPBs], 0
+ jmp .done
+
+ ;
+ ; Init failure.
+ ;
+.done_err:
+ mov word [es:bx + PKTHDR.status], 0810fh ; error, done, init failed.
+ mov byte [es:bx + PKTINITOUT.cUnits], 0
+ mov word [es:bx + PKTINITOUT.cbCode16], 0
+ mov word [es:bx + PKTINITOUT.cbData16], 0
+ mov dword [es:bx + PKTINITOUT.fpaBPBs], 0
+ jmp .done
+
+ ;
+ ; Not init, return 'unknown command'.
+ ;
+.not_init:
+ mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
+ jmp .done
+
+ ;
+ ; Request done.
+ ;
+.done:
+ mov sp, bp
+ pop ebp
+ retf
+ENDPROC VBoxDrvInitEPServiceInitReq
+
+
+;;
+; The Ring-0 init code.
+;
+BEGINPROC VBoxDrvRing0Init
+ push es
+ push esi
+ push ebp
+ mov ebp, esp
+ and sp, 0fffch
+
+ ;
+ ; Thunk the argument string pointer first.
+ ;
+ movzx esi, word [g_fpszArgs] ; offset
+ mov ax, [g_fpszArgs + 2] ; selector
+ mov dl, DevHlp_VirtToLin
+ call far [NAME(g_fpfnDevHlp)]
+ jc near VBoxDrvRing0Init_done ; eax is non-zero on failure (can't happen)
+ push eax ; 00h - pszArgs (for VBoxDrvInit).
+
+ ;
+ ; Do 16-bit init?
+ ;
+
+
+ ;
+ ; Do 32-bit init
+ ;
+ ;jmp far dword NAME(VBoxDrvRing0Init_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvRing0Init_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvRing0Init_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; call the C code.
+ call NAME(VBoxDrvInit)
+
+ ; switch back the stack and reload ds.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ mov dx, seg NAME(g_fInitialized)
+ mov ds, dx
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvRing0Init_16) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvRing0Init_16) wrt CODE16
+ dw CODE16_INIT
+segment CODE16_INIT
+GLOBALNAME VBoxDrvRing0Init_16
+
+ ; check the result and set g_fInitialized on success.
+ or eax, eax
+ jnz VBoxDrvRing0Init_done
+ mov byte [NAME(g_fInitialized)], 1
+
+VBoxDrvRing0Init_done:
+ mov sp, bp
+ pop ebp
+ pop esi
+ pop es
+ ret
+ENDPROC VBoxDrvRing0Init
+
+
+;;
+; Flush any text in the text buffer.
+;
+BEGINPROC VBoxDrvInitFlushText
+ push bp
+ mov bp, sp
+
+ ; Anything in the buffer?
+ mov ax, [NAME(g_cchInitText)]
+ or ax, ax
+ jz .done
+
+%if 1
+ ; Write it to STDOUT.
+ ; APIRET _Pascal DosWrite(HFILE hf, PVOID pvBuf, USHORT cbBuf, PUSHORT pcbBytesWritten);
+ push ax ; bp - 2 : cbBytesWritten
+ mov cx, sp
+ push 1 ; STDOUT
+ push seg NAME(g_szInitText) ; pvBuf
+ push NAME(g_szInitText)
+ push ax ; cbBuf
+ push ss ; pcbBytesWritten
+ push cx
+%if 0 ; wlink generates a non-aliased fixup here which results in 16-bit offset with the flat 32-bit selector.
+ call far DOS16WRITE
+%else
+ ; convert flat pointer to a far pointer using the tiled algorithm.
+ push ds
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov eax, g_pfnDos16Write wrt FLAT
+ movzx eax, word [eax + 2] ; High word of the flat address (in DATA32).
+ shl ax, 3
+ or ax, 0007h
+ pop ds
+ mov [NAME(g_fpfnDos16Write) + 2], ax ; Update the selector (in DATA16_INIT).
+ ; do the call
+ call far [NAME(g_fpfnDos16Write)]
+%endif
+
+%else ; alternative workaround for the wlink issue.
+ ; Use the save message devhlp.
+ push esi
+ push ebx
+ xor bx, bx
+ mov si, NAME(g_MsgTab)
+ mov dx, seg NAME(g_MsgTab)
+ mov ds, dx
+ mov dl, DevHlp_SAVE_MESSAGE
+ call far [NAME(g_fpfnDevHlp)]
+ pop ebx
+ pop esi
+%endif
+
+ ; Empty the buffer.
+ mov word [NAME(g_cchInitText)], 0
+ mov byte [NAME(g_szInitText)], 0
+
+.done:
+ mov sp, bp
+ pop bp
+ ret
+ENDPROC VBoxDrvInitFlushText
+
+
+
+;;
+; This must be present
+segment DATA32
+g_pfnDos16Write:
+ dd DOS16WRITE ; flat
+