diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/nw/vwipxspx/tsr/vwipxspx.asm | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to '')
-rw-r--r-- | private/nw/vwipxspx/tsr/vwipxspx.asm | 711 |
1 files changed, 711 insertions, 0 deletions
diff --git a/private/nw/vwipxspx/tsr/vwipxspx.asm b/private/nw/vwipxspx/tsr/vwipxspx.asm new file mode 100644 index 000000000..601f80c10 --- /dev/null +++ b/private/nw/vwipxspx/tsr/vwipxspx.asm @@ -0,0 +1,711 @@ +page ,132 +if 0 + +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + vwipxspx.asm + +Abstract: + + Contains handlers for 16-bit (DOS) netware IPX/SPX emulation. Creates TSR + + Contents: + start + InstallationCheck + InstallVdd + InstallInterruptHandlers + VwIpxEntryPoint + VwIpxDispatcher + VwIpx7ADispatcher + DispatchWithFeeling + VwIpxEsrFunction + +Author: + + Richard L Firth (rfirth) 30-Sep-1993 + +Environment: + + DOS Real mode only + +Revision History: + + 30-Sep-1993 rfirth + Created + +--*/ + +endif + +; +; DOS include files +; + +.xlist +.xcref +include isvbop.inc ; NTVDM BOP mechanism +include dossym.inc ; includes MS-DOS version etc +include pdb.inc ; PSP defines +include syscall.inc ; AssignOper +include segorder.inc ; load order of 'redir' segments +include debugmac.inc ; debug display macros +include asmmacro.inc ; jumps which may be short or near +include messages.inc ; internationalisationable (prestidigitation) messages +.cref +.list + +InitStack segment stack para 'stack' + + dw 256 dup (?) + +InitStack ends + +InitDataStart + +bad_ver_msg db NLS_MSG_001,c_CR,c_LF +BAD_VER_MSG_LEN equ $-bad_ver_msg + db '$' ; for INT 21/09 display string + +already_loaded_msg db NLS_MSG_002,c_CR,c_LF +ALREADY_LOADED_MSG_LEN equ $-already_loaded_msg + +cannot_load_msg db NLS_MSG_003,c_CR, c_LF +CANNOT_LOAD_MSG_LEN equ $-cannot_load_msg + +; +; strings used to load/dispatch NWIPXSPX.DLL +; + +DllName db "VWIPXSPX.DLL",0 +InitFunc db "VwInitialize",0 +DispFunc db "VwDispatcher",0 + +InitDataEnd + +InitCodeStart + assume cs:InitCode + assume ds:nothing + assume es:nothing + assume ss:nothing + + public start +start proc near + +; +; when we start up we could be on any old PC - even an original, so don't +; assume anything other than a model-T processor +; + + .8086 + +; +; Set the data segment while we're at it - all paths set it sooner +; or later. NOTE: es will point to the PSP until we change it! +; + + mov dx,InitData + mov ds,dx + + assume ds:InitData + +; +; first off, get the DOS version. If we're not running on NT (VDM) then this +; TSR's not going to do much, so exit. Exit using various methods, depending +; on the DOS version (don't you hate compatibility?) +; + + mov ah,30h + int 21h + jc ancient_version ; version not even supported + +; +; version is 2.0 or higher. Check it out. al = major#, ah = minor# +; + + cmp al,major_version + jne invalid_version + +; +; okay, we're at least 5.0. But are we NT? +; + + mov ax,3306h + int 21h + jc invalid_version ; ? + cmp bl,5 + jne invalid_version + cmp bh,50 + jne invalid_version + +; +; what do you know? We're actually running on NT (unless some evil programmer +; has pinched int 21h/30h and broken it!). Enable minimum instruction set +; for NTVDM (286 on RISC). +; + + .286c + +; +; perform an installation check. Bail if we're there dude ((C) Beavis & Butthead) +; + + call InstallationCheck + jnz already_here ; nope - IPX/SPX support installed already + +; +; BUGBUG: we should find some way of deferring loading the 32-bit DLL until an +; IPX/SPX function is called, to speed-up loading. However, if we later find we +; cannot load the DLL, it may be too late: there is no way of consistently +; returning an error and we cannot unload the TSR +; + + call InstallVdd ; returns IRQ in BX + jc initialization_error + call InstallInterruptHandlers + + assume es:nothing + +; +; free the environment segment +; + + mov es,es:[PDB_environ] + mov ah,49h + int 21h ; free environment segment + +; +; finally terminate and stay resident +; + + mov dx,ResidentEnd + sub dx,ResidentStart ; number of paragraphs in resident code + add dx,10h ; additional for PSP (PDB) + mov ax,3100h + int 21h ; terminate and stay resident + +; +; here if the MS-DOS version check (Ah=30h) call is not supported +; + +ancient_version: + mov dx,InitData + mov ds,dx + + assume ds:InitData + + mov dx,offset bad_ver_msg + mov ah,9 ; cp/m-style write to output + int 21h + +; +; safe exit: what we really want to do here is INT 20H, but when you do this, +; CS must be the segment of the PSP of this program. Knowing that CD 20 is +; embedded at the start of the PSP, the most foolproof way of doing this is +; to jump (using far return) to the start of the PSP +; + + push es + xor ax,ax + push ax + retf ; terminate + +; +; we are running on a version of DOS >= 2.00, but its not NT, so we still can't +; help. Display the familiar message and exit, but using a less programmer- +; hostile mechanism +; + +invalid_version: + mov dx,offset bad_ver_msg + mov cx,BAD_VER_MSG_LEN + jmp short print_error_message_and_exit + +; +; if we cannot initialize 32-bit support (because we can't find/load the DLL) +; then put back the hooked interrupt vectors as they were when this TSR started, +; display a message and fail to load the redir TSR +; + +initialization_error: + mov dx,offset cannot_load_msg + mov cx,CANNOT_LOAD_MSG_LEN + jmp short print_error_message_and_exit + +; +; The DOS version's OK, but this TSR is already loaded +; + +already_here: + mov dx,offset already_loaded_msg + mov cx,ALREADY_LOADED_MSG_LEN + +print_error_message_and_exit: + mov bx,1 ; bx = stdout handle + mov ah,40h ; write to handle + int 21h ; write (cx) bytes @ (ds:dx) to stdout + mov ax,4c01h ; terminate program + int 21h ; au revoir, cruel environment + +start endp + +; *** InstallationCheck +; * +; * Test to see if this module is already loaded +; * +; * ENTRY nothing +; * +; * EXIT ZF = 0: loaded +; * +; * USES AX +; * +; * ASSUMES nothing +; * +; *** + +InstallationCheck proc + mov ax,7a00h + int 2fh + or al,al + ret +InstallationCheck endp + +; *** InstallVdd +; * +; * Load VWIPXSPX.DLL into the NTVDM process context +; * +; * ENTRY nothing +; * +; * EXIT CF = 1: error +; * CF = 0: VWIPXSPX loaded ok +; * AX = VDD handle +; * BX = IRQ used by call-back functions (ESR) +; * ResidentCode:VddHandle updated +; * ResidentCode:IrqValue updated +; * +; * USES AX, BX, SI, DI +; * +; * ASSUMES nothing +; * +; *** + +InstallVdd proc + push ds + push es + mov ax,InitData + mov ds,ax + + assume ds:InitData + + mov es,ax + mov si,offset DllName ; ds:si = library name + mov di,offset InitFunc ; es:di = init function name + mov bx,offset DispFunc ; ds:bx = dispatcher function name + + RegisterModule ; returns carry if problem + + mov si,ResidentCode + mov ds,si + + assume ds:ResidentCode + + mov VddHandle,ax + mov IrqValue,bx + pop es + + assume es:nothing + + pop ds + + assume ds:nothing + + ret +InstallVdd endp + +; *** InstallInterruptHandlers +; * +; * Sets the interrupt handlers for all the ints we use - 2F, 7A +; * +; * ENTRY BX = IRQ for call-backs +; * ES = PSP segment +; * +; * EXIT Old2FHandler contains the original interrupt 2F vector +; * Old7AHandler contains the original interrupt 7A vector +; * OldIrqHandler contains original IRQ vector +; * +; * USES AX, BX, CX, DX +; * +; * ASSUMES nothing +; * +; *** + +InstallInterruptHandlers proc + push es ; PSP segment - destroyed by INT 21/35h + push ds + mov dx,ResidentCode + mov ds,dx + + assume ds:ResidentCode + +; +; get and set call-back IRQ +; + + mov ah,35h + mov al,bl + mov cl,bl ; cl = IRQ number + int 21h + mov word ptr OldIrqHandler,bx + mov word ptr OldIrqHandler+2,es + mov al,cl + mov ah,25h + mov dx,offset ResidentCode:VwIpxEsrFunction + int 21h + +; +; get and set 2F handler +; + + mov ax,352Fh + int 21h + mov word ptr Old2FHandler,bx + mov word ptr Old2FHandler+2,es + mov dx,offset ResidentCode:VwIpxEntryPoint + mov ax,252Fh + int 21h + +; +; get and set 7A handler +; + + mov ax,357Ah + int 21h + mov word ptr Old7AHandler,bx + mov word ptr Old7AHandler+2,es + mov dx,offset ResidentCode:VwIpx7ADispatcher + mov ax,257Ah + int 21h + pop ds ; restore segment registers + + assume ds:nothing + + pop es + + assume es:nothing + + ret +InstallInterruptHandlers endp + +InitCodeEnd + +page + +; +; code from here on will be left in memory after initialisation +; + +ResidentCodeStart + + assume cs:ResidentCode + assume ds:nothing + assume es:nothing + assume ss:nothing + +Old2FHandler dd ? +Old7AHandler dd ? +OldIrqHandler dd ? + +IrqValue dw ? + +VddHandle dw ? + +; *** VwIpxEntryPoint +; * +; * The INT 2Fh handler that recognizes the Netware IPX request code (7A). +; * Also chains INT 2F/AX=1122 +; * +; * ENTRY AX = 7A00h +; * +; * EXIT AL = 0FFh +; * ES:DI = address of routine to call when submitting IPX/SPX +; * requests +; * +; * USES +; * +; * ASSUMES nothing +; * +; *** + +VwIpxEntryPoint proc + cmp ax,7a00h + jne @f + mov di,cs + mov es,di + mov di,offset VwIpxDispatcher + dec al + iret + +; +; not 7A00h. Check for 1122h (IFSResetEnvironment). If yes, then this is DOS +; calling the IFS chain to notify that the app is terminating. When we have +; notified the DLL, chain the IFS request +; + +@@: cmp ax,7affh + jne try1122 + mov di,cs + mov es,di + mov di,offset VwIpxDispatcher + or bx,bx + jz @f + mov cx,8000h + mov si,7 + iret +@@: mov cx,14h + mov si,200h + iret + +try1122:cmp ax,1122h + jne @f + +; +; DOS Calls INT 2F/AX=1122 for every terminating app, including this one. We +; can't differentiate between a TSR and a non-TSR. Let the DLL handle it +; + + push ax + push bx + push cx + mov ah,51h + int 21h + mov cx,bx ; cx = PDB of terminating program/TSR + mov bx,-1 ; bx = dispatch code + mov ax,VddHandle ; ax = VDD handle + DispatchCall + pop cx + pop bx + pop ax +@@: jmp Old2FHandler ; chain int 2F +VwIpxEntryPoint endp + +; *** VwIpxDispatcher +; * +; * All DOS IPX/SPX calls are routed here by the netware libraries. Just +; * BOP on through to the other side +; * +; * This routine just transfers control to 32-bit world, where all work is +; * done +; * +; * ENTRY BX = netware IPX/SPX dispatch code +; * others - depends on function +; * +; * EXIT depends on function +; * +; * USES depends on function +; * +; * ASSUMES nothing +; * +; *** + +VwIpxDispatcher proc far + pushf ; apparently we don't modify flags + call DispatchWithFeeling + popf + ret +VwIpxDispatcher endp + +; *** VwIpx7ADispatcher +; * +; * Older Netware apps make the call to IPX/SPX via INT 7A. Same function +; * as VwIpxDispatcher +; * +; * This routine just transfers control to 32-bit world, where all work is +; * done +; * +; * ENTRY BX = netware IPX/SPX dispatch code +; * others - depends on function +; * +; * EXIT depends on function +; * +; * USES depends on function +; * +; * ASSUMES nothing +; * +; *** + +VwIpx7ADispatcher proc + call DispatchWithFeeling + iret +VwIpx7ADispatcher endp + +; *** DispatchWithFeeling +; * +; * Performs the dispatch for VrIpxDispatcher and VrIpx7ADispatcher. Checks +; * requested function for return code in AX: either returns value in AX +; * or restores AX to value on input +; * +; * This routine just transfers control to 32-bit world, where all work is +; * done +; * +; * ENTRY BX = netware IPX/SPX dispatch code +; * others - depends on function +; * +; * EXIT depends on function +; * +; * USES depends on function +; * +; * ASSUMES 1. Dispatch codes are in range 0..255 (ie 0 in BH) +; * +; *** + +DispatchWithFeeling proc + push bp + push ax ; caller value + +; +; some APIs (IPXOpenSocket, IPXScheduleIPXEvent, SPXEstablishConnection, and +; others...) pass a parameter in AX. Since AX is being used for the VDD +; handle, we have to commandeer another register to hold our AX value. BP is +; always a good candidate +; + + mov bp,ax ; grumble, mutter, gnash, gnash + push cx ; required if IPXOpenSocket + push bx ; dispatch code + or bx,bx ; IPXOpenSocket? + jz @f ; yus ma'am + cmp bl,3 ; IPXSendPacket? + jz @f ; yus ma'am again + jmp short carry_on_dispatching ; ooo-err missus + +; +; IPXOpenSocket et IPXSendPacket: We need an extra piece of info - the PDB of +; the process making this request. This is so we can clean-up at program +; termination +; + +@@: push bx + mov ah,51h ; get DOS PDB + int 21h ; this call can be made any time + mov cx,bx + pop bx + +carry_on_dispatching: + mov ax,VddHandle + DispatchCall + mov bp,sp + +; +; BX and [BP] will be the same value except for SPXInitialize which is the only +; function that returns something in BX +; + + xchg bx,[bp] ; bx = dispatch code, [bp] = returned bx + +; +; if this call returns something in AX (or AL) don't pop the AX value we pushed. +; If not a call which returns something in AX then restore the caller's AX. You +; can rest assured some assembler programmer has made use of the fact that some +; calls modify AX and the others leave it alone (presumably...?) +; + + or bl,bl ; 0x00 = IPXOpenSocket + jz @f + cmp bl,2 ; 0x02 = IPXGetLocalTarget + jz @f + cmp bl,4 ; 0x04 = IPXListenForPacket + jz @f + cmp bl,6 ; 0x06 = IPXCancelEvent + jz @f + cmp bl,8 ; 0x08 = IPXGetIntervalMarker + jz @f + cmp bl,10h ; 0x10 = SPXInitialize + jz spx_init + cmp bl,11h ; 0x11 = SPXEstablishConnection + jz @f + cmp bl,15h ; 0x15 = SPXGetConnectionStatus + jz @f + cmp bl,1ah ; 0x1A = IPXGetMaxPacketSize + jz @f + pop cx ; original dispatch code + pop cx ; original cx + pop ax ; original ax + pop bp ; original bp + ret + +; +; here if this call returns something in AX/AL +; + +@@: pop cx ; original dispatch code + pop cx ; original cx + pop bp ; don't restore AX + pop bp + ret + +; +; here if the call was SPXInitialize which returns values in AX, BX, CX, DX +; + +spx_init: + pop bx ; bx = major/minor SPX version # + pop bp ; caller cx - NOT restored + pop bp ; caller ax - NOT restored + pop bp ; caller bp - restored + ret +DispatchWithFeeling endp + +; *** VwIpxEsrFunction +; * +; * This routine makes the call to the ESR as defined in the ECB. We must +; * set up our stack, save the registers (except SS & SP), then call the +; * ESR. +; * +; * Control will not be transferred here for an ECB which has a NULL ESR +; * field +; * +; * ENTRY AL = 0 for AES or 0FFh for IPX +; * ES:SI = ECB address +; * +; * EXIT depends on function +; * +; * USES depends on function +; * +; * ASSUMES nothing +; * +; *** + +VwIpxEsrFunction proc + +; +; Novell documentation states all registers except SS and SP are saved before +; calling ESR and that INTERRUPTS ARE DISABLED +; + + pusha + push ds + push es + mov ax,VddHandle + mov bx,-2 + DispatchCall ; get ECB + jc @f + call dword ptr es:[si][4] ; branch to the ESR + mov al,20h + out 0a0h,al ; clear slave pic + out 20h,al ; " master " + pop es + pop ds + popa + iret +@@: pop es + pop ds + popa + jmp OldIrqHandler +VwIpxEsrFunction endp + +ResidentCodeEnd + +end start |