fa3dc59367
To be able to return free space on larger non local disks, the redirector needs an extension. Dosemu2 has implemented this function and FDPP has an almost identical patch to this. If the extension is not implemented by your chosen redirector, then fallback to the standard 110c function is done for int21/7303. With this patch up to 2TB (with Dosemu2 reporting in 512 blocks) can be displayed.
620 lines
19 KiB
NASM
620 lines
19 KiB
NASM
;
|
|
; File:
|
|
; int2f.asm
|
|
; Description:
|
|
; multiplex interrupt support code
|
|
;
|
|
; Copyright (c) 1996, 1998
|
|
; Pasquale J. Villani
|
|
; All Rights Reserved
|
|
;
|
|
; This file is part of DOS-C.
|
|
;
|
|
; DOS-C is free software; you can redistribute it and/or
|
|
; modify it under the terms of the GNU General Public License
|
|
; as published by the Free Software Foundation; either version
|
|
; 2, or (at your option) any later version.
|
|
;
|
|
; DOS-C is distributed in the hope that it will be useful, but
|
|
; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
|
; the GNU General Public License for more details.
|
|
;
|
|
; You should have received a copy of the GNU General Public
|
|
; License along with DOS-C; see the file COPYING. If not,
|
|
; write to the Free Software Foundation, 675 Mass Ave,
|
|
; Cambridge, MA 02139, USA.
|
|
;
|
|
; $Id: int2f.asm 1591 2011-05-06 01:46:55Z bartoldeman $
|
|
;
|
|
|
|
%include "segs.inc"
|
|
%include "stacks.inc"
|
|
|
|
; macro to switch to an internal stack (if necessary), set DS == SS == DGROUP,
|
|
; and push the old SS:SP onto the internal stack
|
|
;
|
|
; destroys AX, SI, BP; turns on IRQs
|
|
;
|
|
; int2f does not really need to switch to a separate stack for MS-DOS
|
|
; compatibility; this is mainly to work around the C code's assumption
|
|
; that SS == DGROUP
|
|
;
|
|
; TODO: remove the need for this hackery -- tkchia
|
|
%macro SwitchToInt2fStack 0
|
|
mov ax,[cs:_DGROUP_]
|
|
mov ds,ax
|
|
mov si,ss
|
|
mov bp,sp
|
|
cmp ax,si
|
|
jz %%already
|
|
cli
|
|
mov ss,ax
|
|
extern int2f_stk_top
|
|
mov sp,int2f_stk_top
|
|
sti
|
|
%%already:
|
|
; well, GCC does not currently clobber function parameters passed on the
|
|
; stack; but just in case it decides to do that in the future, we push _two_
|
|
; copies of the old SS:SP:
|
|
; - the second copy can be passed as a pointer parameter to a C function
|
|
; - the first copy is used to actually restore the user stack later
|
|
push si
|
|
push bp
|
|
push si
|
|
push bp
|
|
%endmacro
|
|
|
|
; macro to switch back from an internal stack, i.e. undo SwitchToInt2fStack
|
|
;
|
|
; destroys BP; turns on IRQs -- tkchia
|
|
%macro DoneInt2fStack 0
|
|
pop bp
|
|
pop bp
|
|
pop bp
|
|
cli
|
|
pop ss
|
|
mov sp,bp
|
|
sti
|
|
%endmacro
|
|
|
|
segment HMA_TEXT
|
|
extern _cu_psp
|
|
extern _HaltCpuWhileIdle
|
|
extern _syscall_MUX14
|
|
|
|
extern _DGROUP_
|
|
|
|
global reloc_call_int2f_handler
|
|
reloc_call_int2f_handler:
|
|
sti ; Enable interrupts
|
|
cmp ah,11h ; Network interrupt?
|
|
jne Int2f3 ; No, continue
|
|
Int2f1:
|
|
or al,al ; Installation check?
|
|
jz FarTabRetn ; yes, just return
|
|
Int2f2:
|
|
mov ax,1 ; TE 07/13/01
|
|
; at least for redirected INT21/5F44
|
|
; --> 2f/111e
|
|
; the error code is AX=0001 = unknown function
|
|
stc
|
|
FarTabRetn:
|
|
retf 2 ; Return far
|
|
|
|
WinIdle: ; only HLT if at haltlevel 2+
|
|
push ds
|
|
mov ds, [cs:_DGROUP_]
|
|
cmp byte [_HaltCpuWhileIdle],2
|
|
pop ds
|
|
jb FarTabRetn
|
|
pushf
|
|
sti
|
|
hlt ; save some energy :-)
|
|
popf
|
|
push ds
|
|
mov ds, [cs:_DGROUP_]
|
|
cmp byte [_HaltCpuWhileIdle],3
|
|
pop ds
|
|
jb FarTabRetn
|
|
mov al,0 ; even admit we HLTed ;-)
|
|
jmp short FarTabRetn
|
|
|
|
Int2f3: cmp ax,1680h ; Win "release time slice"
|
|
je WinIdle
|
|
cmp ah,12h
|
|
je IntDosCal ; Dos Internal calls
|
|
cmp ah,13h
|
|
je IntDosCal ; Install Int13h Hook
|
|
cmp ah,16h
|
|
je IntDosCal ; Win (Multitasking) Hook
|
|
cmp ah,46h
|
|
je IntDosCal ; Win Hook to avoid MCB corruption
|
|
|
|
cmp ax,4a01h
|
|
je IntDosCal ; Dos Internal calls
|
|
cmp ax,4a02h
|
|
je IntDosCal ; Dos Internal calls
|
|
%ifdef WITHFAT32
|
|
cmp ax,4a33h ; Check DOS version 7
|
|
jne Check4Share
|
|
xor ax,ax ; no undocumented shell strings
|
|
xor bx,bx ; RBIL undoc BX = ?? (0h)
|
|
; " DS:DX ASCIIZ shell exe name
|
|
; " DS:SI SHELL= line
|
|
iret
|
|
Check4Share:
|
|
%endif
|
|
cmp ah,10h ; SHARE.EXE interrupt?
|
|
je Int2f1 ; yes, do installation check
|
|
cmp ah,08h
|
|
je DriverSysCal ; DRIVER.SYS calls
|
|
cmp ah,14h ; NLSFUNC.EXE interrupt?
|
|
jne Int2f?iret ; yes, do installation check
|
|
Int2f?14: ;; MUX-14 -- NLSFUNC API
|
|
;; all functions are passed to syscall_MUX14
|
|
push bp ; Preserve BP later on
|
|
Protect386Registers
|
|
PUSH$ALL
|
|
SwitchToInt2fStack
|
|
call _syscall_MUX14
|
|
DoneInt2fStack
|
|
pop bp ; Discard incoming AX
|
|
push ax ; Correct stack for POP$ALL
|
|
POP$ALL
|
|
Restore386Registers
|
|
mov bp, sp
|
|
or ax, ax
|
|
jnz Int2f?14?1 ; must return set carry
|
|
;; -6 == -2 (CS), -2 (IP), -2 (flags)
|
|
;; current SP = on old_BP
|
|
and BYTE [bp-6], 0feh ; clear carry as no error condition
|
|
pop bp
|
|
iret
|
|
Int2f?14?1: or BYTE [bp-6], 1
|
|
pop bp
|
|
Int2f?iret:
|
|
iret
|
|
|
|
; DRIVER.SYS calls - now only 0803.
|
|
DriverSysCal:
|
|
extern _Dyn
|
|
cmp al, 3
|
|
jne Int2f?iret
|
|
mov ds, [cs:_DGROUP_]
|
|
mov di, _Dyn+2
|
|
jmp short Int2f?iret
|
|
|
|
|
|
;**********************************************************************
|
|
; internal dos calls INT2F/12xx and INT2F/4A01,4A02 - handled through C
|
|
;**********************************************************************
|
|
IntDosCal:
|
|
; set up register structure
|
|
;struct int2f12regs
|
|
;{
|
|
; [space for 386 regs]
|
|
; UWORD es,ds;
|
|
; UWORD di,si,bp,bx,dx,cx,ax;
|
|
; UWORD ip,cs,flags;
|
|
; UWORD callerARG1;
|
|
;}
|
|
push ax
|
|
push cx
|
|
push dx
|
|
push bx
|
|
push bp
|
|
push si
|
|
push di
|
|
push ds
|
|
push es
|
|
|
|
cld
|
|
|
|
%if XCPU >= 386
|
|
%ifdef WATCOM
|
|
mov si,fs
|
|
mov di,gs
|
|
%else
|
|
Protect386Registers
|
|
%endif
|
|
%endif
|
|
|
|
SwitchToInt2fStack
|
|
extern _int2F_12_handler
|
|
call _int2F_12_handler
|
|
DoneInt2fStack
|
|
|
|
%if XCPU >= 386
|
|
%ifdef WATCOM
|
|
mov fs,si
|
|
mov gs,di
|
|
%else
|
|
Restore386Registers
|
|
%endif
|
|
%endif
|
|
|
|
pop es
|
|
pop ds
|
|
pop di
|
|
pop si
|
|
pop bp
|
|
pop bx
|
|
pop dx
|
|
pop cx
|
|
pop ax
|
|
|
|
iret
|
|
|
|
global SHARE_CHECK
|
|
SHARE_CHECK:
|
|
mov ax, 0x1000
|
|
int 0x2f
|
|
test ax, "US" ; Uninstallable SHARE signature
|
|
ret
|
|
|
|
; DOS calls this to see if it's okay to open the file.
|
|
; Returns a file_table entry number to use (>= 0) if okay
|
|
; to open. Otherwise returns < 0 and may generate a critical
|
|
; error. If < 0 is returned, it is the negated error return
|
|
; code, so DOS simply negates this value and returns it in
|
|
; AX.
|
|
; STATIC int share_open_check(const char FAR * filename,
|
|
; /* pointer to fully qualified filename */
|
|
; unsigned short pspseg,
|
|
; /* psp segment address of owner process */
|
|
; int openmode,
|
|
; /* 0=read-only, 1=write-only, 2=read-write */
|
|
; int sharemode) /* SHARE_COMPAT, etc... */
|
|
global SHARE_OPEN_CHECK
|
|
SHARE_OPEN_CHECK:
|
|
push ds
|
|
pop es ; save ds
|
|
mov di, si ; save si
|
|
pop ax ; return address
|
|
popargs {ds,si},bx,cx,dx; filename,pspseg,openmode,sharemode;
|
|
push ax ; return address
|
|
mov ax, 0x10a0
|
|
int 0x2f ; returns ax
|
|
mov si, di ; restore si
|
|
push es
|
|
pop ds ; restore ds
|
|
ret
|
|
|
|
; DOS calls this to record the fact that it has successfully
|
|
; closed a file, or the fact that the open for this file failed.
|
|
; STATIC void share_close_file(int fileno) /* file_table entry number */
|
|
|
|
global SHARE_CLOSE_FILE
|
|
SHARE_CLOSE_FILE:
|
|
pop ax
|
|
pop bx
|
|
push ax
|
|
mov ax, 0x10a1
|
|
int 0x2f
|
|
ret
|
|
|
|
; DOS calls this to determine whether it can access (read or
|
|
; write) a specific section of a file. We call it internally
|
|
; from lock_unlock (only when locking) to see if any portion
|
|
; of the requested region is already locked. If pspseg is zero,
|
|
; then it matches any pspseg in the lock table. Otherwise, only
|
|
; locks which DO NOT belong to pspseg will be considered.
|
|
; Returns zero if okay to access or lock (no portion of the
|
|
; region is already locked). Otherwise returns non-zero and
|
|
; generates a critical error (if allowcriter is non-zero).
|
|
; If non-zero is returned, it is the negated return value for
|
|
; the DOS call.
|
|
;STATIC int share_access_check(unsigned short pspseg,
|
|
; /* psp segment address of owner process */
|
|
; int fileno, /* file_table entry number */
|
|
; unsigned long ofs, /* offset into file */
|
|
; unsigned long len, /* length (in bytes) of region to access */
|
|
; int allowcriter) /* allow a critical error to be generated */
|
|
global SHARE_ACCESS_CHECK
|
|
SHARE_ACCESS_CHECK:
|
|
mov ax, 0x10a2
|
|
share_common:
|
|
push bp
|
|
mov bp, sp
|
|
push si
|
|
push di
|
|
arg pspseg, fileno, {ofs,4}, {len,4}, allowcriter
|
|
mov bx, [.pspseg] ; pspseg
|
|
mov cx, [.fileno] ; fileno
|
|
mov si, [.ofs+2] ; high word of ofs
|
|
mov di, [.ofs] ; low word of ofs
|
|
les dx, [.len] ; len
|
|
or ax, [.allowcriter] ; allowcriter/unlock
|
|
int 0x2f
|
|
pop di
|
|
pop si
|
|
pop bp
|
|
ret 14 ; returns ax
|
|
|
|
; DOS calls this to lock or unlock a specific section of a file.
|
|
; Returns zero if successfully locked or unlocked. Otherwise
|
|
; returns non-zero.
|
|
; If the return value is non-zero, it is the negated error
|
|
; return code for the DOS 0x5c call. */
|
|
;STATIC int share_lock_unlock(unsigned short pspseg, /* psp segment address of owner process */
|
|
; int fileno, /* file_table entry number */
|
|
; unsigned long ofs, /* offset into file */
|
|
; unsigned long len, /* length (in bytes) of region to lock or unlock */
|
|
; int unlock) /* one to unlock; zero to lock */
|
|
global SHARE_LOCK_UNLOCK
|
|
SHARE_LOCK_UNLOCK:
|
|
mov ax,0x10a4
|
|
jmp short share_common
|
|
|
|
; DOS calls this to see if share already has the file marked as open.
|
|
; Returns:
|
|
; 1 if open
|
|
; 0 if not
|
|
; STATIC WORD share_is_file_open(const char far *filename) /* pointer to fully qualified filename */
|
|
global SHARE_IS_FILE_OPEN
|
|
SHARE_IS_FILE_OPEN:
|
|
mov si, ds
|
|
mov es, si ; save ds
|
|
pop ax ; save return address
|
|
pop si ; filename
|
|
pop ds ; SEG filename
|
|
push ax ; restore return address
|
|
mov ax, 0x10a6
|
|
int 0x2f ; returns ax
|
|
mov si, es ; restore ds
|
|
mov ds, si
|
|
ret
|
|
|
|
; Int 2F Multipurpose Remote System Calls
|
|
;
|
|
; added by James Tabor jimtabor@infohwy.com
|
|
; changed by Bart Oldeman
|
|
;
|
|
; assume ss == ds after setup of stack in entry
|
|
; sumtimes return data *ptr is the push stack word
|
|
;
|
|
|
|
remote_lseek: ; arg is a pointer to the long seek value
|
|
mov bx, cx
|
|
mov dx, [bx]
|
|
mov cx, [bx+2]
|
|
; "fall through"
|
|
|
|
remote_getfattr:
|
|
clc ; set to succeed
|
|
int 2fh
|
|
jc ret_neg_ax
|
|
jmp short ret_int2f
|
|
|
|
remote_lock_unlock:
|
|
mov dx, cx ; parameter block (dx) in arg
|
|
mov bx, cx
|
|
mov bl, [bx + 8] ; unlock or not
|
|
mov cx, 1
|
|
int 0x2f
|
|
jnc ret_set_ax_to_carry
|
|
mov ah, 0
|
|
jmp short ret_neg_ax
|
|
|
|
;long ASMPASCAL network_redirector_mx(unsigned cmd, void far *s, void *arg)
|
|
global NETWORK_REDIRECTOR_MX
|
|
NETWORK_REDIRECTOR_MX:
|
|
pop bx ; ret address
|
|
popargs ax,{es,dx},cx ; cmd (ax), seg:off s
|
|
; stack value (arg); cx in remote_rw
|
|
push bx ; ret address
|
|
call_int2f:
|
|
push bp
|
|
push si
|
|
push di
|
|
cmp al, 0fh
|
|
je remote_getfattr
|
|
|
|
mov di, dx ; es:di -> s and dx is used for 1125!
|
|
cmp al, 08h
|
|
je remote_rw
|
|
cmp al, 09h
|
|
je remote_rw
|
|
cmp al, 0ah
|
|
je remote_lock_unlock
|
|
cmp al, 21h
|
|
je remote_lseek
|
|
cmp al, 22h
|
|
je remote_process_end
|
|
cmp al, 23h
|
|
je qremote_fn
|
|
|
|
push cx ; arg
|
|
cmp al, 0ch
|
|
je remote_getfree
|
|
cmp al, 0xa3
|
|
je remote_getfree
|
|
cmp al, 1eh
|
|
je remote_print_doredir
|
|
cmp al, 1fh
|
|
je remote_print_doredir
|
|
|
|
int2f_call:
|
|
xor cx, cx ; set to succeed; clear carry and CX
|
|
int 2fh
|
|
pop bx
|
|
jnc ret_set_ax_to_cx
|
|
ret_neg_ax:
|
|
neg ax
|
|
ret_int2f:
|
|
pop di
|
|
pop si
|
|
pop bp
|
|
ret
|
|
|
|
ret_set_ax_to_cx: ; ext_open or rw -> status from CX in AX
|
|
; otherwise CX was set to zero above
|
|
xchg ax, cx ; set ax:=cx (one byte shorter than mov)
|
|
jmp short ret_int2f
|
|
|
|
remote_print_doredir: ; di points to an lregs structure
|
|
mov es,[di+0xe]
|
|
mov bx,[di+2]
|
|
mov cx,[di+4]
|
|
mov dx,[di+6]
|
|
mov si,[di+8]
|
|
lds di,[di+0xa]
|
|
|
|
clc ; set to succeed
|
|
int 2fh
|
|
pop bx ; restore stack and ds=ss
|
|
push ss
|
|
pop ds
|
|
jc ret_neg_ax
|
|
ret_set_ax_to_carry: ; carry => -1 else 0 (SUCCESS)
|
|
sbb ax, ax
|
|
jmp short ret_int2f
|
|
|
|
remote_getfree:
|
|
clc ; set to succeed
|
|
int 2fh
|
|
pop di ; retrieve pushed pointer arg
|
|
jc ret_set_ax_to_carry
|
|
mov [di],ax
|
|
mov [di+2],bx
|
|
mov [di+4],cx
|
|
mov [di+6],dx
|
|
mov [di+8],si ; for REM_GETLARGEFREE, unused on REM_GETFREE
|
|
jmp short ret_set_ax_to_carry
|
|
|
|
remote_rw:
|
|
clc ; set to succeed
|
|
int 2fh
|
|
jc ret_min_dx_ax
|
|
xor dx, dx ; dx:ax := dx:cx = bytes read
|
|
jmp short ret_set_ax_to_cx
|
|
ret_min_dx_ax: neg ax
|
|
cwd
|
|
jmp short ret_int2f
|
|
|
|
qremote_fn:
|
|
mov bx, cx
|
|
lds si, [bx]
|
|
jmp short int2f_restore_ds
|
|
|
|
remote_process_end: ; Terminate process
|
|
mov ds, [_cu_psp]
|
|
int2f_restore_ds:
|
|
clc
|
|
int 2fh
|
|
push ss
|
|
pop ds
|
|
jmp short ret_set_ax_to_carry
|
|
|
|
; extern UWORD ASMPASCAL call_nls(UWORD bp, UWORD FAR *buf,
|
|
; UWORD subfct, UWORD cp, UWORD cntry, UWORD bufsize);
|
|
|
|
extern _nlsInfo
|
|
global CALL_NLS
|
|
CALL_NLS:
|
|
pop es ; ret addr
|
|
pop cx ; bufsize
|
|
pop dx ; cntry
|
|
pop bx ; cp
|
|
pop ax ; sub fct
|
|
mov ah, 0x14
|
|
push es ; ret addr
|
|
push bp
|
|
mov bp, sp
|
|
push si
|
|
push di
|
|
mov si, _nlsInfo ; nlsinfo
|
|
les di, [bp + 4] ; buf
|
|
mov bp, [bp + 8] ; bp
|
|
int 0x2f
|
|
mov dx, bx ; return id in high word
|
|
pop di
|
|
pop si
|
|
pop bp
|
|
ret 6
|
|
|
|
; extern UWORD ASMPASCAL floppy_change(UWORD drives)
|
|
|
|
global FLOPPY_CHANGE
|
|
FLOPPY_CHANGE:
|
|
pop cx ; ret addr
|
|
pop dx ; drives
|
|
push cx ; ret addr
|
|
mov ax, 0x4a00
|
|
xor cx, cx
|
|
int 0x2f
|
|
mov ax, cx ; return
|
|
ret
|
|
|
|
;
|
|
; Test to see if a umb driver has been loaded.
|
|
; if so, retrieve largest available block+size
|
|
;
|
|
; From RB list and Dosemu xms.c.
|
|
;
|
|
; Call the XMS driver "Request upper memory block" function with:
|
|
; AH = 10h
|
|
; DX = size of block in paragraphs
|
|
; Return: AX = status
|
|
; 0001h success
|
|
; BX = segment address of UMB
|
|
; DX = actual size of block
|
|
; 0000h failure
|
|
; BL = error code (80h,B0h,B1h) (see #02775)
|
|
; DX = largest available block
|
|
;
|
|
; (Table 02775)
|
|
; Values for XMS error code returned in BL:
|
|
; 00h successful
|
|
; 80h function not implemented
|
|
; B0h only a smaller UMB is available
|
|
; B1h no UMBs are available
|
|
; B2h UMB segment number is invalid
|
|
;
|
|
|
|
segment INIT_TEXT
|
|
; int ASMPASCAL UMB_get_largest(void FAR * driverAddress,
|
|
; UCOUNT * seg, UCOUNT * size);
|
|
arg {driverAddress,4}, argseg, size
|
|
global UMB_GET_LARGEST
|
|
|
|
UMB_GET_LARGEST:
|
|
push bp
|
|
mov bp,sp
|
|
|
|
mov dx,0xffff ; go for broke!
|
|
mov ax,1000h ; get the UMBs
|
|
call far [.driverAddress] ; Call the driver
|
|
|
|
;
|
|
; bl = 0xB0 and ax = 0 so do it again.
|
|
;
|
|
cmp bl,0xb0 ; fail safe
|
|
jne umbt_error
|
|
|
|
and dx,dx ; if it returns a size of zero.
|
|
je umbt_error
|
|
|
|
mov ax,1000h ; dx set with largest size
|
|
call far [.driverAddress] ; Call the driver
|
|
|
|
cmp ax,1
|
|
jne umbt_error
|
|
; now return the segment
|
|
; and the size
|
|
|
|
mov cx,bx ; *seg = segment
|
|
mov bx, [.argseg]
|
|
mov [bx],cx
|
|
|
|
mov bx, [.size] ; *size = size
|
|
mov [bx],dx
|
|
|
|
umbt_ret:
|
|
pop bp
|
|
ret 8 ; this was called NEAR!!
|
|
|
|
umbt_error: xor ax,ax
|
|
jmp short umbt_ret
|