1
; $Id: SUPDrvA-os2.asm 1197 2007-03-04 20:58:39Z vboxsync $
3
; VBoxDrv - OS/2 assembly file, the first file in the link.
7
; Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
9
; Permission is hereby granted, free of charge, to any person
10
; obtaining a copy of this software and associated documentation
11
; files (the "Software"), to deal in the Software without
12
; restriction, including without limitation the rights to use,
13
; copy, modify, merge, publish, distribute, sublicense, and/or sell
14
; copies of the Software, and to permit persons to whom the
15
; Software is furnished to do so, subject to the following
18
; The above copyright notice and this permission notice shall be
19
; included in all copies or substantial portions of the Software.
21
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22
; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23
; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24
; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25
; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26
; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28
; OTHER DEALINGS IN THE SOFTWARE.
32
;*******************************************************************************
34
;*******************************************************************************
35
%define RT_INCL_16BIT_SEGMENTS
36
%include "iprt/asmdefs.mac"
39
;*******************************************************************************
40
;* Structures and Typedefs *
41
;*******************************************************************************
43
; Request packet header.
55
; Init request packet - input.
71
; Init request packet - output.
80
.cUnits resb 1 ; block devs only.
83
.fpaBPBs resd 1 ; block devs only.
88
; Open request packet.
100
; Close request packet.
112
; IOCtl request packet.
131
; Read/Write request packet
150
; The two device headers.
153
; Some devhdr.inc stuff.
154
%define DEVLEV_3 0180h
156
%define DEV_CHAR_DEV 8000h
157
%define DEV_16MB 0002h
158
%define DEV_IOCTL2 0001h
160
; Some dhcalls.h stuff.
161
%define DevHlp_VirtToLin 05bh
162
%define DevHlp_SAVE_MESSAGE 03dh
163
%define DevHlp_PhysToVirt 015h
165
; Fast IOCtl category, also defined in SUPDRVIOC.h
166
%define SUP_CTL_CATEGORY_FAST 0c1h
169
;*******************************************************************************
170
;* External Symbols *
171
;*******************************************************************************
172
extern KernThunkStackTo32
173
extern KernThunkStackTo16
177
extern NAME(VBoxDrvInit)
178
extern NAME(VBoxDrvOpen)
179
extern NAME(VBoxDrvClose)
180
extern NAME(VBoxDrvIOCtl)
181
extern NAME(VBoxDrvIOCtlFast)
185
; Device headers. The first one is the one we'll be opening and the
186
; latter is only used for 32-bit initialization.
187
GLOBALNAME g_VBoxDrvHdr1
188
dw NAME(g_VBoxDrvHdr2) wrt DATA16 ; NextHeader.off
189
dw DATA16 ; NextHeader.sel
190
dw DEVLEV_3 | DEV_30 | DEV_CHAR_DEV; SDevAtt
191
dw NAME(VBoxDrvEP) wrt CODE16 ; StrategyEP
193
db 'vboxdrv$' ; DevName
198
dd DEV_16MB | DEV_IOCTL2 ; SDevCaps
201
GLOBALNAME g_VBoxDrvHdr2
202
dd 0ffffffffh ; NextHeader (NIL)
203
dw DEVLEV_3 | DEV_30 | DEV_CHAR_DEV; SDevAtt
204
dw NAME(VBoxDrvInitEP) wrt CODE16 ; StrategyEP
206
db 'vboxdr1$' ; DevName
211
dd DEV_16MB | DEV_IOCTL2 ; SDevCaps
214
;; Tristate 32-bit initialization indicator [0 = need init, -1 = init failed, 1 init succeeded].
215
; Check in the open path of the primary driver. The secondary driver will
216
; open the primary one during it's init and thereby trigger the 32-bit init.
217
GLOBALNAME g_fInitialized
221
;; Pointer to the device helper service routine
222
; This is set during the initialization of the 2nd device driver.
223
GLOBALNAME g_fpfnDevHlp
227
;; Where we write to the log.
228
GLOBALNAME g_offLogHead
230
;; Where we read from the log.
231
GLOBALNAME g_offLogTail
233
;; The size of the log. (power of two!)
234
%define LOG_SIZE 16384
235
GLOBALNAME g_cchLogMax
246
GLOBALNAME g_InitDataStart
248
;; Far pointer to the device argument.
253
;; Message table for the Save_Message device helper.
255
dw 1178 ; MsgId - 'MSG_REPLACEMENT_STRING'.
257
dw NAME(g_szInitText) ; MsgStrings[0]
258
dw seg NAME(g_szInitText)
260
;; Far pointer to DOS16WRITE (corrected set before called).
261
; Just a temporary hack to work around a wlink issue.
262
GLOBALNAME g_fpfnDos16Write
267
;; Size of the text currently in the g_szInitText buffer.
268
GLOBALNAME g_cchInitText
270
;; The max size of text that can fit into the g_szInitText buffer.
271
GLOBALNAME g_cchInitTextMax
273
;; The init text buffer.
274
GLOBALNAME g_szInitText
278
; The 16-bit code segment.
284
; The strategy entry point (vboxdrv$).
286
; ss:bx -> request packet
287
; ds:si -> device header
289
; Can clobber any registers it likes except SP.
299
; Check for the most frequent first.
301
cmp byte [es:bx + PKTHDR.cmd], 10h ; Generic IOCtl
302
jne near VBoxDrvEP_NotGenIOCtl
306
; Generic I/O Control Request.
311
cmp byte [es:bx + PKTIOCTL.cat], SUP_CTL_CATEGORY_FAST
312
jne VBoxDrvEP_GenIOCtl_Other
316
; DECLASM(int) VBoxDrvIOCtlFast(uint16_t sfn, uint8_t iFunction, uint16_t *pcbParm)
318
VBoxDrvEP_GenIOCtl_Fast:
319
mov ax, [es:bx + PKTIOCTL.pData + 2] ; LDT selector to flat address.
322
mov ax, [es:bx + PKTIOCTL.pData]
323
push eax ; 08h - pointer to the rc buffer.
326
movzx edx, byte [es:bx + PKTIOCTL.fun]
329
; system file number.
330
movzx eax, word [es:bx + PKTIOCTL.sfn]
333
; go to the 32-bit code
334
;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Fast_32) wrt FLAT
337
dd NAME(VBoxDrvEP_GenIOCtl_Fast_32) ;wrt FLAT
340
GLOBALNAME VBoxDrvEP_GenIOCtl_Fast_32
342
; switch stack to 32-bit.
343
mov ax, DATA32 wrt FLAT
346
call KernThunkStackTo32
348
; call the C code (don't cleanup the stack).
349
call NAME(VBoxDrvIOCtlFast)
351
; switch back the stack.
353
call KernThunkStackTo16
356
; jump back to the 16-bit code.
357
;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Fast_16) wrt CODE16
360
dw NAME(VBoxDrvEP_GenIOCtl_Fast_16) wrt CODE16
363
GLOBALNAME VBoxDrvEP_GenIOCtl_Fast_16
364
les bx, [bp - 4] ; Reload the packet pointer.
366
jnz near VBoxDrvEP_GeneralFailure
368
; setup output stuff.
370
mov eax, [ss:edx + 0ch] ; output sizes.
371
mov [es:bx + PKTIOCTL.cbParm], eax ; update cbParm and cbData.
372
mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
381
VBoxDrvEP_GenIOCtl_Other:
382
mov eax, [es:bx + PKTIOCTL.cbParm] ; Load cbParm and cbData
383
push eax ; 1eh - in/out data size.
384
; 1ch - in/out parameter size.
385
push edx ; 18h - pointer to data size (filled in later).
386
push ecx ; 14h - pointer to param size (filled in later).
388
; pData (convert to flat 32-bit)
389
mov ax, word [es:bx + PKTIOCTL.pData + 2] ; selector
390
cmp ax, 3 ; <= 3 -> nil selector...
392
movzx esi, word [es:bx + PKTIOCTL.pData] ; offset
393
mov dl, DevHlp_VirtToLin
394
call far [NAME(g_fpfnDevHlp)]
395
jc near VBoxDrvEP_GeneralFailure
402
; pParm (convert to flat 32-bit)
403
mov ax, word [es:bx + PKTIOCTL.pParm + 2] ; selector
404
cmp ax, 3 ; <= 3 -> nil selector...
406
movzx esi, word [es:bx + PKTIOCTL.pParm] ; offset
407
mov dl, DevHlp_VirtToLin
408
call far [NAME(g_fpfnDevHlp)]
409
jc near VBoxDrvEP_GeneralFailure
417
movzx edx, byte [es:bx + PKTIOCTL.fun]
421
movzx ecx, byte [es:bx + PKTIOCTL.cat]
424
; system file number.
425
movzx eax, word [es:bx + PKTIOCTL.sfn]
428
; go to the 32-bit code
429
;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Other_32) wrt FLAT
432
dd NAME(VBoxDrvEP_GenIOCtl_Other_32) ;wrt FLAT
435
GLOBALNAME VBoxDrvEP_GenIOCtl_Other_32
437
; switch stack to 32-bit.
438
mov ax, DATA32 wrt FLAT
441
call KernThunkStackTo32
443
; update in/out parameter pointers
449
; call the C code (don't cleanup the stack).
450
call NAME(VBoxDrvIOCtl)
452
; switch back the stack.
454
call KernThunkStackTo16
457
; jump back to the 16-bit code.
458
;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Other_16) wrt CODE16
461
dw NAME(VBoxDrvEP_GenIOCtl_Other_16) wrt CODE16
464
GLOBALNAME VBoxDrvEP_GenIOCtl_Other_16
465
les bx, [bp - 4] ; Reload the packet pointer.
467
jnz near VBoxDrvEP_GeneralFailure
469
; setup output stuff.
471
mov eax, [ss:edx + 1ch] ; output sizes.
472
mov [es:bx + PKTIOCTL.cbParm], eax ; update cbParm and cbData.
473
mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
481
; Less Performance Critical Requests.
483
VBoxDrvEP_NotGenIOCtl:
484
cmp byte [es:bx + PKTHDR.cmd], 0dh ; Open
486
cmp byte [es:bx + PKTHDR.cmd], 0eh ; Close
488
cmp byte [es:bx + PKTHDR.cmd], 00h ; Init
490
cmp byte [es:bx + PKTHDR.cmd], 04h ; Read
491
je near VBoxDrvEP_Read
492
jmp near VBoxDrvEP_NotSupported
496
; Open Request. w/ ring-0 init.
499
cmp byte [NAME(g_fInitialized)], 1
500
jne VBoxDrvEP_OpenOther
502
; First argument, the system file number.
503
movzx eax, word [es:bx + PKTOPEN.sfn]
506
; go to the 32-bit code
507
;jmp far dword NAME(VBoxDrvEP_Open_32) wrt FLAT
510
dd NAME(VBoxDrvEP_Open_32) ;wrt FLAT
513
GLOBALNAME VBoxDrvEP_Open_32
515
; switch stack to 32-bit.
516
mov ax, DATA32 wrt FLAT
519
call KernThunkStackTo32
522
call NAME(VBoxDrvOpen)
524
; switch back the stack.
526
call KernThunkStackTo16
529
; jump back to the 16-bit code.
530
;jmp far dword NAME(VBoxDrvEP_Open_32) wrt CODE16
533
dw NAME(VBoxDrvEP_Open_16) wrt CODE16
536
GLOBALNAME VBoxDrvEP_Open_16
537
les bx, [bp - 4] ; Reload the packet pointer.
539
jnz near VBoxDrvEP_GeneralFailure
540
mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
541
jmp near VBoxDrvEP_Done
543
; Initializing or failed init?
545
cmp byte [NAME(g_fInitialized)], 0
546
jne VBoxDrvEP_OpenFailed
548
mov byte [NAME(g_fInitialized)], -1
549
call NAME(VBoxDrvRing0Init)
550
cmp byte [NAME(g_fInitialized)], 1
553
VBoxDrvEP_OpenFailed:
554
mov word [es:bx + PKTHDR.status], 0810fh ; error, done, init failed.
555
jmp near VBoxDrvEP_Done
562
; First argument, the system file number.
563
movzx eax, word [es:bx + PKTOPEN.sfn]
566
; go to the 32-bit code
567
;jmp far dword NAME(VBoxDrvEP_Close_32) wrt FLAT
570
dd NAME(VBoxDrvEP_Close_32) ;wrt FLAT
573
GLOBALNAME VBoxDrvEP_Close_32
575
; switch stack to 32-bit.
576
mov ax, DATA32 wrt FLAT
579
call KernThunkStackTo32
582
call NAME(VBoxDrvClose)
584
; switch back the stack.
586
call KernThunkStackTo16
589
; jump back to the 16-bit code.
590
;jmp far dword NAME(VBoxDrvEP_Close_32) wrt CODE16
593
dw NAME(VBoxDrvEP_Close_16) wrt CODE16
596
GLOBALNAME VBoxDrvEP_Close_16
597
les bx, [bp - 4] ; Reload the packet pointer.
599
jnz near VBoxDrvEP_GeneralFailure
600
mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
601
jmp near VBoxDrvEP_Done
606
; The other driver header will do this.
609
mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
610
mov byte [es:bx + PKTINITOUT.cUnits], 0
611
mov word [es:bx + PKTINITOUT.cbCode16], NAME(g_InitCodeStart) wrt CODE16
612
mov word [es:bx + PKTINITOUT.cbData16], NAME(g_InitDataStart) wrt DATA16
613
mov dword [es:bx + PKTINITOUT.fpaBPBs], 0
614
jmp near VBoxDrvEP_Done
622
; Any log data available?
624
mov ax, [NAME(g_offLogTail)]
625
cmp ax, [NAME(g_offLogHead)]
628
; create a temporary mapping of the physical buffer. Docs claims it trashes nearly everything...
630
mov cx, [es:bx + PKTRW.cbTrans]
632
mov ax, [es:bx + PKTRW.PhysTrans + 2]
633
mov bx, [es:bx + PKTRW.PhysTrans]
635
mov dl, DevHlp_PhysToVirt
636
call far [NAME(g_fpfnDevHlp)]
637
pop bx ; bx = cbTrans
639
jc near .log_phystovirt_failed
640
; es:di -> the output buffer.
642
; setup the copy operation.
643
mov ax, [NAME(g_offLogTail)]
644
xor dx, dx ; dx tracks the number of bytes copied.
646
mov cx, [NAME(g_offLogHead)]
651
.log_loop_before: ; cx = end offset
652
sub cx, ax ; cx = sequential bytes to copy.
655
mov cx, bx ; output buffer is smaller than available data.
657
mov si, NAME(g_szLog)
658
add si, ax ; ds:si -> the log buffer.
659
add dx, cx ; update output counter
660
add ax, cx ; calc new offLogTail
662
rep movsb ; do the copy
663
mov [NAME(g_offLogTail)], ax ; commit the read.
667
les bx, [bp - 4] ; Reload the packet pointer.
668
mov word [es:bx + PKTRW.cbTrans], dx
669
mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
670
jmp near VBoxDrvEP_Done
672
.log_phystovirt_failed:
673
les bx, [bp - 4] ; Reload the packet pointer.
674
jmp VBoxDrvEP_GeneralFailure
678
; Return 'unknown command' error.
680
VBoxDrvEP_NotSupported:
681
mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
685
; Return 'general failure' error.
687
VBoxDrvEP_GeneralFailure:
688
mov word [es:bx + PKTHDR.status], 0810ch ; error, done, general failure.
692
; Non-optimized return path.
702
; The helper device entry point.
704
; This is only used to do the DosOpen on the main driver so we can
705
; do ring-3 init and report failures.
707
GLOBALNAME VBoxDrvInitEP
708
; The only request we're servicing is the 'init' one.
709
cmp word [es:bx + PKTHDR.cmd], 0
710
je near NAME(VBoxDrvInitEPServiceInitReq)
712
; Ok, it's not the init request, just fail it.
713
mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
718
; The 16-bit init code.
721
GLOBALNAME g_InitCodeStart
723
;; The device name for DosOpen.
725
db '\DEV\vboxdrv$', 0
727
; icsdebug can't see where stuff starts otherwise. (kDevTest)
736
; The Ring-3 init code.
738
BEGINPROC VBoxDrvInitEPServiceInitReq
743
push -1 ; bp - 6: hfOpen
744
push 0 ; bp - 8: usAction
747
; check for the init package.
748
cmp word [es:bx + PKTHDR.cmd], 0
752
; Copy the data out of the init packet.
754
mov eax, [es:bx + PKTINITIN.fpfnDevHlp]
755
mov [NAME(g_fpfnDevHlp)], eax
756
mov edx, [es:bx + PKTINITIN.fpszArgs]
757
mov [g_fpszArgs], edx
760
; Open the first driver, close it, and check status.
763
; APIRET _Pascal DosOpen(PSZ pszFname, PHFILE phfOpen, PUSHORT pusAction,
764
; ULONG ulFSize, USHORT usAttr, USHORT fsOpenFlags,
765
; USHORT fsOpenMode, ULONG ulReserved);
766
push seg g_szDeviceName ; pszFname
774
push dword 0 ; ulFSize
775
push 0 ; usAttr = FILE_NORMAL
776
push 1 ; fsOpenFlags = FILE_OPEN
777
push 00040h ; fsOpenMode = OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY
778
push dword 0 ; ulReserved
781
push ax ; Quickly flush any text.
782
call NAME(VBoxDrvInitFlushText)
788
; APIRET APIENTRY DosClose(HFILE hf);
793
jnz .done_err ; This can't happen (I hope).
798
mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
799
mov byte [es:bx + PKTINITOUT.cUnits], 0
800
mov word [es:bx + PKTINITOUT.cbCode16], NAME(g_InitCodeStart) wrt CODE16
801
mov word [es:bx + PKTINITOUT.cbData16], NAME(g_InitDataStart) wrt DATA16
802
mov dword [es:bx + PKTINITOUT.fpaBPBs], 0
809
mov word [es:bx + PKTHDR.status], 0810fh ; error, done, init failed.
810
mov byte [es:bx + PKTINITOUT.cUnits], 0
811
mov word [es:bx + PKTINITOUT.cbCode16], 0
812
mov word [es:bx + PKTINITOUT.cbData16], 0
813
mov dword [es:bx + PKTINITOUT.fpaBPBs], 0
817
; Not init, return 'unknown command'.
820
mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
830
ENDPROC VBoxDrvInitEPServiceInitReq
834
; The Ring-0 init code.
836
BEGINPROC VBoxDrvRing0Init
844
; Thunk the argument string pointer first.
846
movzx esi, word [g_fpszArgs] ; offset
847
mov ax, [g_fpszArgs + 2] ; selector
848
mov dl, DevHlp_VirtToLin
849
call far [NAME(g_fpfnDevHlp)]
850
jc near VBoxDrvRing0Init_done ; eax is non-zero on failure (can't happen)
851
push eax ; 00h - pszArgs (for VBoxDrvInit).
861
;jmp far dword NAME(VBoxDrvRing0Init_32) wrt FLAT
864
dd NAME(VBoxDrvRing0Init_32) ;wrt FLAT
867
GLOBALNAME VBoxDrvRing0Init_32
869
; switch stack to 32-bit.
870
mov ax, DATA32 wrt FLAT
873
call KernThunkStackTo32
876
call NAME(VBoxDrvInit)
878
; switch back the stack and reload ds.
880
call KernThunkStackTo16
883
mov dx, seg NAME(g_fInitialized)
886
; jump back to the 16-bit code.
887
;jmp far dword NAME(VBoxDrvRing0Init_16) wrt CODE16
890
dw NAME(VBoxDrvRing0Init_16) wrt CODE16
893
GLOBALNAME VBoxDrvRing0Init_16
895
; check the result and set g_fInitialized on success.
897
jnz VBoxDrvRing0Init_done
898
mov byte [NAME(g_fInitialized)], 1
900
VBoxDrvRing0Init_done:
906
ENDPROC VBoxDrvRing0Init
910
; Flush any text in the text buffer.
912
BEGINPROC VBoxDrvInitFlushText
916
; Anything in the buffer?
917
mov ax, [NAME(g_cchInitText)]
922
; Write it to STDOUT.
923
; APIRET _Pascal DosWrite(HFILE hf, PVOID pvBuf, USHORT cbBuf, PUSHORT pcbBytesWritten);
924
push ax ; bp - 2 : cbBytesWritten
927
push seg NAME(g_szInitText) ; pvBuf
928
push NAME(g_szInitText)
930
push ss ; pcbBytesWritten
932
%if 0 ; wlink generates a non-aliased fixup here which results in 16-bit offset with the flat 32-bit selector.
935
; convert flat pointer to a far pointer using the tiled algorithm.
937
mov ax, DATA32 wrt FLAT
939
mov eax, g_pfnDos16Write wrt FLAT
940
movzx eax, word [eax + 2] ; High word of the flat address (in DATA32).
944
mov [NAME(g_fpfnDos16Write) + 2], ax ; Update the selector (in DATA16_INIT).
946
call far [NAME(g_fpfnDos16Write)]
949
%else ; alternative workaround for the wlink issue.
950
; Use the save message devhlp.
954
mov si, NAME(g_MsgTab)
955
mov dx, seg NAME(g_MsgTab)
957
mov dl, DevHlp_SAVE_MESSAGE
958
call far [NAME(g_fpfnDevHlp)]
964
mov word [NAME(g_cchInitText)], 0
965
mov byte [NAME(g_szInitText)], 0
971
ENDPROC VBoxDrvInitFlushText
976
; This must be present