Metropoli BBS
VIEWER: pmodetsr.asm MODE: TEXT (ASCII)
; Copyright (C) 1996 CW Sandmann (sandmann@clio.rice.edu) 1206 Braelinn, Sugarland, TX 77479
;
; This file is distributed WITHOUT ANY WARRANTY; without even the implied
; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

	title	cws_tsr_pmode

SW_FLAGS	= 0003h			; detect VCPI first, reprogram pic

	p386
	SEGMENT _TEXT PUBLIC USE16 'CODE'
	group DGROUP _DATA, _BSS
	assume cs:_TEXT, ds:DGROUP, es:nothing, ss:nothing
	EXTRN	pm_info:near, pm_init:near

_dpmiint2f:
	cmp	ax,1687h
	jne	short not_us
ct:	mov	cl,3
	xor	ax,ax			;Yes, we are here
	mov	bx,1			;32 bit programs supported
	mov	dx,5ah			;0.90 version
pn:	mov	si,1			;paragraphs needed
	push	cs
	pop	es
	mov	di,offset dpmientry
	iret
not_us:
	db	0eah
oldint2f	label	word
	dw	2 dup (?)

dpmientry:				;far return point cs:ip on stack
	test	al,1
	jnz	short ok_32
	stc
	retf
ok_32:
	pushad
	push	ds
	push	ss			; so we can compare later

; restore old int 2f vector since pmode is not reentrable and looks at int 2f
	xor	ax,ax
	mov	ds,ax
	mov	eax, dword ptr cs:oldint2f
	mov	ds:[2fh*4], eax		; atomic, cli not needed

	push	DGROUP
	pop	ds
	mov	ax,SW_FLAGS		; switch flags
	call	pm_init			; attempt to switch

	jnc	short in_pm
	pop	ax
	pop	ds
	popad
	retf
in_pm:
	pop	ax			; original ss
	pop	dx			; original ds
	cmp	ax,dx
	mov	bx,ss			; bx is just ss if same originally
	je	short no_new_ds

	call	seg_to_sel
no_new_ds:
	mov	ds,bx			; just in case

	mov	dx,[esp+34]		; 8 dwords for pushad and 2 bytes for IP
	call	seg_to_sel
	mov	[esp+34],bx

	mov	ax,0009h		; set selector type and access rights
	mov	dx,cs			; get DPL from current CPL, and access
	lar	cx,dx			;  rights and type from current CS
	shr	cx,8			; type is already 16bit code segment
	int	31h
	jc	short immed_exit

	popad
	retf

; Enter with segment in dx, exit with selector in bx
seg_to_sel:
	mov	bx,dx
	mov	ax,002h			; DPMI says not use it for private
	int	31h			; selectors, but it's only PMODE/DJ |-)
	jc	short immed_exit
	mov	bx,ax
	ret

immed_exit:
	mov	ax,4cffh
	int	21h

; Called by pmode right before exit to free this memory
exit_hook:
	mov	ax,cs
	sub	ax,10h			; psp base
	mov	es,ax
	mov	ah,49h
	int	21h
	ret

start:					; execution starts here

; Deallocate Environment
	mov	es,es:[2ch]
	mov	ah,49h
	int	21h
; Call PMODE's info routine
	push	_DATA
	pop	ds
	mov	ax, SW_FLAGS
	call	pm_info
	jc	short no_pmode
	cmp	ch,3
	jne	short ok1
; Fail - can't get to PM
no_pmode:
	mov	dx, offset msg_no_PM
	mov	ah,9
	int	21h
	mov	ax,4c01h
	int	21h

; store PMODE returned values in our code space
ok1:	mov	byte ptr ct+1,cl
	mov	word ptr pn+1,bx
; Close all the handles (stdin, stdout, stderr, AUX, PRN)
	mov	cx,4
closem:
	mov	ah,3eh
	mov	bx,cx
	int	21h
	loop	closem
; Chain int 2f
	mov	ax,352fh		;Get int 2f
	int	21h
	mov	oldint2f+2,es
	mov	oldint2f,bx
	push	cs
	pop	ds
	mov	dx,offset _dpmiint2f
	mov	ax,252fh
	int	21h

; Terminate and stay resident
	push	_DATA
	pop	ds
	mov	pm_exit,offset exit_hook
	mov	ax,3100h
	mov	dx,ss			;temp SS is at end
	mov	bx,cs			;CS is above PSP
	sub	dx,bx
	add	dx,10h			;add for psp
	int	21h

	ends

	SEGMENT _DATA PUBLIC USE16 'DATA'
	EXTRN	pm_exit:word
msg_no_PM	db "Can't load PMODE.",13,10,"$"
	ends

	SEGMENT _BSS PUBLIC USE16 'BSS'
	ends

	SEGMENT _STACK STACK 'STACK'
	db 256 dup (?)
	ENDS

	end	start
[ RETURN TO DIRECTORY ]