; SCCSID = @(#)mscode.asm 1.2 85/07/23 ; ; MSCODE.ASM -- MSDOS code ; .xlist .xcref include dossym.inc include devsym.inc include dosseg.asm include ifssym.inc include fastopen.inc include fastxxxx.inc .cref .list AsmVars CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING I_need InDos,BYTE ; TRUE => we are in dos, no interrupt I_need OpenBuf,128 ; temp name buffer I_need ExtErr,WORD ; extended error code I_need User_SS,WORD ; stack segment from user I_need User_SP,WORD ; stack pointer from user I_need DskStack,BYTE ; stack segment inside DOS I_need ThisCDS,DWORD ; Currently referenced CDS pointer I_need ThisDPB,DWORD ; Currently referenced DPB pointer I_need Err_Table_21 ; allowed return map table for errors I_need FailErr,BYTE ; TRUE => system call is being failed I_need ExtErr_Action,BYTE ; recommended action I_need ExtErr_Class,BYTE ; error classification I_need ExtErr_Locus,BYTE ; error location I_need I21_Map_E_Tab,BYTE ; mapping extended error table I_need User_In_AX,WORD ; initial input user AX I_need FOO,WORD ; return address for dos 2f dispatch I_need DTAB,WORD ; dos 2f dispatch table I_need HIGH_SECTOR,WORD ; >32mb I_need IFS_DRIVER_ERR,WORD ; >32mb I_need FastOpenFlg,BYTE ; I_need FastSeekFlg,BYTE ; I_need CURSC_DRIVE,BYTE ; BREAK procedure SNULDEV,FAR ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING OR ES:[BX.REQSTAT],STDON ; Set done bit entry INULDEV RET ; MUST NOT BE A RETURN! EndProc SNULDEV BREAK TABLE SEGMENT Public MSC001S,MSC001E MSC001S label byte IF IBM ; Codes returned by BIOS ERRIN: DB 2 ; NO RESPONSE DB 6 ; SEEK FAILURE DB 12 ; GENERAL ERROR DB 4 ; BAD CRC DB 8 ; SECTOR NOT FOUND DB 0 ; WRITE ATTEMPT ON WRITE-PROTECT DISK ERROUT: ; DISK ERRORS RETURNED FROM INT 25 and 26 DB 80H ; NO RESPONSE DB 40H ; Seek failure DB 2 ; Address Mark not found DB 10H ; BAD CRC DB 4 ; SECTOR NOT FOUND DB 3 ; WRITE ATTEMPT TO WRITE-PROTECT DISK NUMERR EQU $-ERROUT ENDIF MSC001E label byte TABLE ENDS ; AbsSetup - setup for abs disk functions Procedure AbsSetup,NEAR ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:DOSGroup INC INDOS STI CLD PUSH DS Context DS CALL GETBP JC errdriv ;PM. error drive ;AN000; MOV ES:[BP.dpb_free_cnt],-1 ; do not trust user at all. errdriv: POP DS ASSUME DS:NOTHING retc MOV [HIGH_SECTOR],0 ;>32mb from API ;AN000; CALL RW32_CONVERT ;>32mb convert 32bit format to 16bit ;AN000; retc invoke SET_RQ_SC_PARMS ;LB. set up SC parms ;AN000; PUSH DS PUSH SI PUSH AX Context DS MOV SI,OFFSET DOSGROUP:OPENBUF MOV [SI],AL ADD BYTE PTR [SI],"A" MOV WORD PTR [SI+1],003AH ; ":",0 MOV AX,0300H CLC INT int_IBM ; Will set carry if shared POP AX POP SI POP DS ASSUME DS:NOTHING retnc MOV ExtErr,error_not_supported return EndProc AbsSetup ; Interrupt 25 handler. Performs absolute disk read. ; Inputs: AL - 0-based drive number ; DS:BX point to destination buffer ; CX number of logical sectors to read ; DX starting logical sector number (0-based) ; Outputs: Original flags still on stack ; Carry set ; AH error from BIOS ; AL same as low byte of DI from INT 24 procedure ABSDRD,FAR ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:NOTHING CLI MOV [user_SS],SS MOV [user_SP],SP PUSH CS POP SS ASSUME SS:DOSGROUP MOV SP,OFFSET DOSGROUP:DSKSTACK invoke Save_World ;>32mb save all regs ;AN000; PUSH ES CALL AbsSetup JC ILEAVE if not ibmcopyright ; Here is a gross temporary fix to get around a serious design flaw in ; the secondary cache. The secondary cache does not check for media ; changed (it should). Hence, you can change disks, do an absolute ; read, and get data from the previous disk. To get around this, ; we just won't use the secondary cache for absolute disk reads. ; -mw 8/5/88 EnterCrit critDisk MOV [CURSC_DRIVE],-1 ; invalidate SC ;AN000; LeaveCrit critDisk endif invoke DSKREAD TLEAVE: JZ ILEAVE IF IBM ; Translate the error code to ancient 1.1 codes PUSH ES PUSH CS POP ES XOR AH,AH ; Nul error code MOV CX,NUMERR ; Number of possible error conditions MOV DI,OFFSET DOSGROUP:ERRIN ; Point to error conditions REPNE SCASB JNZ LEAVECODE ; Not found MOV AH,ES:[DI+NUMERR-1] ; Get translation LEAVECODE: POP ES ENDIF MOV [IFS_DRIVER_ERR],AX ;>32mb save error STC ILEAVE: POP ES invoke Restore_World ;>32mb ;AN000; CLI DEC INDOS MOV SS,[user_SS] ASSUME SS:NOTHING MOV SP,[user_SP] MOV AX,[IFS_DRIVER_ERR] ;>32mb restore error ;AN000; STI RET ; This must not be a RETURN! EndProc ABSDRD ; Interrupt 26 handler. Performs absolute disk write. ; Inputs: AL - 0-based drive number ; DS:BX point to source buffer ; CX number of logical sectors to write ; DX starting logical sector number (0-based) ; Outputs: Original flags still on stack ; Carry set ; AH error from BIOS ; AL same as low byte of DI from INT 24 procedure ABSDWRT,FAR ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING CLI MOV [user_SS],SS MOV [user_SP],SP PUSH CS POP SS ASSUME SS:DOSGROUP MOV SP,OFFSET DOSGROUP:DSKSTACK invoke Save_World ;>32mb save all regs ;AN000; PUSH ES CALL AbsSetup JC ILEAVE EnterCrit critDisk MOV [CURSC_DRIVE],-1 ; invalidate SC ;AN000; CALL Fastxxx_Purge ; purge fatopen ;AN000; LeaveCrit critDisk invoke DSKWRITE JMP TLEAVE EndProc ABSDWRT ; Inputs: ; AL = Logical unit number (A = 0) ; Function: ; Find Drive Parameter Block ; Outputs: ; ES:BP points to DPB ; [THISDPB] = ES:BP ; Carry set if unit number bad or unit is a NET device. ; Later case sets extended error error_I24_not_supported ; No other registers altered Procedure GETBP,NEAR DOSAssume CS,,"GetBP" ASSUME ES:NOTHING PUSH AX ADD AL,1 ; No increment; need carry flag JC SkipGet invoke GetThisDrv JNC SkipGet ;PM. good drive ;AN000; XOR AH,AH ;DCR. ax= error code ;AN000; CMP AX,error_not_dos_disk ;DCR. is unknown media ? ;AN000; JZ SkipGet ;DCR. yes, let it go ;AN000; STC ;DCR. ;AN000; MOV ExtErr,AX ;PM. invalid drive or Non DOS drive ;AN000; MOV [IFS_DRIVER_ERR],0201H ;PM. other errors/unknown unit ;AN000; SkipGet: POP AX retc LES BP,[THISCDS] TEST ES:[BP.curdir_flags],curdir_isnet ; Clears carry JZ GETBP_CDS LES BP,ES:[BP.curdir_ifs_hdr] ;IFS. if remote file ;AN000; TEST ES:[BP.ifs_attribute],IFSREMOTE ;IFS. ;AN000; LES BP,[THISCDS] JZ GETBP_CDS ;IFS. then error ;AN000; MOV ExtErr,error_not_supported STC return GETBP_CDS: LES BP,ES:[BP.curdir_devptr] entry GOTDPB DOSAssume CS,,"GotDPB" ; Load THISDPB from ES:BP MOV WORD PTR [THISDPB],BP MOV WORD PTR [THISDPB+2],ES return EndProc GetBP BREAK ASSUME SS:DOSGROUP ; ; These are the general system call exit mechanisms. All internal system ; calls will transfer (jump) to one of these at the end. Their sole purpose ; is to set the user's flags and set his AX register for return. ; procedure SYS_RETURN,NEAR ASSUME DS:NOTHING,ES:NOTHING entry SYS_RET_OK invoke FETCHI_CHECK ; TAG checking for FETCHI invoke get_user_stack AND [SI.user_F],NOT f_Carry ; turn off user's carry flag JMP SHORT DO_RET ; carry is now clear entry SYS_RET_ERR XOR AH,AH ; hack to allow for smaller error rets invoke ETAB_LK ; Make sure code is OK, EXTERR gets set CALL ErrorMap entry From_GetSet invoke get_user_stack OR [SI.user_F],f_Carry ; signal carry to user STC ; also, signal internal error DO_RET: MOV [SI.user_AX],AX ; Really only sets AH return entry FCB_RET_OK entry CPMFunc XOR AL,AL return entry FCB_RET_ERR XOR AH,AH mov exterr,AX CALL ErrorMap MOV AL,-1 return entry errorMap PUSH SI MOV SI,OFFSET DOSGROUP:ERR_TABLE_21 CMP [FAILERR],0 ; Check for SPECIAL case. JZ EXTENDED_NORMAL ; All is OK. MOV [EXTERR],error_FAIL_I24 ; Ooops, this is the REAL reason MOV SI,OFFSET DOSGROUP:ERR_TABLE_21 EXTENDED_NORMAL: invoke CAL_LK ; Set CLASS,ACTION,LOCUS for EXTERR POP SI return EndProc SYS_RETURN ; Inputs: ; SI is OFFSET in DOSGROUP of CLASS,ACTION,LOCUS Table to use ; (DS NEED not be DOSGROUP) ; [EXTERR] is set with error ; Function: ; Look up and set CLASS ACTION and LOCUS values for GetExtendedError ; Outputs: ; [EXTERR_CLASS] set ; [EXTERR_ACTION] set ; [EXTERR_LOCUS] set (EXCEPT on certain errors as determined by table) ; Destroys SI, FLAGS procedure CAL_LK,NEAR ASSUME DS:NOTHING,ES:NOTHING PUSH DS PUSH AX PUSH BX Context DS ; DS:SI -> Table MOV BX,[EXTERR] ; Get error in BL TABLK1: LODSB CMP AL,0FFH JZ GOT_VALS ; End of table CMP AL,BL JZ GOT_VALS ; Got entry ADD SI,3 ; Next table entry JMP TABLK1 GOT_VALS: LODSW ; AL is CLASS, AH is ACTION CMP AH,0FFH JZ NO_SET_ACT MOV [EXTERR_ACTION],AH ; Set ACTION NO_SET_ACT: CMP AL,0FFH JZ NO_SET_CLS MOV [EXTERR_CLASS],AL ; Set CLASS NO_SET_CLS: LODSB ; Get LOCUS CMP AL,0FFH JZ NO_SET_LOC MOV [EXTERR_LOCUS],AL NO_SET_LOC: POP BX POP AX POP DS return EndProc CAL_LK ; Inputs: ; AX is error code ; [USER_IN_AX] has AH value of system call involved ; Function: ; Make sure error code is appropriate to this call. ; Outputs: ; AX MAY be mapped error code ; [EXTERR] = Input AX ; Destroys ONLY AX and FLAGS procedure ETAB_LK,NEAR ASSUME DS:NOTHING,ES:NOTHING PUSH DS PUSH SI PUSH CX PUSH BX Context DS MOV [EXTERR],AX ; Set EXTERR with "real" error MOV SI,OFFSET DOSGROUP:I21_MAP_E_TAB MOV BH,AL ; Real code to BH MOV BL,BYTE PTR [USER_IN_AX + 1] ; Sys call to BL TABLK2: LODSW CMP AL,0FFH ; End of table? JZ NOT_IN_TABLE ; Yes CMP AL,BL ; Found call? JZ GOT_CALL ; Yes XCHG AH,AL ; Count to AL XOR AH,AH ; Make word for add ADD SI,AX ; Next table entry JMP TABLK2 NOT_IN_TABLE: MOV AL,BH ; Restore original code JMP SHORT NO_MAP GOT_CALL: MOV CL,AH XOR CH,CH ; Count of valid err codes to CX CHECK_CODE: LODSB CMP AL,BH ; Code OK? JZ NO_MAP ; Yes LOOP CHECK_CODE NO_MAP: XOR AH,AH ; AX is now valid code POP BX POP CX POP SI POP DS return EndProc ETAB_LK BREAK IF installed ; ; SetBad sets up info for bad functions ; Procedure SetBad,NEAR ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING MOV AX,error_invalid_function ; ALL NET REQUESTS get inv func MOV ExtErr_LOCUS,errLoc_UNK STC ret EndProc SetBad ; ; BadCall is the initial routine for bad function calls ; procedure BadCall,FAR call SetBad ret EndProc BadCall ; ; OKCall always sets carry to off. ; Procedure OKCall,FAR ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING CLC ret EndProc OKCall ; INT 2F handler works as follows: ; PUSH AX ; MOV AX,multiplex:function ; INT 2F ; POP ... ; The handler itself needs to make the AX available for the various routines. PUBLIC Int2F INT2F PROC FAR INT2FNT: ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING STI CMP AH,multNET JNZ INT2FSHR TestInstall: OR AL,AL JZ Leave2F BadFunc: CALL SetBad entry Leave2F RET 2 ; long return + clear flags off stack INT2FSHR: CMP AH,multSHARE ; is this a share request JZ TestInstall ; yes, check for installation INT2FNLS: CMP AH,NLSFUNC ; is this a DOS 3.3 NLSFUNC request JZ TestInstall ; yes check for installation INT2FDOS: ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING CMP AH,multDOS JZ DispatchDOS IRET ; This assume that we are at the head ; of the list INT2F ENDP DispatchDOS: PUSH FOO ; push return address PUSH DTab ; push table address PUSH AX ; push index PUSH BP MOV BP,SP ; stack looks like: ; 0 BP ; 2 DISPATCH ; 4 TABLE ; 6 RETURN ; 8 LONG-RETURN ; c FLAGS ; e AX MOV AX,[BP+0Eh] ; get AX value POP BP Invoke TableDispatch JMP BadFunc ; return indicates invalid function Procedure INT2F_etcetera,NEAR entry DosGetGroup PUSH CS POP DS return entry DOSInstall MOV AL,0FFh return EndProc INT2F_etcetera ENDIF ;Input: same as ABSDRD and ABSDWRT ; ES:BP -> DPB ;Functions: convert 32bit absolute RW input parms to 16bit input parms ;Output: carry set when CX=-1 and drive is less then 32mb ; carry clear, parms ok ; Procedure RW32_CONVERT,NEAR ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING CMP CX,-1 ;>32mb new format ? ;AN000; JZ new32format ;>32mb yes ;AN000; PUSH AX ;>32mb save ax ;AN000; PUSH DX ;>32mb save dx ;AN000; MOV AX,ES:[BP.dpb_max_cluster] ;>32mb get max cluster # ;AN000; MOV DL,ES:[BP.dpb_cluster_mask] ;>32mb ;AN000; CMP DL,0FEH ;>32mb removable ? ;AN000; JZ letold ;>32mb yes ;AN000; INC DL ;>32mb ;AN000; XOR DH,DH ;>32mb dx = sector/cluster ;AN000; MUL DX ;>32mb dx:ax= max sector # ;AN000; OR DX,DX ;>32mb > 32mb ? ;AN000; letold: POP DX ;>32mb retore dx ;AN000; POP AX ;>32mb restore ax ;AN000; JZ old_style ;>32mb no ;AN000; MOV [IFS_DRIVER_ERR],0207H ;>32mb error ;AN000; STC ;>32mb ;AN000; return ;>32mb ;AN000; new32format: MOV DX,WORD PTR [BX.SECTOR_RBA+2];>32mb ;AN000; MOV [HIGH_SECTOR],DX ;>32mb ;AN000; MOV DX,WORD PTR [BX.SECTOR_RBA] ;>32mb ;AN000; MOV CX,[BX.ABS_RW_COUNT] ;>32mb ;AN000; LDS BX,[BX.BUFFER_ADDR] ;>32mb ;AN000; old_style: ;>32mb ;AN000; CLC ;>32mb ;AN000; return ;>32mb ;AN000; EndProc RW32_CONVERT ;Input: None ;Functions: Purge Fastopen/seek Cache Buffers ;Output: None ; ; Procedure Fastxxx_Purge,NEAR ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING PUSH AX ; save regs. ;AN000; PUSH SI ;AN000; PUSH DX ;AN000; TEST FastSeekflg,Fast_yes ; fastseek installed ? ;AN000; JZ topen ; no ;AN000; MOV AH,FastSeek_ID ; set fastseek id ;AN000; JMP SHORT dofast ; ;AN000; topen: TEST FastOpenflg,Fast_yes ; fastopen installed ? ;AN000; JZ nofast ; no ;AN000; MOV AH,FastOpen_ID ; set fastseek installed ;AN000; dofast: MOV AL,FONC_purge ; purge ;AN000; MOV DL,ES:[BP.dpb_drive] ; set up drive number ;AN000; invoke Fast_Dispatch ; call fastopen/seek ;AN000; nofast: POP DX ;AN000; POP SI ; restore regs ;AN000; POP AX ; ;AN000; return ; exit ;AN000; EndProc Fastxxx_Purge CODE ENDS