SUPDrvA-os2.asm revision b27991b512ea0b29ef75f62a9e54e4bba411f77e
; $Id$
;; @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, uint16_t *pcbParm)
;
VBoxDrvEP_GenIOCtl_Fast:
mov ax, [es:bx + PKTIOCTL.pData + 2] ; LDT selector to flat address.
shr ax, 3
shl eax, 16
mov ax, [es:bx + PKTIOCTL.pData]
push eax ; 08h - pointer to the rc buffer.
; 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.
mov edx, esp
mov eax, [ss:edx + 0ch] ; 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
;
; 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