summaryrefslogtreecommitdiffstats
path: root/private/nw/vwipxspx/tsr
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/nw/vwipxspx/tsr/asmmacro.inc343
-rw-r--r--private/nw/vwipxspx/tsr/debugmac.inc356
-rw-r--r--private/nw/vwipxspx/tsr/makefile159
-rw-r--r--private/nw/vwipxspx/tsr/segorder.inc113
-rw-r--r--private/nw/vwipxspx/tsr/vwipxspx.asm711
5 files changed, 1682 insertions, 0 deletions
diff --git a/private/nw/vwipxspx/tsr/asmmacro.inc b/private/nw/vwipxspx/tsr/asmmacro.inc
new file mode 100644
index 000000000..0b7b2db16
--- /dev/null
+++ b/private/nw/vwipxspx/tsr/asmmacro.inc
@@ -0,0 +1,343 @@
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; asmmacro.inc
+;
+;Abstract:
+;
+; Contains macros to extend masm functionality:
+;
+; jmpc
+; jmpnc
+; jmpne
+; jmps
+; _mkjmp
+;
+;
+;Author:
+;
+; Richard L Firth (rfirth) 24-Sep-1991
+;
+;Environment:
+;
+; DOS application mode only
+;
+;Revision History:
+;
+; 24-Sep-1991 rfirth
+; Created
+;
+;--
+
+
+
+DEFINED_BIT=020h
+;ISDEFINED equ %(.type <thing> and DEFINED_BIT)
+LABEL_DEFINED equ <(.type &label and DEFINED_BIT)>
+
+DEBUG_MACROS = 0
+;DEBUG_MACROS = 1
+
+
+;*** jmpa
+;*
+;* jump to label if above. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpa macro label
+ _mkjmp ja,jna,&label
+endm
+
+;*** jmpc
+;*
+;* jump to label if below. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpb macro label
+ _mkjmp jb,jnb,&label
+endm
+
+;*** jmpc
+;*
+;* jump to label if carry flag set. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpc macro label
+ _mkjmp jc,jnc,&label
+endm
+
+
+
+;*** jmpnc
+;*
+;* jump to label if carry flag NOT set. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpnc macro label
+ _mkjmp jnc,jc,&label
+endm
+
+
+
+;*** jmpne
+;*
+;* jump to label if zero flag NOT set. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpne macro label
+ _mkjmp jne,je,&label
+endm
+
+
+
+;*** jmpe
+;*
+;* jump to label if zero flag set. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmpe macro label
+ _mkjmp je,jne,&label
+endm
+
+
+
+;*** jmps
+;*
+;* jump to label. Label can be short (+129, -126 from
+;* the first byte of the current jump instruction, if it is a short - ie
+;* byte - jump) or near
+;*
+;* ENTRY label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+jmps macro label
+ local l,dist
+dist=&label-$
+if1
+if (.type label and DEFINED_BIT)
+if ((dist gt 129) or (dist lt -126))
+if DEBUG_MACROS
+ %out pass1: &label defined and near
+endif
+ jmp &label
+else
+if DEBUG_MACROS
+ %out pass1: &label defined and short
+endif
+ jmp short &label
+endif
+else
+if DEBUG_MACROS
+ %out pass1: &label not defined
+endif
+ org $+3
+endif
+else
+if ((dist gt 129) or (dist lt -126))
+if DEBUG_MACROS
+ %out pass2: &label defined and near
+endif
+ jmp &label
+else
+if DEBUG_MACROS
+ %out pass2: &label defined and short
+endif
+ jmp short &label
+ org $+1
+endif
+endif
+l:
+endm
+
+
+
+;*** _mkjmp
+;*
+;* Make a jmp<?> macro. Generate instruction sequence for jump with or
+;* without conditional test. Jump may be short (+127/-128 bytes) or near
+;* (+32767/-32768 bytes)
+;*
+;* ENTRY is - short jump instruction
+;* in - near jump instruction
+;* label - to jump to
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+_put macro s,v
+if2
+if DEBUG_MACROS
+%out s = v
+endif
+endif
+endm
+
+_mkjmp macro is, in, label
+ local l
+
+;;
+;; if pass 1 and label is already known, generate correct instruction
+;;
+
+if1
+if (.type &label and DEFINED_BIT)
+
+;;
+;; if label is too far away for short jump instruction, make jump <condition>
+;; into jump <NOT condition> round jump to label followed by a near jump to
+;; label
+;;
+
+if (((&label - $) gt 129) or ((&label - $) lt -126))
+ &in l ;; short jump, NOT condition
+ jmp &label ;; jump to where we want to go
+else
+ &is &label ;; short jump
+endif
+
+;;
+;; if pass 1 and we don't know about the label yet, adjust the program
+;; counter by the max. number of bytes taken up by this macro (5 - 2 for
+;; short jump, 3 for near jump)
+;;
+
+else
+ nop
+ nop
+ nop
+ nop
+ nop
+endif
+
+;;
+;; pass 2 - do same stuff as for pass 1
+;;
+
+else
+if (((&label - $) gt 129) or ((&label - $) lt -126))
+ if ((&label-$) gt 129)
+ _put <label distance>, %(&label-$)
+ else
+ _put <label distance>, %($-&label)
+ endif
+ &in l
+ jmp &label
+else
+
+;;
+;; label is within +127/-128 bytes of current instruction - generate short
+;; jump instruction and put the program counter forward past the space
+;; reserved during pass 1
+;;
+
+ _put <label distance>, %(&label-$)
+ &is &label
+ nop
+ nop
+ nop
+endif
+endif
+l:
+endm
+
+
+
+oldjmps macro label
+if2
+if (((&label - $) gt 127) or (($ - &label) lt -128))
+ jmp short l
+ jmp &label
+else
+ jmp short &label
+ org $+3
+endif
+else
+;;
+;; if this is pass 1 just take up max amount of space so phases don't get
+;; screwed
+;;
+ org $+5
+endif
+l:
+endm
diff --git a/private/nw/vwipxspx/tsr/debugmac.inc b/private/nw/vwipxspx/tsr/debugmac.inc
new file mode 100644
index 000000000..45fe236e5
--- /dev/null
+++ b/private/nw/vwipxspx/tsr/debugmac.inc
@@ -0,0 +1,356 @@
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; debugmac.inc
+;
+;Abstract:
+;
+; Contains debugging macros:
+;
+; DbgBreakPoint
+; DbgUnsupported
+; DbgDEBUG
+; DbgPrint
+; DbgPrintTty
+; DbgPrintString
+; DbgPrintHexDword
+; DbgPrintHexWord
+; DbgPrintHexByte
+; DbgPrintNearPointer
+; DbgPrintFarPointer
+;
+;Author:
+;
+; Richard L Firth (rfirth) 13-Sep-1991
+;
+;Environment:
+;
+; DOS application mode only
+;
+;[Notes:]
+;
+; optional-notes
+;
+;Revision History:
+;
+; 13-Sep-1991 rfirth
+; Created
+;
+;--
+
+
+;*** DbgBreakPoint
+;*
+;* Same as NT routine of same name. No-op in non-DEBUG version
+;*
+;* ENTRY
+;*
+;* EXIT
+;*
+;* RETURNS
+;*
+;* ASSUMES
+;*
+;***
+
+DbgBreakPoint macro
+if DEBUG
+ int 3
+endif
+endm
+
+;*** DbgUnsupported
+;*
+;* Causes the 32-bit support code to display a message about an unsupported
+;* service code, and dumps the 16-bit registers. Used to discover when an
+;* unsupported int 2f/11 call or int 21/5f call is being made
+;*
+;* ENTRY
+;*
+;* EXIT
+;*
+;* RETURNS
+;*
+;* ASSUMES
+;*
+;***
+
+DbgUnsupported macro
+if DEBUG
+ SVC -1
+endif
+endm
+
+;*** DbgDEBUG
+;*
+;* Prints the string "DEBUG: " to console using Bios Int 10h/ah=0eh
+;*
+;* ENTRY nothing
+;*
+;* EXIT nothing
+;*
+;* USES ax
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgDEBUG macro
+ mov ax,(14 shl 8) + 'D'
+ int 10h
+ mov al,'E'
+ int 10h
+ mov al,'B'
+ int 10h
+ mov al,'U'
+ int 10h
+ mov al,'G'
+ int 10h
+ mov al,':'
+ int 10h
+ mov al,' '
+ int 10h
+endm
+
+
+
+;*** DbgCrLf
+;*
+;* Prints CR,LF to console using Bios Int 10h/ah=0eh
+;*
+;* ENTRY nothing
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgCrLf macro
+ push ax
+ mov ax,(14 shl 8) + 13
+ int 10h
+ mov al,10
+ int 10h
+ pop ax
+endm
+
+
+
+;*** DbgPrint
+;*
+;* Prints an ASCIZ string to console using Bios Int 10h
+;*
+;* ENTRY string - address of ASCIZ string to print
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrint macro string
+if DEBUG ;; no macro if not debug version
+ pushf ;; save regs used by DbgPrintTty
+ push ax
+ push bx
+ push si
+ push ds
+ mov ax,seg string
+ mov ds,ax
+ mov si,offset string;; ds:si = address of string
+ DbgPrintTty ;; display it on console
+ pop ds
+ pop si
+ pop bx
+ pop ax
+ popf
+endif
+endm
+
+
+
+;*** DbgPrintTty
+;*
+;* Prints an ASCIZ string in ds:si to console using Bios Int 10h
+;*
+;* ENTRY page - if present defines which Bios video page to use
+;* Defaults to 0
+;* ds:si - address of ASCIZ string to print
+;*
+;* EXIT nothing
+;*
+;* USES al, bh, si, flags
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintTty macro page
+ local l1,l2
+
+if DEBUG ;; no macro if not debug version
+ mov ah,14 ;; Bios Int write character as TTY function
+ifb <page>
+ sub bh,bh
+else
+ mov bh,page
+endif
+ cld ;; autoincrement lodsb
+l1: lodsb ;; al := next character; si := next character addr
+ or al,al ;; eof string?
+ jz l2 ;; yes
+ int 10h ;; display it to console
+ jmp short l1 ;; go round again
+l2:
+endif
+endm
+
+
+
+;*** DbgPrintString
+;*
+;* Prints a string to console using Bios Int 10h. Note that this macro
+;* does not do printf style substitutions. The string "DEBUG: " will be
+;* displayed if the banner parm is not blank
+;*
+;* ENTRY string - character string. Needn't be zero-terminated
+;* banner - the "DEBUG: " banner will be printed if not blank
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintString macro string, banner
+ local s1
+ local l1
+
+if DEBUG ;; no macro if not debug version
+ jmp short l1
+s1 db &string,0
+l1: pushf ;; don't destroy direction flag
+ pusha ;; save gp regs
+ifb <banner>
+ DbgDEBUG ;; Display "DEBUG: "
+endif
+ push ds ;; save user's data seg
+ push cs
+ pop ds ;; ds == cs
+ mov si,offset cs:s1 ;; si := string offset
+ DbgPrintTty ;; display ds:si to console
+ pop ds ;; restore user's data seg
+ popa ;; restore gp regs
+ popf ;; restore direction flag+
+endif
+endm
+
+
+
+;*** DbgPrintHexDword
+;*
+;* Prints a dword to console in hex notation using Bios Int 10h
+;*
+;* ENTRY dword - dword to print
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintHexDword macro dword
+if DEBUG ;; no macro if not debug version
+ DbgPrint <"DbgPrintHexDword not implemented yet",13,10>
+endif
+endm
+
+
+
+;*** DbgPrintHexWord
+;*
+;* Prints a word to console in hex notation using Bios Int 10h
+;*
+;* ENTRY word - to print. Can be memory or register
+;*
+;* EXIT nothing
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintHexWord macro word
+ local l1, l2
+if DEBUG ;; no macro if not debug version
+ pushf ;; don't use any registers
+ push ax
+ push cx
+ push dx
+ifdifi <word>,<ax>
+ mov ax,word
+endif
+ mov cx,4
+l1: rol ax,4
+ mov dx,ax
+ and al,0fh
+ cmp al,9
+ jle l2
+ add al,'a'-('9'+1)
+l2: add al,'0'
+ mov ah,14
+ int 10h
+ mov ax,dx
+ loop l1
+ pop dx
+ pop cx
+ pop ax
+ popf
+endif
+endm
+
+
+
+;*** DbgPrintHexByte
+;*
+;* Prints a string to console using Bios Int 10h. Note that this macro
+;* does not do printf style substitutions
+;*
+;* ENTRY string - character string. Needn't be zero-terminated
+;*
+;* EXIT
+;*
+;* USES nothing
+;*
+;* ASSUMES 286+
+;*
+;***
+
+DbgPrintHexByte macro byte
+if DEBUG ;; no macro if not debug version
+ DbgPrint <"DbgPrintHexByte not implemented yet",13,10>
+endif
+endm
+
+
+
+DbgPrintNearPointer macro nearptr
+endm
+
+
+
+DbgPrintFarPointer macro farptr
+endm
diff --git a/private/nw/vwipxspx/tsr/makefile b/private/nw/vwipxspx/tsr/makefile
new file mode 100644
index 000000000..cd181de7d
--- /dev/null
+++ b/private/nw/vwipxspx/tsr/makefile
@@ -0,0 +1,159 @@
+!IF 0
+
+Copyright (c) 1991 & 1993 Microsoft Corporation
+
+Module Name:
+
+ makefile
+
+Abstract:
+
+ makefile for Vdm NetWare Redir program
+
+Author:
+
+ Richard L Firth (rfirth) 13-Sep-1991
+
+Revision History:
+
+ 13-Sep-1991 rfirth
+ Created
+
+!ENDIF
+
+
+
+.SUFFIXES:
+.SUFFIXES: .asm .h
+
+OBJPATH = obj
+
+ASM = masm
+!IFDEF NTVDM_BASED_BUILD
+LINK = link16
+!ELSE
+LINK = link
+!ENDIF
+
+#
+# set the country info
+#
+
+!IFNDEF COUNTRY
+COUNTRY=usa
+!ENDIF
+
+#
+# convert NTDEBUG into DEBUG flag. NTDEBUG can be not present or retail, either
+# of which mean no debugging; or ntsd, cvp or sym, which means debugging support
+# required
+#
+
+!IFDEF NTDEBUG
+!IF "$(NTDEBUG)" == "retail"
+DEBUGGING=0
+!ELSE
+DEBUGGING=1
+!ENDIF
+!ELSE
+DEBUGGING=0
+!ENDIF
+
+#
+# assembler and linker debugging options
+#
+
+!IF $(DEBUGGING)
+ASMDEBUG = /DDEBUG=1 /Zi
+LINKDEBUG = /CO
+!ELSE
+ASMDEBUG = /DDEBUG=0
+LINKDEBUG =
+!ENDIF
+ASMINC = /I. /I..\..\inc /I..\..\..\mvdm\dos\v86\inc /I\nt\public\sdk\inc
+ASMFLAGS = /Mx
+LINKFLAGS = /MAP /CP:1
+
+#
+# any other non-debug related options (for assembler) go in USERDEFS
+#
+
+USERDEFS = /DCALL_DOS
+
+#
+# Inference rules - asm to obj, h to inc
+#
+
+.asm{$(OBJPATH)\}.obj:
+ $(ASM) $(ASMINC) $(ASMDEBUG) $(USERDEFS) $<,$@;
+
+.h.inc:
+ h2inc $< -o $*.inc
+
+.asm.lst:
+ $(ASM) $(ASMINC) $(ASMDEBUG) $(USERDEFS) /d /L $<;
+
+#
+# what it is we're building
+#
+
+TARGET = $(OBJPATH)\vwipxspx.exe
+MAPFILE = $(TARGET:.exe=.map)
+DEFFILE = ;
+
+OBJS = $(OBJPATH)\vwipxspx.obj
+
+LIBS =
+
+#
+# how to build it
+#
+
+all: makedir $(TARGET)
+
+$(TARGET): $(OBJS)
+ $(LINK) @<<
+$(OBJS)
+$(TARGET) $(LINKFLAGS) $(LINKDEBUG)
+$(MAPFILE)
+$(LIBS)
+$(DEFFILE)
+<<
+
+#
+# where to put it
+#
+
+ binplace $(TARGET)
+
+#
+# clean build - delete all objs
+#
+
+#clean: makedir clean2
+clean: clean2
+
+clean2:
+ if exist $(OBJPATH)\*.obj del $(OBJPATH)\*.obj
+ $(MAKE)
+
+#
+# makedir - ensure the subdirectory for the object files exists
+#
+
+makedir:
+ @-if not exist $(OBJPATH) md $(OBJPATH)
+
+#
+# file dependencies
+#
+
+$(OBJPATH)\vwipxspx.obj:\
+ vwipxspx.asm \
+ debugmac.inc \
+ asmmacro.inc \
+ segorder.inc \
+ messages.inc
+
+messages.inc: ..\..\inc\$(COUNTRY)\messages.inc
+ copy ..\..\inc\$(COUNTRY)\messages.inc .
diff --git a/private/nw/vwipxspx/tsr/segorder.inc b/private/nw/vwipxspx/tsr/segorder.inc
new file mode 100644
index 000000000..689c62fa2
--- /dev/null
+++ b/private/nw/vwipxspx/tsr/segorder.inc
@@ -0,0 +1,113 @@
+;/*++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; segorder.inc
+;
+;Abstract:
+;
+; This module contains the segment order and segment macros
+;
+;Author:
+;
+; Richard Firth (rfirth) 05-Sep-1991
+;
+;Environment:
+;
+; Dos mode only
+;
+;Notes:
+;
+; When initially loaded, the NT VDM redir has the following order:
+;
+; +----------------------+
+; | |
+; | Resident Code |
+; | |
+; +----------------------+
+; | |
+; | Resident Data |
+; | |
+; +----------------------+ ----------------+
+; | | |
+; | Initialisation Code | <- entry point v
+; | |
+; +----------------------+
+; | | all the stuff between these
+; | Initialisation Data | arrows is discarded if we stay
+; | | resident. Note that the redir
+; +----------------------+ does not uninstall
+; | |
+; | Initialisation Stack | ^
+; | | |
+; +----------------------+ ----------------+
+;
+;Revision History:
+;
+; 05-Sep-1991 rfirth
+; Created
+;
+;--*/
+
+
+
+ResidentStart segment public para 'code'
+ResidentStart ends
+
+ResidentCode segment public word 'code'
+ResidentCode ends
+
+ResidentData segment public word 'data'
+ResidentData ends
+
+ResidentEnd segment public para 'data'
+ResidentEnd ends
+
+ResidentGroup group ResidentStart, ResidentCode, ResidentData, ResidentEnd
+
+InitCode segment public para 'init'
+InitCode ends
+
+InitData segment public word 'init'
+InitData ends
+
+InitStack segment stack para 'stack'
+InitStack ends
+
+;
+; macros to avoid having to type in/possibly alter segment header guff
+;
+
+ResidentCodeStart macro
+ResidentCode segment public word 'code'
+endm
+
+ResidentCodeEnd macro
+ResidentCode ends
+endm
+
+ResidentDataStart macro
+ResidentData segment public word 'data'
+endm
+
+ResidentDataEnd macro
+ResidentData ends
+endm
+
+InitCodeStart macro
+InitCode segment public para 'init'
+endm
+
+InitCodeEnd macro
+InitCode ends
+endm
+
+InitDataStart macro
+InitData segment public word 'init'
+endm
+
+InitDataEnd macro
+InitData ends
+endm
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