FreeDOS/kernel/int2f.asm
Andrew Bird fa3dc59367 DosGetExtFree: Use new redirector function 11a3
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.
2023-03-21 20:54:17 -04:00

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