;       SCCSID = @(#)v86init.asm        6.11 92/03/28
;
;*************************************************************************
; MODULE:    v86init
; DESCRIPTION:  Handle initialization functions for VM Boot
; FUNCTIONS:    vmstart
;               v86init_initialize
;
; HISTORY:
;
; B001  9/25/91  CP20 B727366  Mark Rogalski
;       v86init_initialize called $set_default_drive before saving the DOS
;       int 21 handler address in pOldInt21. The $set_default_drive routine
;       calls check_dos when we boot from a disk image, and that routine
;       depends on POldInt21 being setup. The setup code was moved up some.
;
; B002  10/13/91  CP20 B728201  Mark Rogalski
;       DOS 3.3 and DR DOS do not support INT 21 function 3305 (get_boot_drive)
;       Therefore, do a get current drive. It should be accurate at boot time.
;
; B003  11/18/91  CP20 B729525  Mark Rogalski
;       Novell requestor depends on the lastdrive statement to determine
;       which drive letters it can use for network access. Therefore, we must
;       obtain this value from DOS and not use our own LASTDRIVE variable.
;
; B004  12/16/91  CP20 B730953  Mark Rogalski
;       Need to put function number in AH before calling SetDefaultDrive.
;
; BN005 - 1/30/92  CP20 AA04471  Mark Rogalski                          ;BN005;
;         No longer need to set up CurrentPDB variable.                 ;BN005;
;
; BN006 - 2/10/92  CP20 B732885  Mark Rogalski                          ;BN006;
;         Need to get address of REAL INDOS variable for later use.     ;BN006;
;
; BN007 - 2/10/92  CP20 B732823  Mark Rogalski                          ;BN007;
;         Go back to telling OS/2 what the current PDB is so lock works ;BN007;
;
; BN008 - 3/28/92  CP20 AZ10696  Mark Rogalski                          ;BN008;
;         Correct the pointer to the INDOS flag.                        ;BN008;
;
; BN009 - 1/18/93  R206 60491    Bill Madden                            ;BN009;
;         Replace int 66's with int 2f.                                 ;BN009;
;
; BC010 - 3/28/95  R207 83872    ChangeTeam                             ;BC010;
;         Increase BPB array from 10 to 26 for drives A-Z.              ;BC010;
;******************************************************************************

.xlist
include v86seg.inc
.xcref
INCL_NONE = 1
INCL_VDH  = 1
INCL_MI   = 1
include mvdm.inc
include osmaca.inc
include demmac.inc
include dossymc.inc
include devsym.inc
include arena.inc
include exe.inc
include dem.inc
include mvdmexp.inc
include vector.inc
include pdb.inc
include doscntry.inc
include demver.inc
include sysvar.inc
include demsvc.inc
include msdos.inc
include error.inc
include harderr.inc
include vmfilter.inc
.cref
.list
        CpuMode 386

        ReferV86        CURDRV,BYTE
        ReferV86        BOOTDRV,BYTE
        ReferV86        LastDrive,BYTE
        ReferV86        EXTERR_LOCUS,WORD
        ReferV86        DOS_DD_chain_head,DWORD
        ReferV86        drivemap,BYTE
        ReferV86        BLKCNT,BYTE
        ReferV86        checkword,WORD
        ReferV86        request,DWORD
        ReferV86        pOldInt20,DWORD
        ReferV86        pOldInt21,DWORD
        ReferV86        attributes,WORD
        ReferV86        REAL_INDOS,DWORD             ;BN006
        ReferV86        currentPDB,WORD

        EXTRN           VMint20:FAR
        EXTRN           VMint21:FAR
        EXTRN           $SET_DEFAULT_DRIVE:NEAR

V86DATA SEGMENT

VDDINTERFACE    equ     02fh    ; Int vector for VDD interface

        public  vheVDM
vheVDM  vhe_s   <>
       VCOM       db 'VCOM',0
       VDSK       db 'VDSK',0
;BD009 VLPT       db 'VLPT'
pfnVCOM    dd 0                                                         ;BN009
pfnVDSK    dd 0                                                         ;BN009

        ALIGN  2
BPB_array  dw   26 dup(offset V86GROUP:BPB)                             ;BC010

        ALIGN 16
BPB        dw   256
           db   1
           dw   0
           db   1
           dw   1
           dw   100
           db   0f0h
           dw   1
           dw   1
           dw   0

        ALIGN 16

;BD007 dummy_pdb  Process_data_block   <>


V86DATA ENDS


V86LAST SEGMENT
        ASSUME  CS:V86GROUP,DS:NOTHING,SS:NOTHING,ES:NOTHING

;***DD  VMStart - VM FILTER device driver init routine
;
;       This function calls some v86initialization code and then
;       sets up the int 21h hook to our int 21 handler.
;
;       ENTRY   NONE
;
;       EXIT    NONE
;
;       METHOD
;
Public VMstart
VMstart proc near

        mov     cs:[checkword],0acceh  ; special check word so that filter is
                                       ; not installed twice

        mov     ax,3521h               ; Get the int 21h handler address ;BC001
        int     21h                                                      ;BC001

        mov     word ptr cs:[pOldInt21], bx     ;save it for future use  ;BC001
        mov     word ptr cs:[pOldInt21+2], es                            ;BC001

        call    v86init_Initialize

        les     bx,cs:[request]        ; get request packet addr.
        mov     al,cs:BLKCNT
        mov     es:[bx+13],al          ; save number of devices in req. packet

; save DD ending address in request packet

        mov     word ptr es:[bx+14],offset V86GROUP:VMstart
        mov     word ptr es:[bx+16],cs

; save DD BPB pointer in packet

        mov     word ptr es:[bx+18],offset V86GROUP:BPB_array
        mov     word ptr es:[bx+20],cs

        mov     ax,3520h               ; Now hook the int 20h handler
        int     21h

        mov     word ptr cs:[pOldInt20], bx     ; save address for future use
        mov     word ptr cs:[pOldInt20+2], es

        mov     ax, seg    V86GROUP:VMInt20     ; the segment
        mov     ds,ax
        mov     dx, offset V86GROUP:VMInt20     ; the offset part
        mov     ax,2520h                        ; set new handler address
        int     21h

        mov     ax, seg    V86GROUP:VMInt21     ; the segment
        mov     ds,ax
        mov     dx, offset V86GROUP:VMInt21     ; the offset part
        mov     ax,2521h                        ; set new handler address
        int     21h

        ret

VMstart endp


;*************************************************************************
;       v86init_initialize
;
;       ENTRY: None
;
;       FUNCTION: set up debug vectors, error addresses, get DD chain head,
;                 determine number of block devices to reserve
;

Procedure v86init_Initialize,near

IF  FILTER_DEBUG
; fix int 1 and int 3 vectors messed up by DOS so I can debug

        mov     ax,0
        mov     es,ax
        mov     di,4
        mov     eax,1d006712h
        mov     es:[di],eax
        mov     di,0ch
        mov     eax,1d006757h
        mov     es:[di],eax

        int     3  ;mdr mdr
ENDIF

; Set extended error variables and VHE (hard error packet)
; structure addresses for protect mode.

        push    cs
        pop     ds
        mov     dx,offset V86GROUP:EXTERR_LOCUS
        mov     bx,offset V86GROUP:vheVDM
        SVC     SVC_DEMSETV86KERNELADDR

; get Block device count DD_chain_head from DOS

        mov     ah,52h                 ; get DOS internal values
        int     21h
        mov     al,es:[bx+32]          ; get number of DOS block devices
        mov     cs:BLKCNT,al
        lea     ax,es:[bx+34]          ; get address of DD chain head
        mov     word ptr cs:[DOS_DD_chain_head],ax   ; save it for later
        mov     ax,es                                ; segment
        mov     word ptr cs:[DOS_DD_chain_head+2],ax

; set up drive map with automatic mappings to OS/2 drives

        SVC     SVC_DEMGETLOGICALDRIVECNT  ; get number of os2 block devices
        movzx   cx,al                  ; AL = numio

        mov     bx,'A'                 ; drive letter to start reserving
st20:   mov     cs:drivemap[bx-'A'],bl ; map DOS letters to all os2 devices
        inc     bl
        loop    st20

; now find out how many additional DOS devices we need to reserve
; at this point CL=0, AL=OS/2 devices
        cmp     al,cs:BLKCNT           ; if os2 count is <= to DOS count
        jle     done                   ; then do not reserve any letters
        sub     al,cs:BLKCNT           ; else get extra number to reserve
        mov     cl,al                  ; save number to reserve
                                       ; CL=number of letter to reserve
done:   cmp     cl,0                   ; if we don't need to reserve any
        jnz     resrv                  ; then change to character device driver
        or      cs:attributes,8000h    ; and inc cl so we pretend to reserve
        inc     cl                     ; a letter so we stay resident
resrv:  mov     cs:BLKCNT,cl

; determine if drive A: should be mapped and/or released

        mov     ah,19h                 ; get the current drive (bootdrive) BC002
        int     21h                    ; AL = drive number  (A=0,B=1...)   BC002
        mov     cs:[CURDRV],al         ; save boot drive number            BC002
        cmp     al,0                   ; if not booting from A skip over   BC002
        jne     st70

        lea     si,V86GROUP:VDSK       ; query VDSK to see if real or virtual A
        xor     di,di                                                   ;BN009
        mov     es,di                                                   ;BN009
        mov     ax,04011h                                               ;BN009
        int     VDDINTERFACE                                            ;BN009
        mov     ax,es                                                   ;BN009
        or      ax,di                  ; did we get the entry point?    ;BN009
        jz      st50                   ; no, let DOS control A:         ;BN009

        mov     word ptr V86GROUP:[pfnVDSK],di                          ;BN009
        mov     word ptr V86GROUP:[pfnVDSK+2],es                        ;BN009

        mov     ah,1h                  ; drive
        call    cs:[pfnVDSK]           ; go check                       ;BN009
;BD006  int     66h
        jc      st50                   ; if error let DOS control A:
        cmp     al,0                   ; if image let DOS control A:
        jnz     st50
        mov     ah,2h                  ; else release drive A:
        call    cs:[pfnVDSK]           ; go check                       ;BN009
;BD006  int     66h
        jmp     st70
st50:   mov     cs:drivemap[0],0       ; do not map drive A: to OS/2
st70:

;re-enable VCOM device

        xor     di,di                                                   ;BN009
        mov     es,di                                                   ;BN009
        lea     si,V86GROUP:VCOM
        mov     ax,04011h                                               ;BN009
        int     VDDINTERFACE                                            ;BN009
        mov     ax,es                                                   ;BN009
        or      ax,di                  ; did we get the entry point?    ;BN009
        jz      st80                   ; no, skip ahead                 ;BN009

        mov     word ptr V86GROUP:[pfnVCOM],di                          ;BN009
        mov     word ptr V86GROUP:[pfnVCOM+2],es                        ;BN009

        mov     ah,1h                  ; enable function
        call    cs:[pfnVCOM]           ; go check                       ;BN009
;BD009  lea     si,V86GROUP:VCOM
;BD009  int     66h
st80:

; initialize out currentPDB pointer and tell OS/2 what it is

        mov     ah,51h                 ;BC007   ; get active process data block
        int     21h                    ;BC007
        mov     currentPDB,bx          ;BC007

;BD007        mov     bx,offset V86GROUP:dummy_pdb    ; determine paragr of dummy pdb
;BD007        shr     bx,4
;BD007        mov     ax,cs
;BD007        add     bx,ax
        MOV     ES,BX                           ; seg of dummy pdb

;BD007        mov     es:[PDB_Parent_PID],bx          ; set parent to itself
;BD007        mov     word ptr es:[PDB_JFN_Pointer+2],bx       ; set dummy JFT
;BD007        mov     es:[PDB_JFN_Pointer],PDB_JFN_Table
;BD007        mov     es:[PDB_JFN_Length],1

        SVC     SVC_DEMSETCURRENTPDB            ; give os2 dummy pdb

        mov     ah,0eh                          ;BN004 select disk func number
        mov     dl,cs:[CURDRV]
        call    $SET_DEFAULT_DRIVE              ; tell os2 the current drive

        mov     ah,34h                          ;BN006 get address of indos flag
        int     21h                             ;BN006
;BD008        inc     bx                              ;BN006
        mov     word ptr cs:[REAL_INDOS],bx     ;BN006
        mov     word ptr cs:[REAL_INDOS+2],es   ;BN006

        ret

EndProc v86init_Initialize


V86LAST ENDS

        END
