mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-11-25 07:05:45 +00:00
627 lines
18 KiB
NASM
627 lines
18 KiB
NASM
TITLE GETSET - GETting and SETting MS-DOS system calls
|
||
NAME GETSET
|
||
;
|
||
; System Calls which get and set various things
|
||
;
|
||
; $GET_VERSION
|
||
; $GET_VERIFY_ON_WRITE
|
||
; $SET_VERIFY_ON_WRITE
|
||
; $SET_CTRL_C_TRAPPING
|
||
; $INTERNATIONAL
|
||
; $GET_DRIVE_FREESPACE
|
||
; $GET_DMA
|
||
; $SET_DMA
|
||
; $GET_DEFAULT_DRIVE
|
||
; $SET_DEFAULT_DRIVE
|
||
; $GET_INTERRUPT_VECTOR
|
||
; $SET_INTERRUPT_VECTOR
|
||
; RECSET
|
||
; $CHAR_OPER
|
||
;
|
||
.xlist
|
||
;
|
||
; get the appropriate segment definitions
|
||
;
|
||
INCLUDE DOSSEG.ASM
|
||
|
||
IFNDEF ALTVECT
|
||
ALTVECT EQU 0 ; FALSE
|
||
ENDIF
|
||
|
||
IFNDEF IBM
|
||
IBM EQU 0
|
||
ENDIF
|
||
|
||
CODE SEGMENT BYTE PUBLIC 'CODE'
|
||
ASSUME SS:DOSGROUP,CS:DOSGROUP
|
||
|
||
.xcref
|
||
INCLUDE DOSSYM.ASM
|
||
INCLUDE DEVSYM.ASM
|
||
.cref
|
||
.list
|
||
|
||
|
||
i_need VERFLG,BYTE
|
||
i_need CNTCFLAG,BYTE
|
||
i_need DMAADD,DWORD
|
||
i_need CURDRV,BYTE
|
||
i_need Current_Country,WORD
|
||
i_need international_table,BYTE
|
||
i_need INDOS,BYTE
|
||
i_need SYSINITVAR,WORD
|
||
i_need NUMIO,BYTE
|
||
i_need SWITCH_CHARACTER,BYTE
|
||
i_need DEVICE_AVAILABILITY,BYTE
|
||
|
||
USERNUM DW ? ; 24 bit user number
|
||
DB ?
|
||
IF IBM
|
||
OEMNUM DB 0 ; 8 bit OEM number
|
||
ELSE
|
||
OEMNUM DB 0FFH ; 8 bit OEM number
|
||
ENDIF
|
||
|
||
MSVERS EQU THIS WORD ; MS-DOS version in hex for $GET_VERSION
|
||
MSMAJOR DB DOS_MAJOR_VERSION
|
||
MSMINOR DB DOS_MINOR_VERSION
|
||
|
||
|
||
BREAK <$Get_Version -- Return MSDOS version number>
|
||
procedure $GET_VERSION,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; None
|
||
; Function:
|
||
; Return MS-DOS version number
|
||
; Outputs:
|
||
; OEM number in BH
|
||
; User number in BL:CX (24 bits)
|
||
; Version number as AL.AH in binary
|
||
; NOTE: On pre 1.28 DOSs AL will be zero
|
||
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV BX,[USERNUM + 2]
|
||
MOV CX,[USERNUM]
|
||
MOV AX,[MSVERS]
|
||
invoke get_user_stack
|
||
ASSUME DS:NOTHING
|
||
MOV [SI.user_BX],BX
|
||
MOV [SI.user_CX],CX
|
||
MOV [SI.user_AX],AX ; Really only sets AH
|
||
return
|
||
$GET_VERSION ENDP
|
||
|
||
BREAK <$International - return country-dependent information>
|
||
;
|
||
; Inputs:
|
||
; DS:DX point to a block
|
||
; Function:
|
||
; give users an idea of what country the application is running
|
||
; Outputs:
|
||
; AX = number of bytes transferred
|
||
; DS:DX ->+---------------------------------+
|
||
; | WORD Date/time format |
|
||
; +---------------------------------+
|
||
; | BYTE ASCIZ currency symbol |
|
||
; +---------------------------------+
|
||
; | BYTE ASCIZ thousands separator |
|
||
; +---------------------------------+
|
||
; | BYTE ASCIZ decimal separator |
|
||
; +---------------------------------+
|
||
|
||
procedure $INTERNATIONAL,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
MOV BL,AL
|
||
PUSH DS
|
||
POP ES
|
||
PUSH DX
|
||
POP DI
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
CMP DI,-1
|
||
JZ international_set
|
||
OR BL,BL
|
||
JNZ international_find
|
||
MOV SI,[Current_Country]
|
||
MOV AX,WORD PTR [SI-2] ; Get size in AL, country code in AH
|
||
MOV BL,AH ; Set country code
|
||
JMP SHORT international_copy
|
||
|
||
international_find:
|
||
CALL international_get
|
||
JNC international_copy
|
||
error country_not_found
|
||
|
||
international_get:
|
||
MOV SI,OFFSET DOSGROUP:international_table
|
||
international_next:
|
||
LODSW ; Get size in AL, country code in AH
|
||
CMP AL,-1
|
||
JNZ check_code
|
||
STC
|
||
RET35:
|
||
RET
|
||
|
||
check_code:
|
||
CMP BL,AH
|
||
JZ RET35 ; Carry clear
|
||
XOR AH,AH
|
||
ADD SI,AX
|
||
JMP international_next
|
||
|
||
international_copy:
|
||
MOV CL,AL
|
||
XOR CH,CH
|
||
PUSH DI
|
||
REP MOVSB
|
||
POP DI
|
||
MOV WORD PTR ES:[DI.MAP_CALL + 2],CS ; Set segment for case map call
|
||
international_ok:
|
||
XOR AX,AX
|
||
MOV AL,BL ; Return country code in AX
|
||
transfer SYS_RET_OK
|
||
|
||
international_set:
|
||
CALL international_get
|
||
JNC international_store
|
||
error country_not_found
|
||
|
||
international_store:
|
||
MOV [Current_Country],SI
|
||
JMP international_ok
|
||
|
||
$INTERNATIONAL ENDP
|
||
|
||
BREAK <$Get_Verify_on_Write - return verify-after-write flag>
|
||
procedure $GET_VERIFY_ON_WRITE,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; none.
|
||
; Function:
|
||
; returns flag
|
||
; Returns:
|
||
; AL = value of VERIFY flag
|
||
|
||
MOV AL,[VERFLG]
|
||
return
|
||
$GET_VERIFY_ON_WRITE ENDP
|
||
|
||
BREAK <$Set_Verify_on_Write - Toggle verify-after-write flag>
|
||
procedure $SET_VERIFY_ON_WRITE,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; AL = desired value of VERIFY flag
|
||
; Function:
|
||
; Sets flag
|
||
; Returns:
|
||
; None
|
||
|
||
AND AL,1
|
||
MOV [VERFLG],AL
|
||
return
|
||
$SET_VERIFY_ON_WRITE ENDP
|
||
|
||
BREAK <$Set_CTRL_C_Trapping -- En/Disable ^C check in dispatcher>
|
||
procedure $SET_CTRL_C_TRAPPING,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; AL = 0 read ^C status
|
||
; AL = 1 Set ^C status, DL = 0/1 for ^C off/on
|
||
; Function:
|
||
; Enable disable ^C checking in dispatcher
|
||
; Outputs:
|
||
; If AL = 0 then DL = 0/1 for ^C off/on
|
||
|
||
OR AL,AL
|
||
JNZ CTRL_C_set
|
||
invoke get_user_stack
|
||
MOV AL,[CNTCFLAG]
|
||
MOV BYTE PTR [SI.user_DX],AL
|
||
return
|
||
CTRL_C_set:
|
||
DEC AL
|
||
JNZ bad_val
|
||
AND DL,01h
|
||
MOV [CNTCFLAG],DL
|
||
return
|
||
bad_val:
|
||
MOV AL,0FFH
|
||
return
|
||
$SET_CTRL_C_TRAPPING ENDP
|
||
|
||
BREAK <$Get_INDOS_Flag -- Return location of DOS critical-section flag>
|
||
procedure $GET_INDOS_FLAG,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; None
|
||
; Function:
|
||
; Returns location of DOS status for interrupt routines
|
||
; Returns:
|
||
; Flag location in ES:BX
|
||
|
||
invoke get_user_stack
|
||
MOV [SI.user_BX],OFFSET DOSGROUP:INDOS
|
||
MOV [SI.user_ES],SS
|
||
return
|
||
$GET_INDOS_FLAG ENDP
|
||
|
||
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
|
||
; C A V E A T P R O G R A M M E R ;
|
||
; ;
|
||
procedure $GET_IN_VARS,NEAR
|
||
; 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.
|
||
invoke get_user_stack
|
||
MOV [SI.user_BX],OFFSET DOSGROUP:SYSINITVAR
|
||
MOV [SI.user_ES],SS
|
||
return
|
||
$GET_IN_VARS ENDP
|
||
; ;
|
||
; C A V E A T P R O G R A M M E R ;
|
||
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
|
||
|
||
BREAK <$Get_Drive_Freespace -- Return bytes of free disk space on a drive>
|
||
procedure $GET_DRIVE_FREESPACE,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DL = Drive number
|
||
; Function:
|
||
; Return number of free allocation units on drive
|
||
; Outputs:
|
||
; BX = Number of free allocation units
|
||
; DX = Total Number of allocation units on disk
|
||
; CX = Sector size
|
||
; AX = Sectors per allocation unit
|
||
; = -1 if bad drive specified
|
||
; This call returns the same info in the same registers (except for FAT pointer)
|
||
; as the old FAT pointer calls
|
||
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV AL,DL
|
||
invoke GETTHISDRV
|
||
MOV AX,-1
|
||
JC BADFRDRIVE
|
||
invoke FATREAD
|
||
XOR DX,DX
|
||
MOV BX,2
|
||
MOV CX,ES:[BP.dpb_max_cluster]
|
||
DEC CX
|
||
PUSH CX ; Save Total
|
||
SCANFREE:
|
||
invoke UNPACK
|
||
JNZ NOTFREECLUS
|
||
INC DX
|
||
NOTFREECLUS:
|
||
INC BX
|
||
LOOP SCANFREE
|
||
POP BX ; Remember Total
|
||
MOV AL,ES:[BP.dpb_cluster_mask]
|
||
INC AL
|
||
XOR AH,AH
|
||
MOV CX,ES:[BP.dpb_sector_size]
|
||
BADFRDRIVE:
|
||
invoke get_user_stack
|
||
ASSUME DS:NOTHING
|
||
MOV [SI. user_CX],CX
|
||
MOV [SI.user_DX],BX
|
||
MOV [SI.user_BX],DX
|
||
MOV [SI.user_AX],AX
|
||
return
|
||
|
||
$GET_DRIVE_FREESPACE ENDP
|
||
|
||
BREAK <$Get_DMA, $Set_DMA -- Get/Set current DMA address>
|
||
procedure $GET_DMA,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; None
|
||
; Function:
|
||
; Get DISK TRANSFER ADDRESS
|
||
; Returns:
|
||
; ES:BX is current transfer address
|
||
|
||
MOV BX,WORD PTR [DMAADD]
|
||
MOV CX,WORD PTR [DMAADD+2]
|
||
invoke get_user_stack
|
||
MOV [SI.user_BX],BX
|
||
MOV [SI.user_ES],CX
|
||
return
|
||
$GET_DMA ENDP
|
||
|
||
procedure $SET_DMA,NEAR ; System call 26
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DS:DX is desired new disk transfer address
|
||
; Function:
|
||
; Set DISK TRANSFER ADDRESS
|
||
; Returns:
|
||
; None
|
||
|
||
MOV WORD PTR [DMAADD],DX
|
||
MOV WORD PTR [DMAADD+2],DS
|
||
return
|
||
$SET_DMA ENDP
|
||
|
||
BREAK <$Get_Default_DPB,$Get_DPB -- Return pointer to DPB>
|
||
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
|
||
; C A V E A T P R O G R A M M E R ;
|
||
; ;
|
||
procedure $GET_DEFAULT_DPB,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DL = Drive number (always default drive for call 31)
|
||
; Function:
|
||
; Return pointer to drive parameter table for default drive
|
||
; Returns:
|
||
; DS:BX points to the DPB
|
||
; AL = 0 If OK, = -1 if bad drive (call 50 only)
|
||
|
||
MOV DL,0
|
||
entry $GET_DPB
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
MOV AL,DL
|
||
invoke GETTHISDRV
|
||
JC ISNODRV
|
||
invoke FATREAD
|
||
invoke get_user_stack
|
||
ASSUME DS:NOTHING
|
||
MOV [SI.user_BX],BP
|
||
MOV [SI.user_DS],ES
|
||
XOR AL,AL
|
||
return
|
||
|
||
ISNODRV:
|
||
MOV AL,-1
|
||
return
|
||
$GET_Default_dpb ENDP
|
||
; ;
|
||
; C A V E A T P R O G R A M M E R ;
|
||
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
|
||
|
||
|
||
BREAK <$Get_Default_Drive, $Set_Default_Drive -- Set/Get default drive>
|
||
procedure $GET_DEFAULT_DRIVE,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; None
|
||
; Function:
|
||
; Return current drive number
|
||
; Returns:
|
||
; AL = drive number
|
||
|
||
MOV AL,[CURDRV]
|
||
return
|
||
$GET_DEFAULT_DRIVE ENDP
|
||
|
||
procedure $SET_DEFAULT_DRIVE,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; DL = Drive number for new default drive
|
||
; Function:
|
||
; Set the default drive
|
||
; Returns:
|
||
; AL = Number of drives, NO ERROR RETURN IF DRIVE NUMBER BAD
|
||
|
||
MOV AL,[NUMIO]
|
||
CMP DL,AL
|
||
JNB RET17
|
||
MOV [CURDRV],DL
|
||
RET17: return
|
||
$SET_DEFAULT_DRIVE ENDP
|
||
|
||
|
||
BREAK <$Get_Interrupt_Vector - Get/Set interrupt vectors>
|
||
procedure $GET_INTERRUPT_VECTOR,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; AL = interrupt number
|
||
; Function:
|
||
; Get the interrupt vector
|
||
; Returns:
|
||
; ES:BX is current interrupt vector
|
||
|
||
CALL RECSET
|
||
LES BX,DWORD PTR ES:[BX]
|
||
invoke get_user_stack
|
||
MOV [SI.user_BX],BX
|
||
MOV [SI.user_ES],ES
|
||
return
|
||
$GET_INTERRUPT_VECTOR ENDP
|
||
|
||
procedure $SET_INTERRUPT_VECTOR,NEAR ; System call 37
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; AL = interrupt number
|
||
; DS:DX is desired new interrupt vector
|
||
; Function:
|
||
; Set the interrupt vector
|
||
; Returns:
|
||
; None
|
||
|
||
CALL RECSET
|
||
MOV ES:[BX],DX
|
||
MOV ES:[BX+2],DS
|
||
return
|
||
$SET_INTERRUPT_VECTOR ENDP
|
||
|
||
IF ALTVECT
|
||
VECIN: ; INPUT VECTORS
|
||
DB 22H ; Terminate
|
||
DB 23H ; ^C
|
||
DB 24H ; Hard error
|
||
DB 28H ; Spooler
|
||
LSTVEC DB ? ; ALL OTHER
|
||
|
||
VECOUT: ; GET MAPPED VECTOR
|
||
DB int_terminate
|
||
DB int_ctrl_c
|
||
DB int_fatal_abort
|
||
DB int_spooler
|
||
LSTVEC2 DB ? ; Map to itself
|
||
|
||
NUMVEC = VECOUT-VECIN
|
||
ENDIF
|
||
|
||
procedure RECSET,NEAR
|
||
|
||
IF ALTVECT
|
||
PUSH SS
|
||
POP ES
|
||
MOV [LSTVEC],AL ; Terminate list with real vector
|
||
MOV [LSTVEC2],AL ; Terminate list with real vector
|
||
MOV CX,NUMVEC ; Number of possible translations
|
||
MOV DI,OFFSET DOSGROUP:VECIN ; Point to vectors
|
||
REPNE SCASB
|
||
MOV AL,ES:[DI+NUMVEC-1] ; Get translation
|
||
ENDIF
|
||
|
||
XOR BX,BX
|
||
MOV ES,BX
|
||
MOV BL,AL
|
||
SHL BX,1
|
||
SHL BX,1
|
||
return
|
||
recset ENDP
|
||
|
||
BREAK <$Char_Oper - hack on paths, switches so that xenix can look like PCDOS>
|
||
;
|
||
; input: AL = function:
|
||
; 0 - read switch char
|
||
; 1 - set switch char (char in DL)
|
||
; 2 - read device availability
|
||
; 3 - set device availability (0/FF in DL)
|
||
; DL = 0 means /DEV/ must preceed device names
|
||
; DL = Non0 means /DEV/ need not preeceed
|
||
; output: (get) DL - character/flag
|
||
;
|
||
procedure $CHAR_OPER,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
PUSH SS
|
||
POP DS
|
||
ASSUME DS:DOSGROUP
|
||
OR AL,AL
|
||
JNZ char_oper_set_switch
|
||
MOV DL,[switch_character]
|
||
JMP SHORT char_oper_ret
|
||
char_oper_set_switch:
|
||
DEC AL
|
||
JNZ char_oper_read_avail
|
||
MOV [switch_character],DL
|
||
return
|
||
char_oper_read_avail:
|
||
DEC AL
|
||
JNZ char_oper_set_avail
|
||
MOV DL,[device_availability]
|
||
JMP SHORT char_oper_ret
|
||
char_oper_set_avail:
|
||
DEC AL
|
||
JNZ char_oper_bad_ret
|
||
MOV [device_availability],DL
|
||
return
|
||
char_oper_bad_ret:
|
||
MOV AL,0FFh
|
||
return
|
||
char_oper_ret:
|
||
invoke get_user_stack
|
||
MOV [SI.user_DX],DX
|
||
return
|
||
$CHAR_OPER ENDP
|
||
|
||
BREAK <$SetDPB - Create a valid DPB from a user-specified BPB>
|
||
procedure $SETDPB,NEAR
|
||
ASSUME DS:NOTHING,ES:NOTHING
|
||
|
||
; Inputs:
|
||
; ES:BP Points to DPB
|
||
; DS:SI Points to BPB
|
||
; Function:
|
||
; Build a correct DPB from the BPB
|
||
; Outputs:
|
||
; ES:BP and DS preserved all others destroyed
|
||
|
||
MOV DI,BP
|
||
ADD DI,2 ; Skip over dpb_drive and dpb_UNIT
|
||
LODSW
|
||
STOSW ; dpb_sector_size
|
||
MOV DX,AX
|
||
LODSB
|
||
DEC AL
|
||
STOSB ; dpb_cluster_mask
|
||
INC AL
|
||
XOR AH,AH
|
||
LOG2LOOP:
|
||
TEST AL,1
|
||
JNZ SAVLOG
|
||
INC AH
|
||
SHR AL,1
|
||
JMP SHORT LOG2LOOP
|
||
SAVLOG:
|
||
MOV AL,AH
|
||
STOSB ; dpb_cluster_shift
|
||
MOV BL,AL
|
||
MOVSW ; dpb_first_FAT Start of FAT (# of reserved sectors)
|
||
LODSB
|
||
STOSB ; dpb_FAT_count Number of FATs
|
||
MOV BH,AL
|
||
LODSW
|
||
STOSW ; dpb_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 dpb_first_sector
|
||
MOVSW ; Total number of sectors in DSKSIZ (temp as dpb_max_cluster)
|
||
LODSB
|
||
MOV ES:[BP.dpb_media],AL ; Media byte
|
||
LODSW ; Number of sectors in a FAT
|
||
STOSB ; dpb_FAT_size
|
||
MUL BH ; Space occupied by all FATs
|
||
ADD AX,ES:[BP.dpb_first_FAT]
|
||
STOSW ; dpb_dir_sector
|
||
ADD AX,CX ; Add number of directory sectors
|
||
MOV ES:[BP.dpb_first_sector],AX
|
||
SUB AX,ES:[BP.DSKSIZ]
|
||
NEG AX ; Sectors in data area
|
||
MOV CL,BL ; dpb_cluster_shift
|
||
SHR AX,CL ; Div by sectors/cluster
|
||
INC AX
|
||
MOV ES:[BP.dpb_max_cluster],AX
|
||
MOV ES:[BP.dpb_current_dir],0 ; Current directory is root
|
||
return
|
||
$SETDPB ENDP
|
||
; ;
|
||
; C A V E A T P R O G R A M M E R ;
|
||
;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
|
||
|
||
do_ext
|
||
|
||
CODE ENDS
|
||
END
|
||
|