; ; MSCODE.ASM -- MSDOS code ; INCLUDE DOSSEG.ASM INCLUDE STDSW.ASM CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING .xcref INCLUDE DOSSYM.ASM INCLUDE DEVSYM.ASM .cref .list IFNDEF KANJI KANJI EQU 0 ; FALSE ENDIF IFNDEF IBM IBM EQU 0 ENDIF IFNDEF HIGHMEM HIGHMEM EQU 0 ENDIF i_need USER_SP,WORD i_need USER_SS,WORD i_need SAVEDS,WORD i_need SAVEBX,WORD i_need INDOS,BYTE i_need NSP,WORD i_need NSS,WORD i_need CURRENTPDB,WORD i_need AUXSTACK,BYTE i_need CONSWAP,BYTE i_need IDLEINT,BYTE i_need NOSETDIR,BYTE i_need ERRORMODE,BYTE i_need IOSTACK,BYTE i_need WPERR,BYTE i_need DSKSTACK,BYTE i_need CNTCFLAG,BYTE i_need LEAVEADDR,WORD i_need NULLDEVPT,DWORD IF NOT IBM i_need OEM_HANDLER,DWORD ENDIF EXTRN DSKSTATCHK:NEAR,GETBP:NEAR,DSKREAD:NEAR,DSKWRITE:NEAR BREAK CODSTRT EQU $ IF NOT IBM IF NOT KANJI PUBLIC HEADER HEADER DB 13,10,"Microsoft MS-DOS version " DB DOS_MAJOR_VERSION + "0" DB "." DB (DOS_MINOR_VERSION / 10) + "0" DB (DOS_MINOR_VERSION MOD 10) + "0" IF HIGHMEM DB "H" ENDIF ENDIF IF KANJI PUBLIC HEADER HEADER DB 13,10,82h,"M"+1fh,82h,"i"+20h,82h,"c"+20h,82h,"r"+20h,82h,"o"+20h DB 82h,"s"+20h,82h,"o"+20h,82h,"f"+20h,82h,"t"+20h DB 81h,40h,82h,"M"+1fh,82h,"S"+1fh,81h,5dh+1fh DB 82h,"D"+1fh,82h,"O"+1fh,82h,"S"+1fh,81h,40h DB 82h,DOS_MAJOR_VERSION+"0"+1fh DB 81h,25h+1fh DB 82h,(DOS_MINOR_VERSION / 10)+"0"+1fh DB 82h,(DOS_MINOR_VERSION MOD 10)+"0"+1fh DB 94h,0c5h ENDIF DB 13,10 DB "Copyright 1981,82,83 Microsoft Corp.",13,10,"$" ENDIF BREAK ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING procedure SYSTEM_CALL,NEAR entry QUIT ; INT 20H entry point MOV AH,0 JMP SHORT SAVREGS entry COMMAND ; Interrupt call entry point (INT 21H) IF NOT IBM CMP AH,SET_OEM_HANDLER JB NOTOEM JMP $SET_OEM_HANDLER NOTOEM: ENDIF CMP AH,MAXCOM JBE SAVREGS BADCALL: MOV AL,0 entry IRET IRET entry CALL_ENTRY ; System call entry point and dispatcher POP AX ; IP from the long call at 5 POP AX ; Segment from the long call at 5 POP [User_SP] ; IP from the CALL 5 PUSHF ; Start re-ordering the stack CLI PUSH AX ; Save segment PUSH [User_SP] ; Stack now ordered as if INT had been used CMP CL,MAXCALL ; This entry point doesn't get as many calls JA BADCALL MOV AH,CL SAVREGS: CALL save_world MOV [SaveDS],DS MOV [SaveBX],BX MOV BX,CS MOV DS,BX ASSUME DS:DOSGROUP INC [INDOS] ; Flag that we're in the DOS MOV AX,[user_SP] MOV [NSP],AX MOV AX,[user_SS] MOV [NSS],AX POP AX PUSH AX MOV [user_SP],SP MOV [user_SS],SS ; ; save user stack in his area for later returns (possibly from EXEC) ; Here comes multitasking!!! ; MOV DS,[CurrentPDB] MOV WORD PTR DS:[PDB_User_stack],SP MOV WORD PTR DS:[PDB_User_stack+2],SS MOV BX,CS ; no holes here. MOV SS,BX ASSUME SS:DOSGROUP entry REDISP MOV SP,OFFSET DOSGROUP:AUXSTACK ; Enough stack for interrupts STI ; Stack OK now PUSH CS POP DS XOR BH,BH MOV [CONSWAP],BH MOV [IDLEINT],1 MOV BYTE PTR [NoSetDir],0 ; set directories on search MOV BL,AH SHL BX,1 CLD OR AH,AH JZ DSKROUT ; ABORT CMP AH,12 JBE IOROUT ; Character I/O CMP AH,GET_CURRENT_PDB ; INT 24 needs GET,SET PDB JZ IOROUT CMP AH,SET_CURRENT_PDB JNZ DSKROUT IOROUT: CMP [ERRORMODE],0 JNZ DISPCALL ; Stay on AUXSTACK if INT 24 MOV SP,OFFSET DOSGROUP:IOSTACK JMP SHORT DISPCALL DSKROUT: MOV [ERRORMODE],0 ; Cannot make non 1-12 calls in MOV [WPERR],-1 ; error mode, so good place to ; make sure flags are reset MOV SP,OFFSET DOSGROUP:DSKSTACK TEST [CNTCFLAG],-1 JZ DISPCALL PUSH AX invoke DSKSTATCHK POP AX DISPCALL: PUSH [LEAVEADDR] PUSH CS:[BX+DISPATCH] MOV BX,[SaveBX] MOV DS,[SaveDS] ASSUME DS:NOTHING return entry LEAVE ASSUME SS:NOTHING ; User routines may misbehave CLI DEC [INDOS] MOV SP,[user_SP] MOV SS,[user_SS] MOV BP,SP MOV BYTE PTR [BP.user_AX],AL MOV AX,[NSP] MOV [user_SP],AX MOV AX,[NSS] MOV [user_SS],AX CALL restore_world IRET SYSTEM_CALL ENDP ; ; restore_world restores all registers ('cept SS:SP, CS:IP, flags) from ; the stack prior to giving the user control ; ASSUME DS:NOTHING,ES:NOTHING restore_tmp DW ? procedure restore_world,NEAR POP restore_tmp ; POP restore_tmp POP AX ; PUSH ES POP BX ; PUSH DS POP CX ; PUSH BP POP DX ; PUSH DI POP SI ; PUSH SI POP DI ; PUSH DX POP BP ; PUSH CX POP DS ; PUSH BX POP ES ; PUSH AX world_ret: PUSH restore_tmp ; PUSH restore_tmp return restore_world ENDP ; ; save_world saves complete registers on the stack ; procedure save_world,NEAR POP restore_tmp PUSH ES PUSH DS PUSH BP PUSH DI PUSH SI PUSH DX PUSH CX PUSH BX PUSH AX JMP SHORT world_ret save_world ENDP ; ; get_user_stack returns the user's stack (and hence registers) in DS:SI ; procedure get_user_stack,NEAR LDS SI,DWORD PTR [user_SP] return get_user_stack ENDP ; Standard Functions DISPATCH LABEL WORD .lall short_addr $ABORT ; 0 0 .xall short_addr $STD_CON_INPUT ; 1 1 short_addr $STD_CON_OUTPUT ; 2 2 short_addr $STD_AUX_INPUT ; 3 3 short_addr $STD_AUX_OUTPUT ; 4 4 short_addr $STD_PRINTER_OUTPUT ; 5 5 short_addr $RAW_CON_IO ; 6 6 short_addr $RAW_CON_INPUT ; 7 7 short_addr $STD_CON_INPUT_NO_ECHO ; 8 8 short_addr $STD_CON_STRING_OUTPUT ; 9 9 short_addr $STD_CON_STRING_INPUT ; 10 A short_addr $STD_CON_INPUT_STATUS ; 11 B short_addr $STD_CON_INPUT_FLUSH ; 12 C short_addr $DISK_RESET ; 13 D short_addr $SET_DEFAULT_DRIVE ; 14 E short_addr $FCB_OPEN ; 15 F short_addr $FCB_CLOSE ; 16 10 short_addr $DIR_SEARCH_FIRST ; 17 11 short_addr $DIR_SEARCH_NEXT ; 18 12 short_addr $FCB_DELETE ; 19 13 short_addr $FCB_SEQ_READ ; 20 14 short_addr $FCB_SEQ_WRITE ; 21 15 short_addr $FCB_CREATE ; 22 16 short_addr $FCB_RENAME ; 23 17 short_addr CPMFUNC ; 24 18 short_addr $GET_DEFAULT_DRIVE ; 25 19 short_addr $SET_DMA ; 26 1A ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; ; C A V E A T P R O G R A M M E R ; ; ; short_addr $SLEAZEFUNC ; 27 1B short_addr $SLEAZEFUNCDL ; 28 1C ; ; ; C A V E A T P R O G R A M M E R ; ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; short_addr CPMFUNC ; 29 1D short_addr CPMFUNC ; 30 1E ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; ; C A V E A T P R O G R A M M E R ; ; ; short_addr $GET_DEFAULT_DPB ; 31 1F ; ; ; C A V E A T P R O G R A M M E R ; ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; short_addr CPMFUNC ; 32 20 short_addr $FCB_RANDOM_READ ; 33 21 short_addr $FCB_RANDOM_WRITE ; 34 22 short_addr $GET_FCB_FILE_LENGTH ; 35 23 short_addr $GET_FCB_POSITION ; 36 24 MAXCALL = ($-DISPATCH)/2 - 1 ; Extended Functions short_addr $SET_INTERRUPT_VECTOR ; 37 25 ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; ; C A V E A T P R O G R A M M E R ; ; ; short_addr $CREATE_PROCESS_DATA_BLOCK ; 38 26 ; ; ; C A V E A T P R O G R A M M E R ; ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; short_addr $FCB_RANDOM_READ_BLOCK ; 39 27 short_addr $FCB_RANDOM_WRITE_BLOCK ; 40 28 short_addr $PARSE_FILE_DESCRIPTOR ; 41 29 short_addr $GET_DATE ; 42 2A short_addr $SET_DATE ; 43 2B short_addr $GET_TIME ; 44 2C short_addr $SET_TIME ; 45 2D short_addr $SET_VERIFY_ON_WRITE ; 46 2E ; Extended functionality group short_addr $GET_DMA ; 47 2F short_addr $GET_VERSION ; 48 30 short_addr $Keep_Process ; 49 31 ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; ; C A V E A T P R O G R A M M E R ; ; ; short_addr $GET_DPB ; 50 32 ; ; ; C A V E A T P R O G R A M M E R ; ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; short_addr $SET_CTRL_C_TRAPPING ; 51 33 short_addr $GET_INDOS_FLAG ; 52 34 short_addr $GET_INTERRUPT_VECTOR ; 53 35 short_addr $GET_DRIVE_FREESPACE ; 54 36 short_addr $CHAR_OPER ; 55 37 short_addr $INTERNATIONAL ; 56 38 ; XENIX CALLS ; Directory Group short_addr $MKDIR ; 57 39 short_addr $RMDIR ; 58 3A short_addr $CHDIR ; 59 3B ; File Group short_addr $CREAT ; 60 3C short_addr $OPEN ; 61 3D short_addr $CLOSE ; 62 3E short_addr $READ ; 63 3F short_addr $WRITE ; 64 40 short_addr $UNLINK ; 65 41 short_addr $LSEEK ; 66 42 short_addr $CHMOD ; 67 43 short_addr $IOCTL ; 68 44 short_addr $DUP ; 69 45 short_addr $DUP2 ; 70 46 short_addr $CURRENT_DIR ; 71 47 ; Memory Group short_addr $ALLOC ; 72 48 short_addr $DEALLOC ; 73 49 short_addr $SETBLOCK ; 74 4A ; Process Group short_addr $EXEC ; 75 4B short_addr $EXIT ; 76 4C short_addr $WAIT ; 77 4D short_addr $FIND_FIRST ; 78 4E ; Special Group short_addr $FIND_NEXT ; 79 4F ; SPECIAL SYSTEM GROUP ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; ; C A V E A T P R O G R A M M E R ; ; ; short_addr $SET_CURRENT_PDB ; 80 50 short_addr $GET_CURRENT_PDB ; 81 51 short_addr $GET_IN_VARS ; 82 52 short_addr $SETDPB ; 83 53 ; ; ; C A V E A T P R O G R A M M E R ; ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; short_addr $GET_VERIFY_ON_WRITE ; 84 54 ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; ; C A V E A T P R O G R A M M E R ; ; ; short_addr $DUP_PDB ; 85 55 ; ; ; C A V E A T P R O G R A M M E R ; ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; short_addr $RENAME ; 86 56 short_addr $FILE_TIMES ; 87 57 short_addr $AllocOper ; 88 58 MAXCOM = ($-DISPATCH)/2 - 1 CPMFUNC: XOR AL,AL return IF NOT IBM BREAK $SET_OEM_HANDLER: ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; User registers, User Stack, INTS disabled ; If CALL F8, DS:DX is new handler address ; Function: ; Process OEM INT 21 extensions ; Outputs: ; Jumps to OEM_HANDLER if appropriate JNE DO_OEM_FUNC ; If above F8 try to jump to handler MOV WORD PTR [OEM_HANDLER],DX ; Set Handler MOV WORD PTR [OEM_HANDLER+2],DS IRET ; Quick return, Have altered no registers DO_OEM_FUNC: CMP WORD PTR [OEM_HANDLER],-1 JNZ OEM_JMP JMP BADCALL ; Handler not initialized OEM_JMP: JMP [OEM_HANDLER] ENDIF ASSUME SS:DOSGROUP ; ; $Set_current_PDB takes BX and sets it to be the current process ; *** THIS FUNCTION CALL IS SUBJECT TO CHANGE!!! *** ; procedure $SET_CURRENT_PDB,NEAR ASSUME DS:NOTHING,SS:NOTHING MOV [CurrentPDB],BX return $SET_CURRENT_PDB ENDP ; ; $get_current_PDB returns in BX the current process ; *** THIS FUNCTION CALL IS SUBJECT TO CHANGE!!! *** ; procedure $GET_CURRENT_PDB,NEAR ASSUME DS:NOTHING,SS:NOTHING invoke get_user_stack PUSH [CurrentPDB] POP [SI.user_BX] return $GET_CURRENT_PDB ENDP ; ; ; C A V E A T P R O G R A M M E R ; ;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; BREAK procedure SNULDEV,FAR ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING MOV WORD PTR [NULLDEVPT],BX MOV WORD PTR [NULLDEVPT+2],ES return SNULDEV ENDP procedure INULDEV,FAR PUSH ES PUSH BX LES BX,[NULLDEVPT] OR ES:[BX.REQSTAT],STDON ; Set done bit POP BX POP ES return INULDEV ENDP BREAK > IF IBM ERRIN: ; Codes returned by BIOS 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 8 ; DMA OVERRUN DB 4 ; SECTOR NOT FOUND DB 3 ; WRITE ATTEMPT TO WRITE-PROTECT DISK NUMERR EQU $-ERROUT ENDIF procedure ABSDRD,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 INC BYTE PTR [INDOS] STI CLD PUSH ES PUSH DS PUSH SS POP DS ASSUME DS:DOSGROUP invoke GETBP POP DS ASSUME DS:NOTHING JC ILEAVE 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 STC ILEAVE: POP ES CLI DEC BYTE PTR [INDOS] MOV SP,[user_SP] MOV SS,[user_SS] ASSUME SS:NOTHING STI return ABSDRD ENDP 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 INC BYTE PTR [INDOS] STI CLD PUSH ES PUSH DS PUSH SS POP DS ASSUME DS:DOSGROUP invoke GETBP POP DS ASSUME DS:NOTHING JC ILEAVE invoke DSKWRITE JMP TLEAVE ABSDWRT ENDP procedure SYS_RETURN,NEAR ASSUME DS:NOTHING,ES:NOTHING entry SYS_RET_OK call get_user_stack PUSH [SI.user_F] POPF CLC JMP SHORT DO_RET entry SYS_RET_ERR XOR AH,AH ; hack to allow for smaller error rets call get_user_stack PUSH [SI.user_F] POPF STC DO_RET: MOV [SI.user_AX],AX ; Really only sets AH PUSHF POP [SI.user_F] ; dump on his flags return SYS_RETURN ENDP do_ext CODE ENDS END