<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">		WINPKT theory			Joe Doupnik 17 Dec 1991

	Here's the simple story on calling a Windows application from a
driver/TSR loaded before Windows starts. This shim behaves like an 
application to a Packet Driver. To the real application it looks like a 
Packet Driver on another interrupt. There are four essential steps.


	1. Recognize when Windows starts operation. This is done by monitoring
Int 2Fh (Multiplexor Int) for such a broadcast by Windows. Since a lot of
apps also use Int 2Fh in various ways this one method seems to avoid being
deceived by other apps (including NetWare shells). We do the same monitor
and pass-on operation when Windows broadcasts it is shutting down. In summary,
this part tells the driver when an Environment is active.

; Windows (and many many other programs) use the Int 2Fh Multiplexor link,
; and each is supposed to grab it's own calls as seen in AX, or chain them
; to the previous Int 2Fh owner. Windows 3 uses function 16h for most work.
; This is our Int 2Fh routine.
our_2f_isr:
	assume	ds:nothing, es:nothing
	cmp	ax,1608h	; Windows Enhanced "Init completed" broadcast?
	jne	our_2f_1	; ne = not that function, chain it
	mov	vmm_running,1   ; remember that Windows has started
	jmp	their_2f_isr    ; pass it on down the chain
our_2f_1:
	cmp	ax,1609h	; Windows Enhanced "Begin Exit" broadcast?
	jne	our_2f_2	; ne = no
	mov	vmm_running,0   ; remember that Windows has stopped
our_2f_2:
	jmp	their_2f_isr	; propagate broadcasts down the Int 2Fh chain
----------------


	2. When the application attaches to the driver it uses a Packet
Driver interrupt. When that happens ask Windows for the virtual machine
then in use and remember it with the app's request info.

access_type_4:
	mov	[bx].their_handle,ax	; handle returned in ax
	mov	_AX[bp],ax		; save return handle
	cmp	vmm_running,0		; Windows Enhanced mode running?
	je	access_type_5		; e = no
	push	bx			; Windows "Get Current Virtual Mach"
	mov	ax,1683h
	int	2fh			; get current VM_ID to bx
	mov	ax,bx
	pop	bx
	mov	[bx].vm_id,ax		; save ident as part of our handle
access_type_5:
---------------------


	3. When the driver is invoked by an interrupt from the lan adapter
hardware it wants to call the application to deliver a packet. It needs to 
know the virtual machine ident so the correct v.m. will receive the call, 
else disaster. Int 2Fh again, as shown below. This step gets the current v.m. 
and compares it with that of the application needing calling. If the v.m.'s 
are the same then do a double call of the application in real time. Otherwise
do step 4.

	push    bx
	mov	ax,1683h        ; Windows, get current vir mach ident
	int	2fh
	mov	ax,bx		; ident returned in bx
	pop	bx
	cmp	ax,[bx].vm_id	; same as the one the app is using?
	je	our_handler_5	; e = yes, correct VM is running
	jmp	our_handler_7   ; no, another VM is running, switch to wanted
our_handler_5:
;	inc	gvm_pkts
	call	pass_to_app	; copy buffer to application, via double call
	retf

pass_to_app:
	xor	ax,ax		; set up register for first upcall to app
	mov	bx,their_bx	; handle from Packet Driver
	mov	cx,buffer_len	; packet size
	push    ds
	call    their_handler	; do first upcall (request buffer address)
	pop	ds
	mov	ax,es		; check for 0:0 as reject value
	or	ax,ax
	jnz	pass_to_app_1	; nz = have an address
	or	di,di		; check for 0:offset (rather unlikely)
	jnz	pass_to_app_1	; nz = have an offset
	mov	buffer_flag,0   ; packet is being declined, free our buffer
	ret
pass_to_app_1:			; copy from our buffer to app's es:di
	push	di
	mov	cx,buffer_len
	mov	si,offset our_buffer
	cld
	rep	movsb		; copy frame into apps buffer
	mov	ax,1		; set up regs for second upcall
	mov	bx,their_bx	; handle
	mov	cx,buffer_len	; report packet length too
	pop	si
	mov	dx,es
	push	ds
	mov	ds,dx
	assume	ds:nothing

	call	their_handler	; call the application
	pop	ds
	assume	ds:code
	mov	buffer_flag,0	; free buffer
	ret

----------------------

	4. Have Windows invoke the desired virtual machine and then we call
the application (twice in rapid succession, once to get a buffer pointer
and then to tell the app the copy has completed). As noted Windows may delay
invoking the target v.m. by a long time and thus this shim must buffer
the incoming packet to both clear the lan adapter and to reenable interrupts.
We tell Windows to call us when the correct v.m. is available. We ought to
declare critical regions in both steps 3 and 4, and maybe I will if trouble
ensues later on.

; Windows Enhanced, request virtual machine in bx, and call back at es:di 
; when it's ready (which, knowing Windows, may take quite a while, hence 
; the requirement to buffer the packet to clear the lan board and ints).
our_handler_7:
;	inc	bvm_pkts
	mov	ax,1685h	; request switch VMs and callback
	mov	bx,[bx].vm_id	; virtual machine of the app
	xor	cx,cx		; flags (bits 0 and 1), zero is don't wait
	mov	dx,40h		; dx:si is priority boost
	xor	si,si
	push	cs
	pop	es		; es:di is address of callback routine
	mov	di,offset our_callback
	int	2fh
	retf

	assume ds:nothing
our_callback:			; get here with correct virtual machine
	push	ax		; call application twice (a la PD) to deliver
	push	bx		; the buffered packet
	push	cx
	push	dx
	push	si
	push	di
	push	ds
	push	es
	push	bp
	mov	ax,cs
	mov	ds,ax		; set up our ds
	assume	ds:code

	call    pass_to_app
	pop	bp
	pop	es
	pop	ds
	assume  ds:nothing
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	iret
-------------------------------------------------------------------------
</pre></body></html>