summaryrefslogtreecommitdiffstats
path: root/src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
commitf8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch)
tree26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm
parentInitial commit. (diff)
downloadvirtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz
virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm')
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm1669
1 files changed, 1669 insertions, 0 deletions
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm b/src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm
new file mode 100644
index 00000000..30a1f1b6
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuestA-os2.asm
@@ -0,0 +1,1669 @@
+; $Id: VBoxGuestA-os2.asm $
+;; @file
+; VBoxGuest - OS/2 assembly file, the first file in the link.
+;
+
+;
+; Copyright (C) 2007-2019 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;-----------------------------------------------------------------------------
+; This code is based on:
+;
+; VBoxDrv - OS/2 assembly file, the first file in the link.
+;
+; Copyright (c) 2007-2010 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"
+%include "iprt/err.mac"
+%include "VBox/VBoxGuest.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
+
+
+;*******************************************************************************
+;* Defined Constants And Macros *
+;*******************************************************************************
+; Some devhdr.inc stuff.
+%define DEVLEV_3 0180h
+%define DEV_30 0800h
+%define DEV_IOCTL 4000h
+%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_EOI 031h
+%define DevHlp_SetIRQ 01bh
+%define DevHlp_PhysToVirt 015h
+
+; Fast IOCtl category, also defined in VBoxGuest.h
+%define VBGL_IOCTL_CATEGORY_FAST 0c3h
+
+;;
+; Got some nasm/link trouble, so emit the stuff ourselves.
+; @param %1 Must be a GLOBALNAME.
+%macro JMP32TO16 1
+ ;jmp far dword NAME(%1) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(%1) wrt CODE16
+ dw CODE16
+%endmacro
+
+;;
+; Got some nasm/link trouble, so emit the stuff ourselves.
+; @param %1 Must be a GLOBALNAME.
+%macro JMP16TO32 1
+ ;jmp far dword NAME(%1) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(%1) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+%endmacro
+
+
+;*******************************************************************************
+;* External Symbols *
+;*******************************************************************************
+segment CODE16
+extern DOS16OPEN
+extern DOS16CLOSE
+extern DOS16WRITE
+extern DOS16DEVIOCTL2
+segment TEXT32
+extern KernThunkStackTo32
+extern KernThunkStackTo16
+
+extern NAME(vgdrvOS2Init)
+extern NAME(vgdrvOS2Open)
+extern NAME(vgdrvOS2Close)
+extern NAME(vgdrvOS2IOCtl)
+extern NAME(vgdrvOS2IOCtlFast)
+extern NAME(vgdrvOS2IDCConnect)
+extern NAME(VGDrvOS2IDCService)
+extern NAME(vgdrvOS2ISR)
+
+
+segment DATA16
+
+;;
+; Device headers. The first one is the one we'll be opening and the
+; latter is only used for 32-bit initialization.
+GLOBALNAME g_VBoxGuestHdr1
+ dw NAME(g_VBoxGuestHdr2) wrt DATA16 ; NextHeader.off
+ dw DATA16 ; NextHeader.sel
+ dw DEVLEV_3 | DEV_30 | DEV_CHAR_DEV | DEV_IOCTL; SDevAtt
+ dw NAME(VGDrvOS2Entrypoint) wrt CODE16 ; StrategyEP
+ dw NAME(VGDrvOS2IDC) wrt CODE16 ; IDCEP
+ db 'vboxgst$' ; DevName
+ dw 0 ; SDevProtCS
+ dw 0 ; SDevProtDS
+ dw 0 ; SDevRealCS
+ dw 0 ; SDevRealDS
+ dd DEV_16MB | DEV_IOCTL2 ; SDevCaps
+
+align 4
+GLOBALNAME g_VBoxGuestHdr2
+ dd 0ffffffffh ; NextHeader (NIL)
+ dw DEVLEV_3 | DEV_30 | DEV_CHAR_DEV ; SDevAtt
+ dw NAME(vgdrvOS2InitEntrypoint) wrt CODE16 ; StrategyEP
+ dw 0 ; IDCEP
+ db 'vboxgs1$' ; 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
+
+
+;; vgdrvFindAdapter Output
+; @{
+
+;; The MMIO base of the VMMDev.
+GLOBALNAME g_PhysMMIOBase
+ dd 0
+;; The size of the MMIO memory of the VMMDev.
+GLOBALNAME g_cbMMIO
+ dd 0
+;; The I/O port base of the VMMDev.
+GLOBALNAME g_IOPortBase
+ dw 0
+;; The VMMDev Interrupt Line.
+GLOBALNAME g_bInterruptLine
+ db 0
+;; The PCI bus number returned by Find PCI Device.
+GLOBALNAME g_bPciBusNo
+ db 0
+;; The PCI Device No / Function Number returned by Find PCI Device.
+; (The upper 5 bits is the number, and the lower 3 the function.)
+GLOBALNAME g_bPciDevFunNo
+ db 0
+;; Flag that is set by the vboxgst$ init routine if VMMDev was found.
+; Both init routines must refuse loading the driver if the
+; device cannot be located.
+GLOBALNAME g_fFoundAdapter
+ db 0
+;; @}
+
+
+%ifdef DEBUG_READ
+;; 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
+%endif ; DEBUG_READ
+
+
+;
+; 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
+
+;; Message string that's written on failure.
+g_achLoadFailureMsg1:
+ db 0dh,0ah,'VBoxGuest: load failure no. '
+g_cchLoadFailureMsg1 EQU $ - g_achLoadFailureMsg1
+g_achLoadFailureMsg2:
+ db '!',0dh,0ah
+g_cchLoadFailureMsg2 EQU $ - g_achLoadFailureMsg2
+
+
+;
+; 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 VGDrvOS2Entrypoint
+ 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 vgdrvOS2EP_NotGenIOCtl
+
+
+ ;
+ ; Generic I/O Control Request.
+ ;
+vgdrvOS2EP_GenIOCtl:
+
+ ; Fast IOCtl?
+ cmp byte [es:bx + PKTIOCTL.cat], VBGL_IOCTL_CATEGORY_FAST
+ jne vgdrvOS2EP_GenIOCtl_Other
+
+ ;
+ ; Fast IOCtl.
+ ; DECLASM(int) vgdrvOS2IOCtlFast(uint16_t sfn, uint8_t iFunction, uint16_t *pcbParm)
+ ;
+vgdrvOS2EP_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
+
+ JMP16TO32 vgdrvOS2EP_GenIOCtl_Fast_32
+segment TEXT32
+GLOBALNAME vgdrvOS2EP_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(vgdrvOS2IOCtlFast)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ JMP32TO16 vgdrvOS2EP_GenIOCtl_Fast_32
+segment CODE16
+GLOBALNAME vgdrvOS2EP_GenIOCtl_Fast_16
+
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near vgdrvOS2EP_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)
+ ;
+vgdrvOS2EP_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 vgdrvOS2EP_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 vgdrvOS2EP_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
+
+ JMP16TO32 vgdrvOS2EP_GenIOCtl_Other_32
+segment TEXT32
+GLOBALNAME vgdrvOS2EP_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(vgdrvOS2IOCtl)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ JMP32TO16 vgdrvOS2EP_GenIOCtl_Other_16
+segment CODE16
+GLOBALNAME vgdrvOS2EP_GenIOCtl_Other_16
+
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near vgdrvOS2EP_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.
+ ;
+vgdrvOS2EP_NotGenIOCtl:
+ cmp byte [es:bx + PKTHDR.cmd], 0dh ; Open
+ je vgdrvOS2EP_Open
+ cmp byte [es:bx + PKTHDR.cmd], 0eh ; Close
+ je vgdrvOS2EP_Close
+ cmp byte [es:bx + PKTHDR.cmd], 00h ; Init
+ je vgdrvOS2EP_Init
+%ifdef DEBUG_READ
+ cmp byte [es:bx + PKTHDR.cmd], 04h ; Read
+ je near vgdrvOS2EP_Read
+%endif
+ jmp near vgdrvOS2EP_NotSupported
+
+
+ ;
+ ; Open Request. w/ ring-0 init.
+ ;
+vgdrvOS2EP_Open:
+ cmp byte [NAME(g_fInitialized)], 1
+ jne vgdrvOS2EP_OpenOther
+
+ ; First argument, the system file number.
+ movzx eax, word [es:bx + PKTOPEN.sfn]
+ push eax
+
+ JMP16TO32 vgdrvOS2EP_Open_32
+segment TEXT32
+GLOBALNAME vgdrvOS2EP_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(vgdrvOS2Open)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ JMP32TO16 vgdrvOS2EP_Open_16
+segment CODE16
+GLOBALNAME vgdrvOS2EP_Open_16
+
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near vgdrvOS2EP_GeneralFailure
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ jmp near vgdrvOS2EP_Done
+
+ ; Initializing or failed init?
+vgdrvOS2EP_OpenOther:
+ cmp byte [NAME(g_fInitialized)], 0
+ jne vgdrvOS2EP_OpenFailed
+
+ mov byte [NAME(g_fInitialized)], -1
+ call NAME(vgdrvRing0Init)
+ cmp byte [NAME(g_fInitialized)], 1
+ je vgdrvOS2EP_Open
+
+vgdrvOS2EP_OpenFailed:
+ mov word [es:bx + PKTHDR.status], 0810fh ; error, done, init failed.
+ jmp near vgdrvOS2EP_Done
+
+
+ ;
+ ; Close Request.
+ ;
+vgdrvOS2EP_Close:
+ ; First argument, the system file number.
+ movzx eax, word [es:bx + PKTOPEN.sfn]
+ push eax
+
+ JMP16TO32 vgdrvOS2EP_Close_32
+segment TEXT32
+GLOBALNAME vgdrvOS2EP_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(vgdrvOS2Close)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ JMP32TO16 vgdrvOS2EP_Close_16
+segment CODE16
+GLOBALNAME vgdrvOS2EP_Close_16
+
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near vgdrvOS2EP_GeneralFailure
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ jmp near vgdrvOS2EP_Done
+
+
+ ;
+ ; Init Request.
+ ; Find the VMMDev adapter so we can unload the driver (and avoid trouble) if not found.
+ ;
+vgdrvOS2EP_Init:
+ call NAME(vgdrvFindAdapter)
+ test ax, ax
+ jz .ok
+ mov word [es:bx + PKTHDR.status], 0810fh ; error, done, init failed.
+ call NAME(vgdrvOS2InitFlushText)
+ jmp .next
+.ok:
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+.next:
+ 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 vgdrvOS2EP_Done
+
+
+%ifdef DEBUG_READ
+ ;
+ ; Read Request.
+ ; Return log data.
+ ;
+vgdrvOS2EP_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 vgdrvOS2EP_Done
+
+.log_phystovirt_failed:
+ les bx, [bp - 4] ; Reload the packet pointer.
+ jmp vgdrvOS2EP_GeneralFailure
+%endif ; DEBUG_READ
+
+
+ ;
+ ; Return 'unknown command' error.
+ ;
+vgdrvOS2EP_NotSupported:
+ mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
+ jmp vgdrvOS2EP_Done
+
+ ;
+ ; Return 'general failure' error.
+ ;
+vgdrvOS2EP_GeneralFailure:
+ mov word [es:bx + PKTHDR.status], 0810ch ; error, done, general failure.
+ jmp vgdrvOS2EP_Done
+
+ ;
+ ; Non-optimized return path.
+ ;
+vgdrvOS2EP_Done:
+ mov sp, bp
+ pop ebp
+ retf
+ENDPROC VGDrvOS2Entrypoint
+
+
+;;
+; 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 vgdrvOS2InitEntrypoint
+ ; The only request we're servicing is the 'init' one.
+ cmp word [es:bx + PKTHDR.cmd], 0
+ je near NAME(vgdrvOS2InitEntrypointServiceInitReq)
+
+ ; Ok, it's not the init request, just fail it.
+ mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
+ retf
+
+
+;;
+; The OS/2 IDC entry point.
+;
+; This is only used to setup connection, the returned structure
+; will provide the entry points that we'll be using.
+;
+; @cproto void far __cdecl VGDrvOS2IDC(VBOXGUESTOS2IDCCONNECT far *fpConnectInfo);
+;
+; @param fpConnectInfo [bp + 8] Pointer to an VBOXGUESTOS2IDCCONNECT structure.
+;
+GLOBALNAME VGDrvOS2IDC
+ push ebp ; bp - 0h
+ mov ebp, esp
+ ; save everything we might touch.
+ push es ; bp - 2h
+ push ds ; bp - 4h
+ push eax ; bp - 8h
+ push ebx ; bp - 0ch
+ push ecx ; bp - 10h
+ push edx ; bp - 14h
+ and sp, 0fffch
+
+ JMP16TO32 VGDrvOS2IDC_32
+segment TEXT32
+GLOBALNAME VGDrvOS2IDC_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(vgdrvOS2IDCConnect)
+
+ ;
+ ; Load the return buffer address into ds:ebx and setup the buffer.
+ ; (eax == u32Session)
+ ;
+ mov cx, [ebp + 08h + 2]
+ mov ds, cx
+ movzx ebx, word [ebp + 08h]
+
+ mov dword [ebx + VBGLOS2ATTACHDD.u32Version ], VBGL_IOC_VERSION
+ mov dword [ebx + VBGLOS2ATTACHDD.u32Session ], eax
+ mov dword [ebx + VBGLOS2ATTACHDD.pfnServiceEP ], NAME(VGDrvOS2IDCService)
+ mov word [ebx + VBGLOS2ATTACHDD.fpfnServiceEP ], NAME(VGDrvOS2IDCService16) wrt CODE16
+ mov word [ebx + VBGLOS2ATTACHDD.fpfnServiceEP + 2], CODE16
+ mov word [ebx + VBGLOS2ATTACHDD.fpfnServiceAsmEP ], NAME(VGDrvOS2IDCService16Asm) wrt CODE16
+ mov word [ebx + VBGLOS2ATTACHDD.fpfnServiceAsmEP+2],CODE16
+
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+
+ ; switch back the stack.
+ call KernThunkStackTo16
+
+ JMP32TO16 VGDrvOS2IDC_16
+segment CODE16
+GLOBALNAME VGDrvOS2IDC_16
+
+ ; restore.
+ lea sp, [bp - 14h]
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ pop ds
+ pop es
+ pop ebp
+ retf
+ENDPROC VGDrvOS2IDC
+
+
+;;
+; The 16-bit IDC entry point, cdecl.
+;
+; All this does is thunking the request into something that fits
+; the 32-bit IDC service routine.
+;
+;
+; @returns VBox status code.
+; @param u32Session bp + 8h - The above session handle.
+; @param iFunction bp + 0ch - The requested function.
+; @param fpReqHdr bp + 0eh - The input/output data buffer. The caller ensures that this
+; cannot be swapped out, or that it's acceptable to take a
+; page in fault in the current context. If the request doesn't
+; take input or produces output, passing NULL is okay.
+; @param cbReq bp + 12h - The size of the data buffer.
+;
+; @cproto long far __cdecl VGDrvOS2IDCService16(uint32_t u32Session, uint16_t iFunction, void far *fpReqHdr, uint16_t cbReq);
+;
+GLOBALNAME VGDrvOS2IDCService16
+ push ebp ; bp - 0h
+ mov ebp, esp
+ push es ; bp - 2h
+ push ds ; bp - 4h
+ push ecx ; bp - 8h
+ push edx ; bp - 0ch
+ push esi ; bp - 10h
+ and sp, 0fffch ; align the stack.
+
+ ; locals
+ push dword 0 ; esp + 18h (dd): cbDataReturned
+
+ ; load our ds (for g_fpfnDevHlp).
+ mov ax, DATA16
+ mov ds, ax
+
+ ;
+ ; Create the call frame before switching.
+ ;
+ movzx ecx, word [bp + 12h]
+ push ecx ; esp + 10h: cbData
+
+ ; thunk data argument if present.
+ mov ax, [bp + 0eh + 2] ; selector
+ cmp ax, 3 ; <= 3 -> nil selector...
+ jbe .no_data
+ movzx esi, word [bp + 0eh] ; offset
+ mov dl, DevHlp_VirtToLin
+ call far [NAME(g_fpfnDevHlp)]
+ jc near VGDrvOS2IDCService16_InvalidPointer
+ jmp .finish_data
+.no_data:
+ xor eax, eax
+.finish_data:
+ push eax ; esp + 08h: pvData
+ movzx edx, word [bp + 0ch]
+ push edx ; esp + 04h: iFunction
+ mov ecx, [bp + 08h]
+ push ecx ; esp + 00h: u32Session
+
+ JMP16TO32 VGDrvOS2IDCService16_32
+segment TEXT32
+GLOBALNAME VGDrvOS2IDCService16_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(VGDrvOS2IDCService)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ JMP32TO16 VGDrvOS2IDCService16_16
+segment CODE16
+GLOBALNAME VGDrvOS2IDCService16_16
+
+VGDrvOS2IDCService16_Done:
+ lea sp, [bp - 10h]
+ pop esi
+ pop edx
+ pop ecx
+ pop ds
+ pop es
+ pop ebp
+ retf
+
+VGDrvOS2IDCService16_InvalidPointer:
+ mov ax, VERR_INVALID_POINTER
+ jmp VGDrvOS2IDCService16_Done
+ENDPROC VGDrvOS2IDCService16
+
+
+;;
+; The 16-bit IDC entry point, register based.
+;
+; This is just a wrapper around VGDrvOS2IDCService16 to simplify
+; calls from 16-bit assembly code.
+;
+; @returns ax: VBox status code; cx: The amount of data returned.
+;
+; @param u32Session eax - The above session handle.
+; @param iFunction dl - The requested function.
+; @param pvData es:bx - The input/output data buffer.
+; @param cbData cx - The size of the data buffer.
+;
+GLOBALNAME VGDrvOS2IDCService16Asm
+ push ebp ; bp - 0h
+ mov ebp, esp
+ push edx ; bp - 4h
+
+ push cx ; cbData
+ push es
+ xor dh, dh
+ push dx
+ push eax
+ call NAME(VGDrvOS2IDCService16)
+
+ mov cx, [es:bx + VBGLREQHDR.cbOut]
+
+ mov edx, [bp - 4]
+ mov esp, ebp
+ pop ebp
+ retf
+ENDPROC VGDrvOS2IDCService16Asm
+
+
+
+;;
+; The 16-bit interrupt service routine.
+;
+; OS/2 saves all registers according to the docs, although it doesn't say whether
+; this includes the 32-bit parts. Since it doesn't cost much to be careful, save
+; everything.
+;
+; @returns CF=0 if it's our interrupt, CF=1 it it isn't.
+;
+;
+GLOBALNAME vgdrvOS2ISR16
+ push ebp
+ mov ebp, esp
+ pushf ; bp - 02h
+ cli
+ push eax ; bp - 06h
+ push edx ; bp - 0ah
+ push ebx ; bp - 0eh
+ push ds ; bp - 10h
+ push es ; bp - 12h
+ push ecx ; bp - 16h
+ push esi ; bp - 1ah
+ push edi ; bp - 1eh
+
+ and sp, 0fff0h ; align the stack (16-bytes make GCC extremely happy).
+
+ JMP16TO32 vgdrvOS2ISR16_32
+segment TEXT32
+GLOBALNAME vgdrvOS2ISR16_32
+
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+
+ call KernThunkStackTo32
+
+ call NAME(vgdrvOS2ISR)
+ mov ebx, eax
+
+ call KernThunkStackTo16
+
+ JMP32TO16 vgdrvOS2ISR16_16
+segment CODE16
+GLOBALNAME vgdrvOS2ISR16_16
+
+ lea sp, [bp - 1eh]
+ pop edi
+ pop esi
+ pop ecx
+ pop es
+ pop ds
+ test bl, 0ffh
+ jnz .our
+ pop ebx
+ pop edx
+ pop eax
+ popf
+ pop ebp
+ stc
+ retf
+
+ ;
+ ; Do EIO.
+ ;
+.our:
+ mov al, [NAME(g_bInterruptLine)]
+ mov dl, DevHlp_EOI
+ call far [NAME(g_fpfnDevHlp)]
+
+ pop ebx
+ pop edx
+ pop eax
+ popf
+ pop ebp
+ clc
+ retf
+ENDPROC vgdrvOS2ISR16
+
+
+
+
+
+
+;
+; The 32-bit text segment.
+;
+segment TEXT32
+;;
+; 32-bit worker for registering the ISR.
+;
+; @returns 0 on success, some non-zero OS/2 error code on failure.
+; @param bIrq [ebp + 8] The IRQ number. (uint8_t)
+;
+GLOBALNAME vgdrvOS2DevHlpSetIRQ
+ push ebp
+ mov ebp, esp
+ push ebx
+ push ds
+
+ call KernThunkStackTo16
+
+ movzx ebx, byte [ebp + 8] ; load bIrq into BX.
+
+ JMP32TO16 vgdrvOS2DevHlpSetIRQ_16
+segment CODE16
+GLOBALNAME vgdrvOS2DevHlpSetIRQ_16
+
+ mov ax, DATA16 ; for g_fpfnDevHlp.
+ mov ds, ax
+ mov ax, NAME(vgdrvOS2ISR16) ; The devhlp assume it's relative to DS.
+ mov dh, 1 ; 1 = shared
+ mov dl, DevHlp_SetIRQ
+ call far [NAME(g_fpfnDevHlp)]
+ jnc .ok
+ movzx eax, ax
+ or eax, eax
+ jnz .go_back
+ or eax, 6
+ jmp .go_back
+.ok:
+ xor eax, eax
+
+.go_back:
+ JMP16TO32 vgdrvOS2DevHlpSetIRQ_32
+segment TEXT32
+GLOBALNAME vgdrvOS2DevHlpSetIRQ_32
+
+ pop ds ; KernThunkStackTo32 ASSUMES flat DS and ES.
+
+ mov ebx, eax
+ call KernThunkStackTo32
+ mov eax, ebx
+
+ pop ebx
+ pop ebp
+ ret
+ENDPROC vgdrvOS2DevHlpSetIRQ
+
+
+
+
+;
+; The 16-bit init code.
+;
+segment CODE16_INIT
+GLOBALNAME g_InitCodeStart
+
+;; The device name for DosOpen.
+g_szDeviceName:
+ db '\DEV\vboxgst$', 0
+
+; icsdebug can't see where stuff starts otherwise. (kDevTest)
+int3
+int3
+int3
+int3
+int3
+int3
+
+;;
+; The Ring-3 init code.
+;
+BEGINPROC vgdrvOS2InitEntrypointServiceInitReq
+ 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
+
+ ; check that we found the VMMDev.
+ test byte [NAME(g_fFoundAdapter)], 1
+ jz near .done_err
+
+ ;
+ ; 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(vgdrvOS2InitFlushText)
+ 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 vgdrvOS2InitEntrypointServiceInitReq
+
+
+;;
+; The Ring-0 init code.
+;
+BEGINPROC vgdrvRing0Init
+ 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 vgdrvRing0Init_done ; eax is non-zero on failure (can't happen)
+ push eax ; 00h - pszArgs (for vgdrvOS2Init).
+
+ ;
+ ; Do 16-bit init?
+ ;
+
+
+ ;
+ ; Do 32-bit init
+ ;
+ JMP16TO32 vgdrvRing0Init_32
+segment TEXT32
+GLOBALNAME vgdrvRing0Init_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(vgdrvOS2Init)
+
+ ; switch back the stack and reload ds.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ mov dx, seg NAME(g_fInitialized)
+ mov ds, dx
+
+ JMP32TO16 vgdrvRing0Init_16
+segment CODE16_INIT
+GLOBALNAME vgdrvRing0Init_16
+
+ ; check the result and set g_fInitialized on success.
+ or eax, eax
+ jnz vgdrvRing0Init_done
+ mov byte [NAME(g_fInitialized)], 1
+
+vgdrvRing0Init_done:
+ mov sp, bp
+ pop ebp
+ pop esi
+ pop es
+ ret
+ENDPROC vgdrvRing0Init
+
+
+;;
+; Flush any text in the text buffer.
+;
+BEGINPROC vgdrvOS2InitFlushText
+ 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 vgdrvOS2InitFlushText
+
+
+;; The device name for DosOpen.
+g_szOemHlpDevName:
+ db '\DEV\OEMHLP$', 0
+
+
+;;
+; Talks to OEMHLP$ about finding the VMMDev PCI adapter.
+;
+; On success g_fFoundAdapter is set to 1, and g_cbMMIO,
+; g_PhysMMIOBase and g_IOPortBase are initialized with
+; the PCI data.
+;
+; @returns 0 on success, non-zero on failure. (eax)
+;
+; @remark ASSUMES DS:DATA16.
+; @uses nothing.
+;
+BEGINPROC vgdrvFindAdapter
+ push ebx
+ push ecx
+ push edx
+ push esi
+ push edi
+ push ebp
+ mov ebp, esp
+ push -1 ; bp - 2: hfOpen
+%define hfOpen bp - 2
+ push 0 ; bp - 4: usAction
+%define usAction bp - 4
+ sub sp, 20h ; bp - 44: 32 byte parameter buffer.
+%define abParm bp - 24h
+ sub sp, 40h ; bp - c4: 32 byte data buffer.
+%define abData bp - 44h
+
+;; VBox stuff
+%define VBOX_PCI_VENDORID 080eeh
+%define VMMDEV_DEVICEID 0cafeh
+
+;; OEMHLP$ stuff.
+%define IOCTL_OEMHLP 80h
+%define OEMHLP_PCI 0bh
+%define PCI_FIND_DEVICE 1
+%define PCI_READ_CONFIG 3
+
+;; PCI stuff
+%define PCI_INTERRUPT_LINE 03ch ;;< 8-bit RW - Interrupt line.
+%define PCI_BASE_ADDRESS_0 010h ;;< 32-bit RW */
+%define PCI_BASE_ADDRESS_1 014h ;;< 32-bit RW */
+
+
+%macro CallIOCtl 2
+ ; APIRET _Pascal DosDevIOCtl2(PVOID pData, USHORT cbData, PVOID pParm,
+ ; USHORT cbParm, USHORT usFun, USHORT usCategory,
+ ; HFILE hDev);
+ push ss ; pData
+ lea dx, [abData]
+ push dx
+ push %2 ; cbData
+
+ push ss ; pParm
+ lea dx, [abParm]
+ push dx
+ push %1 ; cbParm
+ push OEMHLP_PCI ; usFun
+ push IOCTL_OEMHLP ; usCategory
+
+ mov ax, [hfOpen] ; hDev
+ push ax
+ call far DOS16DEVIOCTL2
+
+ ; check for error.
+ test ax, ax
+ jnz near .done_err_close
+ cmp [abData + 0], byte 0
+ jne near .done_err_close
+%endmacro
+
+
+ ;
+ ; Open the OEMHLP$ driver.
+ ;
+
+ ; APIRET _Pascal DosOpen(PSZ pszFname, PHFILE phfOpen, PUSHORT pusAction,
+ ; ULONG ulFSize, USHORT usAttr, USHORT fsOpenFlags,
+ ; USHORT fsOpenMode, ULONG ulReserved);
+ mov di, '0'
+ push seg g_szOemHlpDevName ; pszFname
+ push g_szOemHlpDevName
+ push ss ; phfOpen
+ lea dx, [hfOpen]
+ push dx
+ push ss ; pusAction
+ lea dx, [usAction]
+ 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
+ or ax, ax
+ jnz near .done
+
+
+ ;
+ ; Send a PCI_FIND_DEVICE request.
+ ;
+
+ ; Initialize the parameter packet.
+ mov [abParm + 0], byte PCI_FIND_DEVICE ; 0 - db - SubFunction Number
+ mov [abParm + 1], word VMMDEV_DEVICEID ; 1 - dw - Device ID
+ mov [abParm + 3], word VBOX_PCI_VENDORID ; 3 - dw - Vendor ID
+ mov [abParm + 5], byte 0 ; 5 - db - (Device) Index
+
+ ; Zero padd the data packet.
+ mov [abData + 0], dword 0
+
+ mov di, '1'
+ CallIOCtl 6, 3
+
+ mov al, [abData + 1] ; 1 - db - Bus Number.
+ mov [NAME(g_bPciBusNo)], al
+ mov al, [abData + 2] ; 2 - db - DevFunc Number.
+ mov [NAME(g_bPciDevFunNo)], al
+
+ ;
+ ; Read the interrupt register (byte).
+ ;
+ mov di, '2'
+ mov ax, PCI_INTERRUPT_LINE | 0100h
+ call .NestedReadReg
+ mov [NAME(g_bInterruptLine)], al
+
+ ;
+ ; Read the first base address (dword), this shall must be in I/O space.
+ ;
+ mov di, '3'
+ mov ax, PCI_BASE_ADDRESS_0 | 0400h
+ call .NestedReadReg
+ mov di, '4'
+ test al, 1h ; Test that it's an I/O space address.
+ jz .done_err_close
+ mov di, '5'
+ test eax, 0ffff0002h ; These shall all be 0 according to the specs.
+ jnz .done_err_close
+ and ax, 0fffeh
+ mov [NAME(g_IOPortBase)], ax
+
+ ;
+ ; Read the second base address (dword), this shall be in memory space if present.
+ ;
+ mov di, '6'
+ mov ax, PCI_BASE_ADDRESS_1 | 0400h
+ call .NestedReadReg
+ mov di, '7'
+ test al, 1h ; Test that it's a memory space address.
+ jnz .done_err_close
+ and eax, 0fffffff0h
+ mov [NAME(g_PhysMMIOBase)], eax
+
+ ;or eax, eax
+ ;jz .done_success ; No memory region.
+ ;; @todo If there is a simple way of determining the size do that, if
+ ; not we can easily handle it the code that does the actual mapping.
+
+
+ ;
+ ; Ok, we're good!
+ ;
+.done_success:
+ or [NAME(g_fFoundAdapter)], byte 1
+ jmp .done_close
+
+ ;
+ ; Close the OEMHLP$ driver.
+ ;
+.done_err_close:
+ or ax, 80h
+.done_close:
+ ; APIRET APIENTRY DosClose(HFILE hf);
+ push ax ; Save result
+ mov cx, [hfOpen]
+ push cx
+ call far DOS16CLOSE
+ or ax, ax
+ jnz .bitch ; This can't happen (I hope).
+ pop ax
+ or ax, ax
+ jnz .bitch
+
+ ;
+ ; Return to vgdrvOS2EP_Init.
+ ;
+.done:
+ mov esp, ebp
+ pop ebp
+ pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ ret
+
+
+ ;
+ ; Puts the reason for failure in message buffer.
+ ; The caller will flush this.
+ ;
+.bitch:
+ push es
+
+ mov ax, ds
+ mov es, ax
+ mov ax, di ; save the reason.
+ mov di, NAME(g_szInitText)
+ add di, [NAME(g_cchInitText)]
+
+ mov si, g_achLoadFailureMsg1
+ mov cx, g_cchLoadFailureMsg1
+ rep movsb
+
+ stosb
+
+ mov si, g_achLoadFailureMsg2
+ mov cx, g_cchLoadFailureMsg2
+ rep movsb
+
+ mov [di], byte 0
+ sub di, NAME(g_szInitText)
+ mov [NAME(g_cchInitText)], di
+
+ pop es
+ jmp .done
+
+
+ ;
+ ; Nested function which reads a PCI config register.
+ ; (This operates on the vgdrvFindAdapter stack frame.)
+ ;
+ ; Input:
+ ; al - register to read
+ ; ah - register size.
+ ;
+ ; Output:
+ ; eax - the value.
+ ;
+ ; Uses:
+ ; dx
+ ;
+.NestedReadReg:
+ ; Fill in the request packet.
+ mov [abParm + 0], byte PCI_READ_CONFIG ; 0 - db - SubFunction Number
+ mov dl, [NAME(g_bPciBusNo)]
+ mov [abParm + 1], dl ; 1 - db - Bus Number
+ mov dl, [NAME(g_bPciDevFunNo)]
+ mov [abParm + 2], dl ; 2 - db - DevFunc Number
+ mov [abParm + 3], al ; 3 - db - Configuration Register
+ mov [abParm + 4], ah ; 4 - db - (Register) Size
+
+ ; Pad the data packet.
+ mov [abData + 0], dword 0
+ mov [abData + 4], dword 0
+
+ CallIOCtl 5, 5
+
+ mov eax, [abData + 1] ; 1 - dd - Data
+
+ ret
+
+ENDPROC vgdrvFindAdapter
+
+
+
+;;
+; This must be present
+segment DATA32
+g_pfnDos16Write:
+ dd DOS16WRITE ; flat
+