Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

711 lines
18 KiB

  1. page ,132
  2. if 0
  3. /*++
  4. Copyright (c) 1993 Microsoft Corporation
  5. Module Name:
  6. vwipxspx.asm
  7. Abstract:
  8. Contains handlers for 16-bit (DOS) netware IPX/SPX emulation. Creates TSR
  9. Contents:
  10. start
  11. InstallationCheck
  12. InstallVdd
  13. InstallInterruptHandlers
  14. VwIpxEntryPoint
  15. VwIpxDispatcher
  16. VwIpx7ADispatcher
  17. DispatchWithFeeling
  18. VwIpxEsrFunction
  19. Author:
  20. Richard L Firth (rfirth) 30-Sep-1993
  21. Environment:
  22. DOS Real mode only
  23. Revision History:
  24. 30-Sep-1993 rfirth
  25. Created
  26. --*/
  27. endif
  28. ;
  29. ; DOS include files
  30. ;
  31. .xlist
  32. .xcref
  33. include ..\..\..\..\public\sdk\inc\isvbop.inc ; NTVDM BOP mechanism
  34. include dossym.inc ; includes MS-DOS version etc
  35. include pdb.inc ; PSP defines
  36. include syscall.inc ; AssignOper
  37. include segorder.inc ; load order of 'redir' segments
  38. include debugmac.inc ; debug display macros
  39. include asmmacro.inc ; jumps which may be short or near
  40. include messages.inc ; internationalisationable (prestidigitation) messages
  41. .cref
  42. .list
  43. InitStack segment stack para 'stack'
  44. dw 256 dup (?)
  45. InitStack ends
  46. InitDataStart
  47. bad_ver_msg db NLS_MSG_001,c_CR,c_LF
  48. BAD_VER_MSG_LEN equ $-bad_ver_msg
  49. db '$' ; for INT 21/09 display string
  50. already_loaded_msg db NLS_MSG_002,c_CR,c_LF
  51. ALREADY_LOADED_MSG_LEN equ $-already_loaded_msg
  52. cannot_load_msg db NLS_MSG_003,c_CR, c_LF
  53. CANNOT_LOAD_MSG_LEN equ $-cannot_load_msg
  54. ;
  55. ; strings used to load/dispatch NWIPXSPX.DLL
  56. ;
  57. DllName db "VWIPXSPX.DLL",0
  58. InitFunc db "VwInitialize",0
  59. DispFunc db "VwDispatcher",0
  60. InitDataEnd
  61. InitCodeStart
  62. assume cs:InitCode
  63. assume ds:nothing
  64. assume es:nothing
  65. assume ss:nothing
  66. public start
  67. start proc near
  68. ;
  69. ; when we start up we could be on any old PC - even an original, so don't
  70. ; assume anything other than a model-T processor
  71. ;
  72. .8086
  73. ;
  74. ; Set the data segment while we're at it - all paths set it sooner
  75. ; or later. NOTE: es will point to the PSP until we change it!
  76. ;
  77. mov dx,InitData
  78. mov ds,dx
  79. assume ds:InitData
  80. ;
  81. ; first off, get the DOS version. If we're not running on NT (VDM) then this
  82. ; TSR's not going to do much, so exit. Exit using various methods, depending
  83. ; on the DOS version (don't you hate compatibility?)
  84. ;
  85. mov ah,30h
  86. int 21h
  87. jc ancient_version ; version not even supported
  88. ;
  89. ; version is 2.0 or higher. Check it out. al = major#, ah = minor#
  90. ;
  91. cmp al,major_version
  92. jne invalid_version
  93. ;
  94. ; okay, we're at least 5.0. But are we NT?
  95. ;
  96. mov ax,3306h
  97. int 21h
  98. jc invalid_version ; ?
  99. cmp bl,5
  100. jne invalid_version
  101. cmp bh,50
  102. jne invalid_version
  103. ;
  104. ; what do you know? We're actually running on NT (unless some evil programmer
  105. ; has pinched int 21h/30h and broken it!). Enable minimum instruction set
  106. ; for NTVDM (286 on RISC).
  107. ;
  108. .286c
  109. ;
  110. ; perform an installation check. Bail if we're there dude ((C) Beavis & Butthead)
  111. ;
  112. call InstallationCheck
  113. jnz already_here ; nope - IPX/SPX support installed already
  114. ;
  115. ; We should find some way of deferring loading the 32-bit DLL until an
  116. ; IPX/SPX function is called, to speed-up loading. However, if we later find we
  117. ; cannot load the DLL, it may be too late: there is no way of consistently
  118. ; returning an error and we cannot unload the TSR
  119. ;
  120. call InstallVdd ; returns IRQ in BX
  121. jc initialization_error
  122. call InstallInterruptHandlers
  123. assume es:nothing
  124. ;
  125. ; free the environment segment
  126. ;
  127. mov es,es:[PDB_environ]
  128. mov ah,49h
  129. int 21h ; free environment segment
  130. ;
  131. ; finally terminate and stay resident
  132. ;
  133. mov dx,ResidentEnd
  134. sub dx,ResidentStart ; number of paragraphs in resident code
  135. add dx,10h ; additional for PSP (PDB)
  136. mov ax,3100h
  137. int 21h ; terminate and stay resident
  138. ;
  139. ; here if the MS-DOS version check (Ah=30h) call is not supported
  140. ;
  141. ancient_version:
  142. mov dx,InitData
  143. mov ds,dx
  144. assume ds:InitData
  145. mov dx,offset bad_ver_msg
  146. mov ah,9 ; cp/m-style write to output
  147. int 21h
  148. ;
  149. ; safe exit: what we really want to do here is INT 20H, but when you do this,
  150. ; CS must be the segment of the PSP of this program. Knowing that CD 20 is
  151. ; embedded at the start of the PSP, the most foolproof way of doing this is
  152. ; to jump (using far return) to the start of the PSP
  153. ;
  154. push es
  155. xor ax,ax
  156. push ax
  157. retf ; terminate
  158. ;
  159. ; we are running on a version of DOS >= 2.00, but its not NT, so we still can't
  160. ; help. Display the familiar message and exit, but using a less programmer-
  161. ; hostile mechanism
  162. ;
  163. invalid_version:
  164. mov dx,offset bad_ver_msg
  165. mov cx,BAD_VER_MSG_LEN
  166. jmp short print_error_message_and_exit
  167. ;
  168. ; if we cannot initialize 32-bit support (because we can't find/load the DLL)
  169. ; then put back the hooked interrupt vectors as they were when this TSR started,
  170. ; display a message and fail to load the redir TSR
  171. ;
  172. initialization_error:
  173. mov dx,offset cannot_load_msg
  174. mov cx,CANNOT_LOAD_MSG_LEN
  175. jmp short print_error_message_and_exit
  176. ;
  177. ; The DOS version's OK, but this TSR is already loaded
  178. ;
  179. already_here:
  180. mov dx,offset already_loaded_msg
  181. mov cx,ALREADY_LOADED_MSG_LEN
  182. print_error_message_and_exit:
  183. mov bx,1 ; bx = stdout handle
  184. mov ah,40h ; write to handle
  185. int 21h ; write (cx) bytes @ (ds:dx) to stdout
  186. mov ax,4c01h ; terminate program
  187. int 21h ; au revoir, cruel environment
  188. start endp
  189. ; *** InstallationCheck
  190. ; *
  191. ; * Test to see if this module is already loaded
  192. ; *
  193. ; * ENTRY nothing
  194. ; *
  195. ; * EXIT ZF = 0: loaded
  196. ; *
  197. ; * USES AX
  198. ; *
  199. ; * ASSUMES nothing
  200. ; *
  201. ; ***
  202. InstallationCheck proc
  203. mov ax,7a00h
  204. int 2fh
  205. or al,al
  206. ret
  207. InstallationCheck endp
  208. ; *** InstallVdd
  209. ; *
  210. ; * Load VWIPXSPX.DLL into the NTVDM process context
  211. ; *
  212. ; * ENTRY nothing
  213. ; *
  214. ; * EXIT CF = 1: error
  215. ; * CF = 0: VWIPXSPX loaded ok
  216. ; * AX = VDD handle
  217. ; * BX = IRQ used by call-back functions (ESR)
  218. ; * ResidentCode:VddHandle updated
  219. ; * ResidentCode:IrqValue updated
  220. ; *
  221. ; * USES AX, BX, SI, DI
  222. ; *
  223. ; * ASSUMES nothing
  224. ; *
  225. ; ***
  226. InstallVdd proc
  227. push ds
  228. push es
  229. mov ax,InitData
  230. mov ds,ax
  231. assume ds:InitData
  232. mov es,ax
  233. mov si,offset DllName ; ds:si = library name
  234. mov di,offset InitFunc ; es:di = init function name
  235. mov bx,offset DispFunc ; ds:bx = dispatcher function name
  236. RegisterModule ; returns carry if problem
  237. mov si,ResidentCode
  238. mov ds,si
  239. assume ds:ResidentCode
  240. mov VddHandle,ax
  241. mov IrqValue,bx
  242. pop es
  243. assume es:nothing
  244. pop ds
  245. assume ds:nothing
  246. ret
  247. InstallVdd endp
  248. ; *** InstallInterruptHandlers
  249. ; *
  250. ; * Sets the interrupt handlers for all the ints we use - 2F, 7A
  251. ; *
  252. ; * ENTRY BX = IRQ for call-backs
  253. ; * ES = PSP segment
  254. ; *
  255. ; * EXIT Old2FHandler contains the original interrupt 2F vector
  256. ; * Old7AHandler contains the original interrupt 7A vector
  257. ; * OldIrqHandler contains original IRQ vector
  258. ; *
  259. ; * USES AX, BX, CX, DX
  260. ; *
  261. ; * ASSUMES nothing
  262. ; *
  263. ; ***
  264. InstallInterruptHandlers proc
  265. push es ; PSP segment - destroyed by INT 21/35h
  266. push ds
  267. mov dx,ResidentCode
  268. mov ds,dx
  269. assume ds:ResidentCode
  270. ;
  271. ; get and set call-back IRQ
  272. ;
  273. mov ah,35h
  274. mov al,bl
  275. mov cl,bl ; cl = IRQ number
  276. int 21h
  277. mov word ptr OldIrqHandler,bx
  278. mov word ptr OldIrqHandler+2,es
  279. mov al,cl
  280. mov ah,25h
  281. mov dx,offset ResidentCode:VwIpxEsrFunction
  282. int 21h
  283. ;
  284. ; get and set 2F handler
  285. ;
  286. mov ax,352Fh
  287. int 21h
  288. mov word ptr Old2FHandler,bx
  289. mov word ptr Old2FHandler+2,es
  290. mov dx,offset ResidentCode:VwIpxEntryPoint
  291. mov ax,252Fh
  292. int 21h
  293. ;
  294. ; get and set 7A handler
  295. ;
  296. mov ax,357Ah
  297. int 21h
  298. mov word ptr Old7AHandler,bx
  299. mov word ptr Old7AHandler+2,es
  300. mov dx,offset ResidentCode:VwIpx7ADispatcher
  301. mov ax,257Ah
  302. int 21h
  303. pop ds ; restore segment registers
  304. assume ds:nothing
  305. pop es
  306. assume es:nothing
  307. ret
  308. InstallInterruptHandlers endp
  309. InitCodeEnd
  310. page
  311. ;
  312. ; code from here on will be left in memory after initialisation
  313. ;
  314. ResidentCodeStart
  315. assume cs:ResidentCode
  316. assume ds:nothing
  317. assume es:nothing
  318. assume ss:nothing
  319. Old2FHandler dd ?
  320. Old7AHandler dd ?
  321. OldIrqHandler dd ?
  322. IrqValue dw ?
  323. VddHandle dw ?
  324. ; *** VwIpxEntryPoint
  325. ; *
  326. ; * The INT 2Fh handler that recognizes the Netware IPX request code (7A).
  327. ; * Also chains INT 2F/AX=1122
  328. ; *
  329. ; * ENTRY AX = 7A00h
  330. ; *
  331. ; * EXIT AL = 0FFh
  332. ; * ES:DI = address of routine to call when submitting IPX/SPX
  333. ; * requests
  334. ; *
  335. ; * USES
  336. ; *
  337. ; * ASSUMES nothing
  338. ; *
  339. ; ***
  340. VwIpxEntryPoint proc
  341. cmp ax,7a00h
  342. jne @f
  343. mov di,cs
  344. mov es,di
  345. mov di,offset VwIpxDispatcher
  346. dec al
  347. iret
  348. ;
  349. ; not 7A00h. Check for 1122h (IFSResetEnvironment). If yes, then this is DOS
  350. ; calling the IFS chain to notify that the app is terminating. When we have
  351. ; notified the DLL, chain the IFS request
  352. ;
  353. @@: cmp ax,7affh
  354. jne try1122
  355. mov di,cs
  356. mov es,di
  357. mov di,offset VwIpxDispatcher
  358. or bx,bx
  359. jz @f
  360. mov cx,8000h
  361. mov si,7
  362. iret
  363. @@: mov cx,14h
  364. mov si,200h
  365. iret
  366. try1122:cmp ax,1122h
  367. jne @f
  368. ;
  369. ; DOS Calls INT 2F/AX=1122 for every terminating app, including this one. We
  370. ; can't differentiate between a TSR and a non-TSR. Let the DLL handle it
  371. ;
  372. push ax
  373. push bx
  374. push cx
  375. mov ah,51h
  376. int 21h
  377. mov cx,bx ; cx = PDB of terminating program/TSR
  378. mov bx,-1 ; bx = dispatch code
  379. mov ax,VddHandle ; ax = VDD handle
  380. DispatchCall
  381. pop cx
  382. pop bx
  383. pop ax
  384. @@: jmp Old2FHandler ; chain int 2F
  385. VwIpxEntryPoint endp
  386. ; *** VwIpxDispatcher
  387. ; *
  388. ; * All DOS IPX/SPX calls are routed here by the netware libraries. Just
  389. ; * BOP on through to the other side
  390. ; *
  391. ; * This routine just transfers control to 32-bit world, where all work is
  392. ; * done
  393. ; *
  394. ; * ENTRY BX = netware IPX/SPX dispatch code
  395. ; * others - depends on function
  396. ; *
  397. ; * EXIT depends on function
  398. ; *
  399. ; * USES depends on function
  400. ; *
  401. ; * ASSUMES nothing
  402. ; *
  403. ; ***
  404. VwIpxDispatcher proc far
  405. pushf ; apparently we don't modify flags
  406. call DispatchWithFeeling
  407. popf
  408. ret
  409. VwIpxDispatcher endp
  410. ; *** VwIpx7ADispatcher
  411. ; *
  412. ; * Older Netware apps make the call to IPX/SPX via INT 7A. Same function
  413. ; * as VwIpxDispatcher
  414. ; *
  415. ; * This routine just transfers control to 32-bit world, where all work is
  416. ; * done
  417. ; *
  418. ; * ENTRY BX = netware IPX/SPX dispatch code
  419. ; * others - depends on function
  420. ; *
  421. ; * EXIT depends on function
  422. ; *
  423. ; * USES depends on function
  424. ; *
  425. ; * ASSUMES nothing
  426. ; *
  427. ; ***
  428. VwIpx7ADispatcher proc
  429. call DispatchWithFeeling
  430. iret
  431. VwIpx7ADispatcher endp
  432. ; *** DispatchWithFeeling
  433. ; *
  434. ; * Performs the dispatch for VrIpxDispatcher and VrIpx7ADispatcher. Checks
  435. ; * requested function for return code in AX: either returns value in AX
  436. ; * or restores AX to value on input
  437. ; *
  438. ; * This routine just transfers control to 32-bit world, where all work is
  439. ; * done
  440. ; *
  441. ; * ENTRY BX = netware IPX/SPX dispatch code
  442. ; * others - depends on function
  443. ; *
  444. ; * EXIT depends on function
  445. ; *
  446. ; * USES depends on function
  447. ; *
  448. ; * ASSUMES 1. Dispatch codes are in range 0..255 (ie 0 in BH)
  449. ; *
  450. ; ***
  451. DispatchWithFeeling proc
  452. push bp
  453. push ax ; caller value
  454. ;
  455. ; some APIs (IPXOpenSocket, IPXScheduleIPXEvent, SPXEstablishConnection, and
  456. ; others...) pass a parameter in AX. Since AX is being used for the VDD
  457. ; handle, we have to commandeer another register to hold our AX value. BP is
  458. ; always a good candidate
  459. ;
  460. mov bp,ax ; grumble, mutter, gnash, gnash
  461. push cx ; required if IPXOpenSocket
  462. push bx ; dispatch code
  463. or bx,bx ; IPXOpenSocket?
  464. jz @f ; yus ma'am
  465. cmp bl,3 ; IPXSendPacket?
  466. jz @f ; yus ma'am again
  467. jmp short carry_on_dispatching ; ooo-err missus
  468. ;
  469. ; IPXOpenSocket et IPXSendPacket: We need an extra piece of info - the PDB of
  470. ; the process making this request. This is so we can clean-up at program
  471. ; termination
  472. ;
  473. @@: push bx
  474. mov ah,51h ; get DOS PDB
  475. int 21h ; this call can be made any time
  476. mov cx,bx
  477. pop bx
  478. carry_on_dispatching:
  479. mov ax,VddHandle
  480. DispatchCall
  481. mov bp,sp
  482. ;
  483. ; BX and [BP] will be the same value except for SPXInitialize which is the only
  484. ; function that returns something in BX
  485. ;
  486. xchg bx,[bp] ; bx = dispatch code, [bp] = returned bx
  487. ;
  488. ; if this call returns something in AX (or AL) don't pop the AX value we pushed.
  489. ; If not a call which returns something in AX then restore the caller's AX. You
  490. ; can rest assured some assembler programmer has made use of the fact that some
  491. ; calls modify AX and the others leave it alone (presumably...?)
  492. ;
  493. or bl,bl ; 0x00 = IPXOpenSocket
  494. jz @f
  495. cmp bl,2 ; 0x02 = IPXGetLocalTarget
  496. jz @f
  497. cmp bl,4 ; 0x04 = IPXListenForPacket
  498. jz @f
  499. cmp bl,6 ; 0x06 = IPXCancelEvent
  500. jz @f
  501. cmp bl,8 ; 0x08 = IPXGetIntervalMarker
  502. jz @f
  503. cmp bl,10h ; 0x10 = SPXInitialize
  504. jz spx_init
  505. cmp bl,11h ; 0x11 = SPXEstablishConnection
  506. jz @f
  507. cmp bl,15h ; 0x15 = SPXGetConnectionStatus
  508. jz @f
  509. cmp bl,1ah ; 0x1A = IPXGetMaxPacketSize
  510. jz @f
  511. pop cx ; original dispatch code
  512. pop cx ; original cx
  513. pop ax ; original ax
  514. pop bp ; original bp
  515. ret
  516. ;
  517. ; here if this call returns something in AX/AL
  518. ;
  519. @@: pop cx ; original dispatch code
  520. pop cx ; original cx
  521. pop bp ; don't restore AX
  522. pop bp
  523. ret
  524. ;
  525. ; here if the call was SPXInitialize which returns values in AX, BX, CX, DX
  526. ;
  527. spx_init:
  528. pop bx ; bx = major/minor SPX version #
  529. pop bp ; caller cx - NOT restored
  530. pop bp ; caller ax - NOT restored
  531. pop bp ; caller bp - restored
  532. ret
  533. DispatchWithFeeling endp
  534. ; *** VwIpxEsrFunction
  535. ; *
  536. ; * This routine makes the call to the ESR as defined in the ECB. We must
  537. ; * set up our stack, save the registers (except SS & SP), then call the
  538. ; * ESR.
  539. ; *
  540. ; * Control will not be transferred here for an ECB which has a NULL ESR
  541. ; * field
  542. ; *
  543. ; * ENTRY AL = 0 for AES or 0FFh for IPX
  544. ; * ES:SI = ECB address
  545. ; *
  546. ; * EXIT depends on function
  547. ; *
  548. ; * USES depends on function
  549. ; *
  550. ; * ASSUMES nothing
  551. ; *
  552. ; ***
  553. VwIpxEsrFunction proc
  554. ;
  555. ; Novell documentation states all registers except SS and SP are saved before
  556. ; calling ESR and that INTERRUPTS ARE DISABLED
  557. ;
  558. pusha
  559. push ds
  560. push es
  561. mov ax,VddHandle
  562. mov bx,-2
  563. DispatchCall ; get ECB
  564. jc @f
  565. call dword ptr es:[si][4] ; branch to the ESR
  566. mov al,20h
  567. out 0a0h,al ; clear slave pic
  568. out 20h,al ; " master "
  569. pop es
  570. pop ds
  571. popa
  572. iret
  573. @@: pop es
  574. pop ds
  575. popa
  576. jmp OldIrqHandler
  577. VwIpxEsrFunction endp
  578. ResidentCodeEnd
  579. end start