MS-DOS/v2.0/source/XENIX2.ASM

626 lines
17 KiB
NASM
Raw Normal View History

1983-08-13 01:53:34 +01:00
;
; xenix file calls for MSDOS
;
INCLUDE DOSSEG.ASM
IFNDEF KANJI
KANJI EQU 0 ;FALSE
ENDIF
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
TITLE XENIX - IO system to mimic UNIX
NAME XENIX
i_need NoSetDir,BYTE
i_need CURDRV,BYTE
i_need IOCALL,BYTE
i_need IOMED,BYTE
i_need IOSCNT,WORD
i_need IOXAD,DWORD
i_need DIRSTART,WORD
i_need ATTRIB,BYTE
i_need THISFCB,DWORD
i_need AuxStack,BYTE
i_need Creating,BYTE
i_need ThisDRV,BYTE
i_need NAME1,BYTE
i_need LastEnt,WORD
i_need ThisDPB,DWORD
i_need EntLast,WORD
i_need CurrentPDB,WORD
i_need sft_addr,DWORD ; pointer to head of table
i_need CURBUF,DWORD ; pointer to current buffer
i_need DMAADD,DWORD ; pointer to current dma address
BREAK <Local data>
CODE ENDS
DATA SEGMENT BYTE PUBLIC 'DATA'
PushSave DW ?
PushES DW ?
PushBX DW ?
xenix_count DW ?
DATA ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
BREAK <get_sf_from_sfn - translate a sfn into sf pointer>
;
; get_sf_from_sfn
; input: AX has sfn (0 based)
; DS is DOSGROUP
; output: JNC <found>
; ES:DI is sf entry
; JC <error>
; ES,DI indeterminate
;
procedure get_sf_from_sfn,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
PUSH AX ; we trash AX in process
LES DI,[sft_addr]
get_sfn_loop:
CMP DI,-1 ; end of chain of tables?
JZ get_sf_invalid ; I guess so...
SUB AX,ES:[DI].sft_count ; chop number of entries in this table
JL get_sf_gotten ; sfn is in this table
LES DI,ES:[DI].sft_link ; step to next table
JMP get_sfn_loop
get_sf_gotten:
ADD AX,ES:[DI].sft_count ; reset to index in this table
PUSH BX
MOV BX,SIZE sf_entry
MUL BL ; number of bytes offset into table
POP BX
ADD AX,sft_table ; offset into sf table structure
ADD DI,AX ; offset into memory
CLC
JMP SHORT get_sf_ret
get_sf_jfn_invalid:
get_sf_invalid:
STC
get_sf_jfn_ret:
get_sf_ret:
POP AX ; remember him?
RET
get_sf_from_sfn ENDP
BREAK <get_sf_from_jfn - translate a jfn into sf pointer>
;
; get_sf_from_jfn
; input: BX is jfn 0 based
; DS is DOSGROUP
; output: JNC <found>
; ES:DI is sf entry
; JC <error>
; ES,DI is indeterminate
;
procedure get_sf_from_jfn,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
PUSH AX ; save him
invoke get_jfn_pointer
JC get_sf_jfn_invalid
MOV AL,ES:[DI] ; get sfn
CMP AL,0FFh ; is it free?
JZ get_sf_jfn_invalid ; yep... error
XOR AH,AH
invoke get_sf_from_sfn ; check this sfn out...
JMP SHORT get_sf_jfn_ret ; condition codes are properly set
get_sf_from_jfn ENDP
BREAK <get_jfn_pointer - map a jfn into a pointer to jfn>
;
; get_jfn_pointer
; input: BX is jfn
; DS is DOSGROUP
; output: JNC <found>
; ES:DI is pointer to jfn
; JC <bad jfn>
;
procedure Get_jfn_pointer,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
CMP BX,FilPerProc
JAE get_jfn_bad
MOV ES,[CurrentPDB]
MOV DI,BX
ADD DI,PDB_JFN_Table
CLC
RET
get_jfn_bad:
STC
RET
get_jfn_pointer ENDP
BREAK <$Close - release a handle>
;
; Assembler usage:
; MOV BX, handle
; MOV AH, Close
; INT int_command
;
; Error return:
; AX = error_invalid_handle
;
procedure $Close,NEAR
ASSUME DS:NOTHING,ES:NOTHING
context DS
invoke get_jfn_pointer ; get jfn loc
JNC close_jfn
close_bad_handle:
error error_invalid_handle
close_jfn:
MOV AL,BYTE PTR ES:[DI]
CMP AL,0FFh
JE close_bad_handle
MOV BYTE PTR ES:[DI],0FFh;
XOR AH,AH
invoke get_sf_from_sfn
JC close_bad_handle
PUSH ES
POP DS
ASSUME DS:NOTHING
DEC [DI].sf_ref_count ; no more reference
LEA DX,[DI].sf_fcb
;
; need to restuff Attrib if we are closing a protected file
;
TEST [DI.sf_fcb.fcb_DevID],devid_file_clean+devid_device
JNZ close_ok
PUSH WORD PTR [DI].sf_attr
invoke MOVNAMENOSET
POP BX
MOV [Attrib],BL
invoke FCB_CLOSE_INNER
CMP AL,0FFh ; file not found error?
JNZ close_ok
error error_file_not_found
close_ok:
transfer SYS_RET_OK
$Close ENDP
BREAK <PushDMA, PopDMA, ptr_normalize - set up local dma and save old>
; PushDMA
; input: DS:DX is DMA
; output: DS:DX is normalized , ES:BX destroyed
; [DMAADD] is now set up to DS:DX
; old DMA is pushed
procedure PushDMA,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV PushES,ES
MOV PushBX,BX
POP PushSave
LES BX,DWORD PTR [DMAADD] ; get old dma
PUSH ES
PUSH BX
PUSH PushSave
invoke ptr_normalize ; get new dma
MOV WORD PTR [DMAADD],DX ; save IT!
MOV WORD PTR [DMAADD+2],DS
MOV ES,PushES
MOV BX,PushBX
RET
PushDMA ENDP
; PopDMA
; input: old DMA under ret address on stack
; output: [DMAADD] set to old version and stack popped
procedure PopDMA,NEAR
ASSUME DS:NOTHING,ES:NOTHING
POP PushSave
POP WORD PTR [DMAADD]
POP WORD PTR [DMAADD+2]
PUSH PushSave
RET
PopDMA ENDP
; ptr_normalize
; input: DS:DX is a pointer
; output: DS:DX is normalized (DX < 10h)
procedure ptr_normalize,NEAR
PUSH CX ; T1 = CX
PUSH DX ; T2 = DX
MOV CL,4
SHR DX,CL ; DX = (DX >> 4) (using CX)
MOV CX,DS
ADD CX,DX
MOV DS,CX ; DS = DS + DX (using CX)
POP DX
AND DX,0Fh ; DX = T2 & 0Fh
POP CX ; CX = T1
; PUSH AX
; PUSH DX
; MOV AX,DS
; PUSH CX
; MOV CL,4
; SHR DX,CL ; get upper part of dx
; POP CX
; ADD AX,DX ; add into seg address
; MOV DS,AX
; POP DX
; AND DX,0Fh ; save low part
; POP AX
RET
ptr_normalize ENDP
BREAK <$Read - Do file/device I/O>
;
; Assembler usage:
; LDS DX, buf
; MOV CX, count
; MOV BX, handle
; MOV AH, Read
; INT int_command
; AX has number of bytes read
; Errors:
; AX = read_invalid_handle
; = read_access_denied
;
procedure $Read,NEAR
ASSUME DS:NOTHING,ES:NOTHING
invoke PushDMA
CALL IO_setup
JC IO_err
CMP ES:[DI].sf_mode,open_for_write
JNE read_setup
IO_bad_mode:
MOV AL,read_access_denied
IO_err:
invoke PopDMA
transfer SYS_RET_ERR
read_setup:
invoke $FCB_RANDOM_READ_BLOCK ; do read
IO_done:
invoke get_user_stack ; get old frame
MOV AX,[SI].user_CX ; get returned CX
MOV CX,xenix_count
MOV [SI].user_CX,CX ; stash our CX
invoke PopDMA ; get old DMA
transfer SYS_RET_OK
$Read ENDP
BREAK <$Write - Do file/device I/O>
;
; Assembler usage:
; LDS DX, buf
; MOV CX, count
; MOV BX, handle
; MOV AH, Write
; INT int_command
; AX has number of bytes written
; Errors:
; AX = write_invalid_handle
; = write_access_denied
;
procedure $Write,NEAR
ASSUME DS:NOTHING,ES:NOTHING
invoke PushDMA
CALL IO_setup
JC IO_err
CMP ES:[DI].sf_mode,open_for_read
JE IO_bad_mode
invoke $FCB_RANDOM_WRITE_BLOCK ; do write
JMP IO_done
$write ENDP
IO_setup:
ASSUME DS:NOTHING,ES:NOTHING
context DS
MOV xenix_count,CX
invoke Get_sf_from_jfn
; ES:DI is sf pointer
MOV AL,read_invalid_handle ;Assume an error
MOV CX,xenix_count
LEA DX,[DI].sf_fcb
PUSH ES
POP DS
ASSUME DS:NOTHING
RET
BREAK <$LSEEK - set random record field>
;
; Assembler usage:
; MOV DX, offsetlow
; MOV CX, offsethigh
; MOV BX, handle
; MOV AL, method
; MOV AH, LSeek
; INT int_command
; DX:AX has the new location of the pointer
; Error returns:
; AX = error_invalid_handle
; = error_invalid_function
procedure $LSEEK,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CMP AL,3
JB lseek_get_sf
error error_invalid_function
lseek_get_sf:
context DS
invoke get_sf_from_jfn
PUSH ES
POP DS
ASSUME DS:NOTHING
JC lseek_bad
;
; don't seek device
;
TEST [DI.sf_fcb+fcb_devid],devid_device
JZ lseek_dispatch
XOR AX,AX
XOR DX,DX
JMP SHORT lseek_ret
lseek_dispatch:
DEC AL
JL lseek_beginning
DEC AL
JL lseek_current
; move from end of file
; first, get end of file
XCHG AX,DX ; AX <- low
XCHG DX,CX ; DX <- high
ASSUME DS:NOTHING
ADD AX,[DI+sf_fcb+fcb_FILSIZ]
ADC DX,[DI+sf_fcb+fcb_FILSIZ+2]
JMP SHORT lseek_ret
lseek_beginning:
XCHG AX,DX ; AX <- low
XCHG DX,CX ; DX <- high
lseek_ret:
MOV WORD PTR [DI+sf_fcb+fcb_RR],AX
MOV WORD PTR [DI+sf_fcb+fcb_RR+2],DX
invoke get_user_stack
MOV [SI.user_DX],DX
MOV [SI.user_AX],AX
transfer SYS_RET_OK
lseek_current:
; ES:DI is pointer to sf... need to invoke set random record for place
XCHG AX,DX ; AX <- low
XCHG DX,CX ; DX <- high
ADD AX,WORD PTR [DI+sf_fcb+fcb_RR]
ADC DX,WORD PTR [DI+sf_fcb+fcb_RR+2]
JMP lseek_ret
lseek_bad:
error error_invalid_handle
$lseek ENDP
BREAK <$IOCTL - return/set device dependent stuff>
;
; Assembler usage:
; MOV BX, Handle
; MOV DX, Data
;
; (or LDS DX,BUF
; MOV CX,COUNT)
;
; MOV AH, Ioctl
; MOV AL, Request
; INT 21h
;
; Error returns:
; AX = error_invalid_handle
; = error_invalid_function
; = error_invalid_data
procedure $IOCTL,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV SI,DS ;Stash DS for calls 2,3,4 and 5
context DS
CMP AL,3
JA ioctl_check_block ;Block device
PUSH DX
invoke get_sf_from_jfn
POP DX ;Restore DATA
JNC ioctl_check_permissions ; have valid handle
error error_invalid_handle
ioctl_check_permissions:
CMP AL,2
JAE ioctl_control_string
CMP AL,0
MOV AL,BYTE PTR ES:[DI+sf_fcb+fcb_devid]
JZ ioctl_read ; read the byte
OR DH,DH
JZ ioctl_check_device ; can I set with this data?
error error_invalid_data ; no DH <> 0
ioctl_check_device:
TEST AL,devid_ISDEV ; can I set this handle?
JZ ioctl_bad_fun ; no, it is a file.
MOV BYTE PTR ES:[DI+sf_fcb+fcb_devid],DL
transfer SYS_RET_OK
ioctl_read:
XOR AH,AH
TEST AL,devid_ISDEV ; Should I set high byte
JZ ioctl_no_high ; no
LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer
MOV AH,BYTE PTR ES:[DI.SDEVATT+1] ;Get high byte
ioctl_no_high:
invoke get_user_stack
MOV DX,AX
MOV [SI.user_DX],DX
transfer SYS_RET_OK
ioctl_control_string:
TEST BYTE PTR ES:[DI+sf_fcb+fcb_devid],devid_ISDEV ; can I?
JZ ioctl_bad_fun ; no, it is a file.
LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer
XOR BL,BL ; Unit number of char dev = 0
JMP SHORT ioctl_do_string
ioctl_check_block:
DEC AL
DEC AL ;4=2,5=3,6=4,7=5
CMP AL,3
JBE ioctl_get_dev
MOV AH,1
SUB AL,4 ;6=0,7=1
JZ ioctl_get_status
MOV AH,3
DEC AL
JNZ ioctl_bad_fun
ioctl_get_status:
PUSH AX
invoke GET_IO_FCB
POP AX
JC ioctl_acc_err
invoke IOFUNC
MOV AH,AL
MOV AL,0FFH
JNZ ioctl_status_ret
INC AL
ioctl_status_ret:
transfer SYS_RET_OK
ioctl_bad_fun:
error error_invalid_function
ioctl_acc_err:
error error_access_denied
ioctl_get_dev:
PUSH CX
PUSH DX
PUSH AX
PUSH SI ;DS in disguise
MOV AL,BL ;Drive
invoke GETTHISDRV
JC ioctl_bad_drv
invoke FATREAD ;"get" the drive
MOV BL,ES:[BP.dpb_UNIT] ; Unit number
LES DI,ES:[BP.dpb_driver_addr]
CLC ;Make sure error jump not taken
ioctl_bad_drv:
POP SI
POP AX
POP DX
POP CX
JC ioctl_acc_err
ioctl_do_string:
TEST ES:[DI.SDEVATT],DEVIOCTL ;See if device accepts control
JZ ioctl_bad_fun ;NO
DEC AL
DEC AL
JZ ioctl_control_read
MOV [IOCALL.REQFUNC],DEVWRIOCTL
JMP SHORT ioctl_control_call
ioctl_control_read:
MOV [IOCALL.REQFUNC],DEVRDIOCTL
ioctl_control_call:
MOV AL,DRDWRHL
MOV AH,BL ;Unit number
MOV WORD PTR [IOCALL.REQLEN],AX
XOR AX,AX
MOV [IOCALL.REQSTAT],AX
MOV [IOMED],AL
MOV [IOSCNT],CX
MOV WORD PTR [IOXAD],DX
MOV WORD PTR [IOXAD+2],SI
PUSH ES
POP DS
ASSUME DS:NOTHING
MOV SI,DI ;DS:SI -> driver
PUSH SS
POP ES
MOV BX,OFFSET DOSGROUP:IOCALL ;ES:BX -> Call header
invoke DEVIOCALL2
MOV AX,[IOSCNT] ;Get actual bytes transferred
transfer SYS_RET_OK
$IOCTL ENDP
BREAK <File_Times - modify write times on a handle>
;
; Assembler usage:
; MOV AH, FileTimes
; MOV AL, func
; MOV BX, handle
; ; if AL = 1 then then next two are mandatory
; MOV CX, time
; MOV DX, date
; INT 21h
; ; if AL = 0 then CX/DX has the last write time/date
; ; for the handle.
;
; Error returns:
; AX = error_invalid_function
; = error_invalid_handle
;
procedure $File_times,near
CMP AL,2
JB filetimes_ok
error error_invalid_function
filetimes_ok:
PUSH SS
POP DS
CALL Get_sf_from_jfn
JNC filetimes_disp
error error_invalid_handle
filetimes_disp:
OR AL,AL
JNZ filetimes_set
MOV CX,ES:[DI.sf_fcb.fcb_FTIME]
MOV DX,ES:[DI.sf_fcb.fcb_FDATE]
invoke Get_user_stack
MOV [SI.user_CX],CX
MOV [SI.user_DX],DX
transfer SYS_RET_OK
filetimes_set:
MOV ES:[DI.sf_fcb.fcb_FTIME],CX
MOV ES:[DI.sf_fcb.fcb_FDATE],DX
AND ES:[DI.sf_fcb.fcb_DEVID],NOT devid_file_clean
transfer SYS_RET_OK
$file_times ENDP
do_ext
CODE ENDS
END