        page    ,132
        title   MISC - Miscellanious routines for MS-DOS

;
; Miscellaneous system calls most of which are CAVEAT
;
;   $SLEAZEFUNC
;   $SLEAZEFUNCDL
;   $GET_INDOS_FLAG
;   $GET_IN_VARS
;   $GET_DEFAULT_DPB
;   $GET_DPB
;   $DISK_RESET
;   $SETDPB
;   $Dup_PDB
;   $CREATE_PROCESS_DATA_BLOCK
;   SETMEM
;   FETCHI_CHECK
;
;   Revisions:
;
;Local  DCR/
;Tag    PTM(R)  Who     When
;               ARR     30 March 1983
;
;A000                   Jan. 1988
;                   version 4.00
;
;A001   D490
;                   Change IOCTL subfunctions from 63h, 43h to 66h , 46h
;
;               danno   07-Jan-1989
;                   Modified for MVDM
;
;***********************************************************************;BN001;
; BN001 - 27Feb91 G.L.Fulk                                              ;BN001;
; Change the code to support either the DOS 3.x or DOS 4+5 DPB          ;BN001;
; structure, based on DOS version number.  The default should be DOS 5  ;BN001;
; compatible.                                                           ;BN001;
;***********************************************************************;BN001;
;  B002    CP20 PTR B719135 - 6/3/91  Mark Rogalski                     ;BN002;
;               Alter GET_IN_VARS function to return address one para-  ;BN002;
;               graph higher than normal, and copy in_vars struct from  ;BN002;
;               high mem if neccessary.                                 ;BN002;
;***********************************************************************;BN002;
; BN003 - 07Oct91 G.L.Fulk                                              ;BN003;
; Add an additional int 13h call to int 21h, ah=1Fh and ah=32h.  This   ;BN003;
; is because of a very poorly program called PeachTree.  This silly     ;BN003;
; work around should get it working.                                    ;BN003;
;***********************************************************************;BN003;
; BN004 - 27Jan92 G.L.Fulk                                              ;BN004;
; SysInitVar is moved into HMA if DOS=HIGH.                             ;BN004;
;***********************************************************************;BN004;
; 12Feb92 - G.L.Fulk                                                    ;BN005;
; Adjust for the new default PDB in low memory.                         ;BN005;
;***********************************************************************;BN005;
; 22Feb92 - G.L.Fulk                                                    ;BN006;
; Use the current PDB to save the DOS fake version.                     ;BN006;
;***********************************************************************;BN006;
; 28Feb92 - G.L.Fulk                                                    ;BN007;
; Add "FSTCW [bx]" to NPX fake list.                                    ;BN007;
;***********************************************************************;BN007;
; 04Mar92 - G.L.Fulk                                                    ;BN008;
; Add "FSTCW ss:[xxxx]" to NPX fake list.                               ;BN008;
;***********************************************************************;BN008;
; 04Mar92 - G.L.Fulk                                                    ;BN009;
; Return the DPB.device_driver pointing to BLKDEV.                      ;BN009;
;***********************************************************************;BN009;
; 14Mar92 - J.D.Muir
; Removed math coprocessor support.  Now done by VNPX.
;**********************************************************************
; 25Mar92 - G.L.Fulk                                                    ;BN011;
; Fixed int 21h, fns 1Fh and 32h to correctly preserve AH and CX.       ;BN011;
;********************************************************************** ;BN011;
; 15Jun92 - G.L.Fulk                                                    ;BN012;
; Preserve AX register during function 52h call.                        ;BN012;
;********************************************************************** ;BN012;
; 29Oct92 - G.L.Fulk                                                    ;56287;
; The version checking for Get_DPB should be 10.0 and 20.0 not 10h.0    ;56287;
; and 20h.0.                                                            ;56287;
;********************************************************************** ;56287;
; 11Jan93 - G.L.Fulk                                                    ;59983;
; CurrentPDB can be corrupted if a timer tick occurs between the real   ;59983;
; and protect mode alterations of the variable.  The CLI will prevent   ;59983;
; timer ticks from this corruption.                                     ;59983;
;********************************************************************** ;59983;
; 20Jan93 - L.M.Primm                                                   ;60492;
; Int21h Func53h previously not implemented for OS/2, but Win31 Fileman ;60492;
; uses this function during FormatFloppy.  The implementation is simply ;60492;
; a port of the DOS code for that function.                             ;60492;
;********************************************************************** ;60492;
; 15Apr93 - Fulkgl                                                      ;65622;
; Fix the Peachtree problem for B: as well as A:.                       ;65622;
;********************************************************************** ;65622;

.xlist
;
; get the appropriate segment definitions
;
include v86seg.inc

.xcref
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include dossymc.inc
include devsym.inc
include error.inc
include pdb.inc
include dpb.inc
include bpb.inc                                                         ;60492;
include sft.inc
include vector.inc
include mi.inc
include mvdmexp.inc
include demsvc.inc
include dos3dev.inc
include struc30.inc                                                     ;BN003;
include dosver.inc                                                      ;BN006;
.cref
.list

        CpuMode 386

ENTRYPOINTSEG   EQU     0CH
MAXDIF          EQU     0FFFH
SAVEXIT         EQU     10

        i_need  INDOS,BYTE
        i_need  SYSINITVAR,BYTE
        i_need  CurrentPDB,WORD
        i_need  CreatePDB,BYTE
        i_need  THISSFT,DWORD
        i_need  FETCHI_TAG,WORD                  ; for TAG CHECK
        i_need  DOS34_FLAG,WORD                  ;AN000;
        i_need  FATBYTE,WORD
        i_need  internal_val_seg,WORD            ;BN002;

        ReferV86    RMDevHandleInfo,rmdi
        ReferV86    CURDRV,BYTE                                         ;BN003;



V86CODE    SEGMENT
        ASSUME  CS:V86GROUP

        EXTRN   Get_User_Stack:NEAR
        EXTRN   pJFNFromHandle:NEAR
        EXTRN   $IoCtl:NEAR
        EXTRN   ECritDisk:NEAR
        EXTRN   LCritDisk:NEAR
        EXTRN   SFFromSFN:NEAR
        EXTRN   RMDevOpen:NEAR
        EXTRN   Sys_Return:NEAR
        EXTRN   Sys_Ret_OK:NEAR
        EXTRN   Sys_Ret_Err:NEAR
        EXTRN   FCB_RET_ERR:NEAR
;56287; EXTRN   $GET_VERSION:NEAR                                       ;BN001;
        EXTRN   END_INTERNAL_VAL:NEAR                                   ;BN002;


subttl  SleazeFunc -- get a pointer to media byte
page

;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;                                                                          ;
; Inputs:
;       None
; Function:
;       Return Stuff sort of like old get fat call
; Outputs:
;       DS:BX = Points to FAT ID byte (IBM only)
;               GOD help anyone who tries to do ANYTHING except
;               READ this ONE byte.
;       DX = Total Number of allocation units on disk
;       CX = Sector size
;       AL = Sectors per allocation unit
;          = -1 if bad drive specified

procedure   $SLEAZEFUNC,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

        XOR     DL,DL

entry   $SLEAZEFUNCDL           ; Same as above except that drive is
                                ; passed in DL (0=default, 1=A, 2=B, ...)
        push    ss
        pop     ds
        assume  ds:V86GROUP
        SVC     SVC_DEMGETDRIVEFREESPACE
        .if     nc
          MOV     BYTE PTR [FATBYTE],AL ; FAT ID BYTE
          MOV     AX,SI                 ; (AL) = Sectors per allocation unit
          ; NOTE THAT A FIXED MEMORY CELL IS USED --> THIS CALL IS NOT
          ; RE-ENTRANT. USERS BETTER GET THE ID BYTE BEFORE THEY MAKE THE
          ; CALL AGAIN
          mov     di,OFFSET V86GROUP:FATBYTE
          call    get_user_stack
          ASSUME  DS:NOTHING
          MOV     [SI.user_DX],DX       ; Number of clusters on drive
          MOV     [SI.user_CX],CX       ; Bytes/sector
          MOV     [SI.user_BX],DI       ; Offset of FAT ID BYTE
          MOV     [SI.user_DS],CS       ; Segment of FAT ID BYTE ; stash correct pointer
          ret
        .endif
        mov     ax,error_invalid_drive  ; Assume error
        jmp     FCB_RET_ERR

EndProc $SLEAZEFUNC
;                                                                          ;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;


subttl  $GSetMediaID
page
;
;***    $GSetMediaID - Int 21 Get/Set Media ID                  @3xb12
;
;INT 21h (AH=69h) $GSetMediaID          v86code\misc.asm           #1/3
;INT 21h (AH=69h) [SVC]demGSetMediaID   mvdm\dempath2.asm          #2/3
;INT 21h (AH=69h) GSetMediaID           filesys\fsinfo.asm         #3/3
;
;       This routine allows the caller to query or modify the
;       media ID information.
;
;       ENTRY      AL = 00h - Get Media ID
;                       01h - Set Media ID
;                  BH = Reserved (must be 00h)
;                       or infolevel if nonzero
;                  BL = Drive Number (0=Default,1=A,2=B, ...)
;                  CX = Buffer size (only if BH<>0)
;                  DS:DX -> Buffer
;
;       EXIT       'C' clear if no error
;                  'C' set if error,  AX has error code
;
;       USES       AX,CX,DX,DS,ES,SI,DI
;
;       CALLS      GSetMediaID

        ASSUME  DS:NOTHING, ES:NOTHING
Procedure $GSetMediaID
        SVC     SVC_DEMGSETMEDIAID
        jmp     Sys_Return
EndProc   $GsetMediaID



subttl  $Get_INDOS_Flag -- Return location of DOS critical-section flag
page
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;                                                                          ;
; Inputs:
;       None
; Function:
;       Returns location of DOS status for interrupt routines
; Returns:
;       Flag location in ES:BX

procedure   $GET_INDOS_FLAG,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

        call    get_user_stack
        MOV     [SI.user_BX],OFFSET V86GROUP:INDOS
        MOV     [SI.user_ES],SS
        ret
EndProc $GET_INDOS_FLAG
;                                                                          ;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;

BREAK <$Get_IN_VARS -- Return a pointer to DOS variables>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;                                                                          ;
; Return a pointer to interesting DOS variables This call is version
; dependent and is subject to change without notice in future versions.
; Use at risk.
;
; NOTE NOTE!!!!   Modified to return a segment:offset one paragraph higher
; \               than the real DOS segment. This is because DEM has a 16
;  \              byte header so that it can be moved up to high mem with
;   \             out having to alter data offsets. Therefore it's segment
;    >            appears to be one paragraph lower than it should. Nasty
;   /             MicroSoft apps look at specific offsets from the DOS
;  /              segment which they obtain through this function. So
; /               this is an attempt to fake them out. MDR  6/3/91
;

procedure   $GET_IN_VARS,NEAR
        push    ax
        call    get_user_stack
        mov     ax,offset V86GROUP:SYSINITVAR
        mov     [SI].user_BX,ax         ; internal_val_seg is one
        mov     ax,[internal_val_seg]   ; higher than real DOS segment
        mov     [SI].user_ES,ax
        mov     es,ax                   ; save seg for use later
        mov     ax,cs
        .if     <AX eq 0FFFFh>
          mov     ds,ax                 ; setup regs for mem copy
          mov     si,10h
          mov     di,si
          mov     cx,offset V86GROUP:END_INTERNAL_VAL
          sub     cx,si                 ; copy from 10h to struct end
          rep     movsb                 ; copy struct from high to low
        .endif
        pop     ax
        ret
EndProc $GET_IN_VARS
;                                                                          ;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;


subttl  $GET_DEFAULT_DPB - Get default DPB
page

;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;                                                                          ;
;***    $Get_Default_DPB - Return pointer to DPB for default drive
;
;       Fill in a static buffer with disk information in the form of
;       a DOS 3.2 DPB.
;
;       ENTRY:  none
;
;       EXIT:   (AL) =  0, success
;                   (DS:BX) = ptr to static DPB buffer
;               (AL) = -1, bad drive (call 32h only)

V86DATA SEGMENT
public Fake4xDPB                                                        ;56287;
Fake4xDPB   dpb4x     <>                                                ;BN001;
V86DATA ENDS

procedure   $GET_DEFAULT_DPB,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

        XOR     DL,DL

entry   $GET_DPB                        ; Same as above only drive passed
                                        ; in DL (0=default, 1=A, 2=B, ...)


                                                                        ;BN003;
;------ save registers used by int 13h hack                             ;BN003;
        push    ax                                                      ;BN003;
        push    dx                                                      ;BN003;
                                                                        ;BN003;
;------ get the default drive (if necessary)                            ;BN003;
        .if     <ZERO DL>               ;DL 0=default 1=A: 2=B: 3=C:    ;BN003;
          mov     DL,[CurDrv]           ;DL           0=A: 1=B: 2=C:    ;BN003;
          inc     DL                    ;DL           1=A: 2=B: 3=C:    ;BN003;
        .endif                                                          ;BN003;
                                                                        ;BN003;
;------ if int 21/ah=1F or ah=32 for drive A: only, do the int 13h hack ;BN003;
        .if     <DL eq 2> or                                            ;65622;
        .if     <DL eq 1>                                               ;BN003;
          mov     ah,0                                                  ;BN003;
          mov     dl,0                                                  ;BN003;
          int     13h                                                   ;BN003;
        .endif                                                          ;BN003;
                                                                        ;BN003;
;------ restore registers used by int 13h patch, AL=0 means success     ;BN003;
        pop     dx                                                      ;BN003;



        ; Fake DPB filled by worker                                     ;BN001;
        MOV     DI, OFFSET V86GROUP:FAKE4XDPB                           ;BN001;
        PUSH    CS
        POP     ES                      ; ES:DI fake DPB
        XOR     DH,DH
        SVC     SVC_DEMGETDPB
        .if     <AL eq -1>                                              ;BN011;
          pop     ax                                                    ;BN011;
          mov     al,-1                 ;AL=-1 means Error              ;BN011;
          ret                                                           ;BN011;
        .endif                                                          ;BN011;

;-------                                                                ;BN001;
        push    bx                                                      ;BN001;
;56287; push    cx                                                      ;BN001;
        push    ds                                                      ;56287;
        mov     ds,[CurrentPDB]                                         ;56287;
        mov     ax,ds:[PDB_Version]                                     ;56287;
        pop     ds                                                      ;56287;
;56287; call    $GET_VERSION                                            ;BN001;
;*Warning* $GET_VERSION changes the user_stack AX, BX, and CX values.   ;BN011;
        xchg    ah,al                                                   ;BN001;
        mov     bx,offset V86GROUP:FAKE4XDPB  ; Offset of fake DPB      ;BN001;

        EXTRN   BLKDEV:word                                             ;BN009;
        mov     word ptr cs:[bx].dpb4x_driver_addr,offset V86GROUP:BLKDEV;BN009;
        mov     word ptr cs:[bx].dpb4x_driver_addr+2,cs                 ;BN009;

        cmp     ax,0400h                                                ;BN001;
        jb      short glf_x3                                            ;BN001;
        .if     <AX ae 0A00h> and                                       ;56287;
        .if     <AX b  1400h>                                           ;56287;
glf_x3:                                                                 ;BN001;
          mov     ax,cs:[bx].dpb4x_dir_sector                           ;BN001;
          mov     cs:[bx].dpb3x_dir_sector,ax                           ;BN001;
                                                                        ;BN001;
          mov     ax,word ptr cs:[bx].dpb4x_driver_addr                 ;BN001;
          mov     word ptr cs:[bx].dpb3x_driver_addr,ax                 ;BN001;
          mov     ax,word ptr cs:[bx].dpb4x_driver_addr+2               ;BN001;
          mov     word ptr cs:[bx].dpb3x_driver_addr+2,ax               ;BN001;
                                                                        ;BN001;
          mov     al,cs:[bx].dpb4x_media                                ;BN001;
          mov     cs:[bx].dpb3x_media,al                                ;BN001;
                                                                        ;BN001;
          mov     al,cs:[bx].dpb4x_first_access                         ;BN001;
          mov     cs:[bx].dpb3x_first_access,al                         ;BN001;
                                                                        ;BN001;
          mov     ax,word ptr cs:[bx].dpb4x_next_dpb                    ;BN001;
          mov     word ptr cs:[bx].dpb3x_next_dpb,ax                    ;BN001;
          mov     ax,word ptr cs:[bx].dpb4x_next_dpb+2                  ;BN001;
          mov     word ptr cs:[bx].dpb3x_next_dpb+2,ax                  ;BN001;
                                                                        ;BN001;
          mov     ax,cs:[bx].dpb4x_next_free                            ;BN001;
          mov     cs:[bx].dpb3x_next_free,ax                            ;BN001;
                                                                        ;BN001;
          mov     ax,cs:[bx].dpb4x_free_cnt                             ;BN001;
          mov     cs:[bx].dpb3x_free_cnt,ax                             ;BN001;
        .endif                                                          ;BN011;
;56287; pop     cx                                                      ;BN001;
        pop     bx                                                      ;BN001;
;-------                                                                ;BN001;
                                                                        ;BN001;
        call    get_user_stack
        pop     ax                                                      ;BN011;
        xor     al,al                                                   ;BN011;
        mov     [SI.user_BX],offset V86GROUP:FAKE4XDPB  ; Offset &      ;BN001;
        mov     [SI.user_DS],cs                         ; Segment of fake DPB
;56287; mov     [SI.user_CX],cx         ;repair because of $GET_VERSION ;BN011;
        mov     [SI.user_AX],ax         ;repair because of $GET_VERSION ;BN011;
        ret                                                             ;BC003;
EndProc $GET_DEFAULT_DPB


;                                                                          ;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;


BREAK <$SetDPB - Create a valid DPB from a user-specified BPB>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;                                                                          ;

;60492 Add whole 53h function from ported DOS code  -  L.M.Primm
;
;**     $SetDPB - Create a DPB
;
;       SetDPB Creates a valid DPB from a user-specified BPB
;
;       Added this to support Win31 Fileman; data set up in the DOS     ;60492;
;       drive parameter block based on info in the user-specified BPB   ;60492;
;       DOS code modified to run in VDM for OS/2                        ;60492;
;
;       ENTRY   ES:BP Points to DPB
;               DS:SI Points to BPB
;       EXIT    DPB setup
;       USES    ALL but BP, DS, ES
;
;----------------------------------------------------------------------------
;
word3   dw      3               ; M008 -- word value for divides

procedure   $SETDPB,NEAR

        MOV     DI,BP
        ADD     DI,2                    ; Skip over dpb_drive and dpb_UNIT
        LODSW
        STOSW                           ; dpb_sector_size
        CMP     BYTE PTR [SI.BPB_NumberOfFATs-2],0     ; FAT file system drive          ;AN000;
        JNZ     short yesfat                        ; yes                             ;AN000;
        MOV     BYTE PTR ES:[DI.dpb4x_FAT_count-4],0
        JMP     short setend                          ; NO                              ;AN000;
yesfat:
        MOV     DX,AX
        LODSB
        DEC     AL
        STOSB                           ; dpb4x_cluster_mask
        INC     AL
        XOR     AH,AH
LOG2LOOP:
        test    AL,1
        JNZ     short SAVLOG
        INC     AH
        SHR     AL,1
        JMP     SHORT LOG2LOOP
SAVLOG:
        MOV     AL,AH
        STOSB                           ; dpb4x_cluster_shift
        MOV     BL,AL
        MOVSW                           ; dpb4x_first_FAT Start of FAT (# of reserved sectors)
        LODSB
        STOSB                           ; dpb4x_FAT_count Number of FATs
;       OR      AL,AL                   ; NONFAT ?                              ;AN000;
;       JZ      setend                  ; yes, don't do anything                ;AN000;
        MOV     BH,AL
        LODSW
        STOSW                           ; dpb4x_root_entries Number of directory entries
        MOV     CL,5
        SHR     DX,CL                   ; Directory entries per sector
        DEC     AX
        ADD     AX,DX                   ; Cause Round Up
        MOV     CX,DX
        XOR     DX,DX
        DIV     CX
        MOV     CX,AX                   ; Number of directory sectors
        INC     DI
        INC     DI                      ; Skip dpb4x_first_sector
        MOVSW                           ; Total number of sectors in DSKSIZ (temp as dpb4x_max_cluster)
        LODSB
        MOV     ES:[BP.dpb4x_media],AL    ; Media byte
        LODSW                           ; Number of sectors in a FAT
        STOSW                           ;AC000;;>32mb dpb4x_FAT_size
        MOV     DL,BH                   ;AN000;;>32mb
        XOR     DH,DH                   ;AN000;;>32mb
        MUL     DX                      ;AC000;;>32mb Space occupied by all FATs
        ADD     AX,ES:[BP.dpb4x_first_FAT]
        STOSW                           ; dpb4x_dir_sector
        ADD     AX,CX                   ; Add number of directory sectors
        MOV     ES:[BP.dpb4x_first_sector],AX

        MOV     CL,BL                  ;F.C. >32mb                              ;AN000;
        CMP     WORD PTR ES:[BP.DSKSIZ],0       ;F.C. >32mb                     ;AN000;
        JNZ     short normal_dpb       ;F.C. >32mb                              ;AN000;
        XOR     CH,CH                  ;F.C. >32mb                              ;AN000;
        MOV     BX,WORD PTR [SI+BPB_BigTotalSectors-BPB_SectorsPerTrack]        ;AN000;
        MOV     DX,WORD PTR [SI+BPB_BigTotalSectors-BPB_SectorsPerTrack+2]      ;AN000;
        SUB     BX,AX                  ;AN000;;F.C. >32mb
        SBB     DX,0                   ;AN000;;F.C. >32mb
        OR      CX,CX                  ;AN000;;F.C. >32mb
        JZ      short norot            ;AN000;;F.C. >32mb
rott:                                  ;AN000;;F.C. >32mb
        CLC                            ;AN000;;F.C. >32mb
        RCR     DX,1                   ;AN000;;F.C. >32mb
        RCR     BX,1                   ;AN000;;F.C. >32mb
        LOOP    rott                   ;AN000;;F.C. >32mb
norot:                                 ;AN000;
        MOV     AX,BX                  ;AN000;;F.C. >32mb
        JMP     short setend           ;AN000;;F.C. >32mb
normal_dpb:
        SUB     AX,ES:[BP.DSKSIZ]
        NEG     AX                      ; Sectors in data area
;;      MOV     CL,BL                   ; dpb4x_cluster_shift
        SHR     AX,CL                   ; Div by sectors/cluster
setend:

;       M008 - CAS
;
        INC     AX                      ; +2 (reserved), -1 (count -> max)
;
;       There has been a bug in our fatsize calculation for so long
;         that we can't correct it now without causing some user to
;         experience data loss.  There are even cases where allowing
;         the number of clusters to exceed the fats is the optimal
;         case -- where adding 2 more fat sectors would make the
;         data field smaller so that there's nothing to use the extra
;         fat sectors for.
;
;       Note that this bug had very minor known symptoms.  CHKDSK would
;         still report that there was a cluster left when the disk was
;         actually full.  Very graceful failure for a corrupt system
;         configuration.  There may be worse cases that were never
;         properly traced back to this bug.  The problem cases only
;         occurred when partition sizes were very near FAT sector
;         rounding boundaries, which were rare cases.
;
;       Also, it's possible that some third-party partition program might
;         create a partition that had a less-than-perfect FAT calculation
;         scheme.  In this hypothetical case, the number of allocation
;         clusters which don't actually have FAT entries to represent
;         them might be larger and might create a more catastrophic
;         failure.  So we'll provide the safeguard of limiting the
;         max_cluster to the amount that will fit in the FATs.
;
;       ax = maximum legal cluster, ES:BP -> dpb

;       make sure the number of fat sectors is actually enough to
;         hold that many clusters.  otherwise, back the number of
;         clusters down

        mov     bx,ax                   ; remember calculated # clusters
        mov     ax,ES:[BP.dpb4x_fat_size]
        mul     ES:[BP.dpb4x_sector_size] ; how big is the FAT?
        cmp     bx,4096-10              ; test for 12 vs. 16 bit fat
        jb      short setend_fat12
        shr     dx,1
;cs3 7/2/92
        jnz     short setend_faterr     ; some bonehead gave us more fatspace
;                                       ; than enough for the maximum FAT,
;                                       ; so go ahead and use the calculated
;                                       ; number of clusters.
;cs3 7/2/92

        rcr     ax,1                    ; find number of entries
        cmp     ax,4096-10+1            ; would this truncation move us
;                                       ;  into 12-bit fatland?
        jb      short setend_faterr     ; then go ahead and let the
;                                       ;  inconsistency pass through
;                                       ;  rather than lose data by
;                                       ;  correcting the fat type
        jmp     short setend_fat16

setend_fat12:
        add     ax,ax                   ; (fatsiz*2)/3 = # of fat entries
        adc     dx,dx
;cs3 7/2/92
        cmp     dx,3                    ; if our fatspace is WAY more than
        jnb     short setend_faterr     ; we need, we may get an overflow
;                                       ; here.  Check for it and use
;                                       ; the calcuated size in this case.
;cs3 7/2/92
        div     cs:word ptr word3

setend_fat16:
        dec     ax                      ; limit at 1
        cmp     ax,bx                   ; is fat big enough?
        jbe     short setend_fat        ; use max value that'll fit

setend_faterr:
        mov     ax,bx                   ; use calculated value

setend_fat:

;       now ax = maximum legal cluster

;       end M008

        MOV     ES:[BP.dpb4x_max_cluster],AX
        MOV     ES:[BP.dpb4x_next_free],0 ; Init so first ALLOC starts at
                                        ; begining of FAT
        MOV     ES:[BP.dpb4x_free_cnt],-1 ; current count is invalid.
        return
EndProc $SETDPB
;60492 end of whole function.... added for defect 60492 L.M.Primm
;                                                                          ;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;


BREAK <$Disk_Reset -- Flush out all dirty buffers>

procedure   $DISK_RESET,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       None
; Function:
;       Flush and invalidate all buffers
; Returns:
;       Nothing

        MOV     AL,-1
entry   $DISK_RESET2             ; who calls this entry point?
        EnterCrit   critDisk
        SVC     SVC_DEMDISKRESET            ; Let OS2 do everything
        LeaveCrit   critDisk
        ret

EndProc $DISK_RESET




BREAK <$Create_Process_Data_Block,SetMem -- Set up process data block>
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;                                                                          ;
;
; Inputs:   DX is new segment address of process
;           SI is end of new allocation block
;
procedure   $Dup_PDB,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING
        mov     byte ptr [CreatePDB],-1
        mov     ds,CurrentPDB
        push    si
        JMP     SHORT   CreateCopy
EndProc $Dup_PDB

procedure   $CREATE_PROCESS_DATA_BLOCK,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

; Inputs:
;       DX = Segment number of new base
; Function:
;       Set up program base and copy term and ^C from int area
; Returns:
;       None
; Called at DOS init

        mov     byte ptr [CreatePDB],0
        call    get_user_stack
        mov     ds,[SI.user_CS]
        push    ds:[PDB_Block_len]

CreateCopy:

;------ copy the 1st 80h bytes from the old PDB to the new PDB
        mov     es,dx
        xor     si,si
        mov     di,si
        mov     cx,80h/4
        rep     movs dword ptr [si],dword ptr [di]

;------ in case the JFT has moved out of the PDB, copy the 1st 20 handles
        mov     cx,FilPerProc
        mov     di,PDB_JFN_Table
        push    ds
        LDS     SI,ds:[PDB_JFN_Pointer]
        rep     movsb
        pop     ds

;------ This is function 55h, create a PDB (process data block)
        .if     <CreatePDB ne 0>        ; Shall we create a process?

          lea     di,RMDevHandleInfo
          ;entry: ES=new PDB segment value
          ;       CS:DI=&RMDevHandleInfo
          SVC     SVC_DEMDUPJFT         ; Dup the OS/2 handles

          mov     cx,FILPERPROC         ; Dup only the first 20 handles
          mov     di,PDB_JFN_Table
          LDS     SI,ds:[PDB_JFN_POINTER]

          .repeat
            lodsb                       ; Get the next VSFN
            .if     <AL ae VSFN_DEV>    ;{JC}
              xor     bh,bh
              mov     bl,al
              SaveReg     <ax,cx,ds,si,es,di>
              call    SFFromSFN
              .if     <<es:[di].rmdi_DevPtr.Offst> eq -1> or   ; OS/2 device ?
              .if     <BIT <es:[di].rmdi_flags> and RMDI_NO_INHERIT>
                stc
              .else
                call    RMDevOpen         ; send open packet to the device
              .endif
              RestoreReg  <di,es,si,ds,cx,ax>
            .endif

            .if     nc                  ; Skip if open error
              stosb                     ; Store inherited VSFN
            .else
              inc     di
            .endif

          .loop

          mov     bx,[CurrentPDB]         ; get current process
          mov     es:[PDB_Parent_PID],bx  ; stash in child
          pushf                                                         ;59983;
          cli                                                           ;59983;
          mov     [CurrentPDB],es                                       ;59983;
          SVC     SVC_DEMSETCURRENTPDB                                  ;59983;
          popf                                                          ;59983;
          mov     ds,bx
          assume  ds:nothing
        .endif

;------ get the segment size value
        pop     ax

entry   SETMEM
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

; Inputs:
;       AX = Size of memory in paragraphs
;       DX = Segment
; Function:
;       Completely prepares a program base at the
;       specified segment.
; Called at DOS init
; Outputs:
;       DS = DX
;       ES = DX
;       [0] has INT int_abort
;       [2] First unavailable segment
;       [4] DOS fake version count
;       [5] to [9] form a long call to the entry point
;       [10] to [13] have exit address (from int_terminate)
;       [14] to [17] have ctrl-C exit address (from int_ctrl_c)
;       [18] to [21] have fatal error address (from int_fatal_abort)
;       [32h] size of JFT
;       [34h] addr of JFT
;       [38h] -1 next pdb
;       [40h] DOS version
;       [50h] old system call
; DX,BP unchanged. All other registers destroyed.

        XOR     CX,CX
        MOV     DS,CX                           ; DS = INT Vectors
        MOV     ES,DX                           ; ES = PDB
        MOV     SI,addr_int_terminate
        MOV     DI,SAVEXIT
        MOV     CX,6
        REP     MOVSW                           ; Copy some vectors
        MOV     ES:[2],AX
        SUB     AX,DX
        .if     <AX a MAXDIF>
          mov     ax,MAXDIF
        .endif
        SUB     AX,10H                  ; Allow for 100h byte "stack"
        MOV     BX,ENTRYPOINTSEG        ;       in .COM files
        SUB     BX,AX
        MOV     CL,4
        SHL     AX,CL
        MOV     ds,dx                           ; DS = PDB
        MOV     WORD PTR ds:[PDB_CPM_Call+1],AX
        MOV     WORD PTR ds:[PDB_CPM_Call+3],BX
        MOV     BYTE PTR ds:[PDB_CPM_Call],mi_Long_CALL
        MOV     ds:[PDB_Exit_Call],(int_abort SHL 8) + mi_INT
        MOV     WORD PTR ds:[PDB_Call_System],(int_command SHL 8) + mi_INT
        MOV     BYTE PTR ds:[PDB_Call_System+2],mi_Long_RET
        MOV     WORD PTR ds:[PDB_JFN_Pointer],PDB_JFN_Table
        MOV     WORD PTR ds:[PDB_JFN_Pointer+2],DS
        MOV     WORD PTR ds:[PDB_JFN_Length],FilPerProc
;
; The server runs several PDB's without creating them VIA EXEC.  We need to
; enumerate all PDB's at CPS time in order to find all references to a
; particular SFT.  We perform this by requiring that the server link together
; for us all sub-PDB's that he creates.  The requirement for us, now, is to
; initialize this pointer.
;
        mov     word ptr ds:[PDB_Next_PDB],-1
        mov     word ptr ds:[PDB_Next_PDB+2],-1

        mov     ds:[PDB_Version_count],0                                ;BN006;
        mov     ax,DOS_VERSION                                          ;BN006;
        xchg    al,ah                                                   ;BN006;
        mov     ds:[PDB_Version],ax                                     ;BN006;

        ret

EndProc $CREATE_PROCESS_DATA_BLOCK,NoCheck
;                                                                          ;
;            C  A  V  E  A  T     P  R  O  G  R  A  M  M  E  R             ;
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;

;Procedure FETCHI_CHECK,NEAR
;        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING
;        pushf
;        .if     <<cs:[FETCHI_TAG]> ne 22642>
;          invoke  DOSINIT                 ; go to hell
;        .endif
;        popf
;        ret
;EndProc   FETCHI_CHECK


;----------------------------------------------------------------------
PUBLIC  DemMisc_BAD_COMMAND_COM
PUBLIC  DemMisc_V86IE_BLOCK_DD
PUBLIC  TXT_MSG_STAND_BY
PUBLIC  TXT_MSG_RESPONSE_DATA
DemMisc_BAD_COMMAND_COM dw      offset V86GROUP:TXT_MSG_BAD_COMMAND_COM
DemMisc_V86IE_BLOCK_DD  dw      offset V86GROUP:TXT_MSG_V86IE_BLOCK_DD

include misc.inc        ;<--- V86GROUP messages
;----------------------------------------------------------------------

V86CODE ENDS

        END
