.386p
page 58,132
;******************************************************************************
	title   ELIMFUNC - CEMM functions module
;******************************************************************************
;
;   (C) Copyright MICROSOFT Corp. 1986-1991
;   (C) Copyright COMPAQ Computer Corp. 1986-1991
;
;       Title:  EMM386.EXE - MICROSOFT Expanded Memory Manager 386 Driver
;
;       Module: ELIMFUNC - entry point for VDM functions
;
;       Version: 2.00
;
;       Date:   May 24,1986
;
;       Author: Steve Preston
;
;******************************************************************************
;
;       Change Log:
;
;       DATE     REVISION       Description
;       -------- --------       --------------------------------------------
;       04/24/86 Original       From EMML LIM driver.
;       06/28/86 0.02           Name change from CEMM386 to CEMM (SBP).
;       07/05/86 0.04           Added segment R_CODE (SBP).
;       07/10/86 0.05           jmp $+2 before "POPF" (SBP).
;       05/12/87 2.00           moved code to R_CODE (SBP).
;       05/21/87 2.00           added debug functions (SBP).
;       05/31/88 ?.??           set active flag AFTER GoVirtual (SBP).
;
;******************************************************************************
;   Functional Description:
;       This module contains the ON/OFF functionality code for activating/
;   deactivating CEMM from DOS.
;
;******************************************************************************
.lfcond
	page
;******************************************************************************
;                       P U B L I C   D E C L A R A T I O N S
;******************************************************************************
;
	public  b2asc10
	public  b2asc10_far
	public  b2ascHEX
	public  b2ascHEX_far
	public  ELIM_Entry
	public  EFunTab
	public  EFUN_CNT

ifdef   QHKN
	public  Debug_PhysIO
	public  E_Debug
endif

	public  E_GetStatus
	public  E_ONOFF
	public  E_Weitek
	public  I_Message_Display
	public  E_XStatus_Display

;
	page
;******************************************************************************
;                       L O C A L   C O N S T A N T S
;******************************************************************************
;
	include vdmseg.inc
	include vdmsel.inc
	include emm386.inc
	include page.inc
	include emmfunct.inc
	include emmdata.inc
	include winemm.inc

;******************************************************************************
;                       E X T E R N A L    R E F E R E N C E S
;******************************************************************************
;
R_CODE  SEGMENT
	EXTRN   ttl_hndls: WORD
	extrn   GoVirtual:near
;;      extrn   check_XMM:far
;       extrn   XMMAllocateHMA:far
;       extrn   XMMDeallocateHMA:far
	extrn   XMMAllocHMAFar:dword
	extrn   XMMDeallHMAFar:dword
	extrn   checkXMMFar:dword
	extrn   Devname:byte
R_CODE  ENDS


LAST    SEGMENT
	extrn   StatusMess:byte
	extrn   LIMVerMess:byte
	extrn   TotalPagesMess:byte
	extrn   AvailPagesMess:byte
	extrn   TotalHanMess:byte
	extrn   AvailHanMess:byte
	extrn   PFBAMess:byte
	extrn   MemSizeMess:byte
	extrn   ISizeMess:byte
	extrn   InitMessage:byte
	extrn   NoEMSmess:byte
	extrn   UMBstatusMess:byte
	extrn   UMBavail:byte
	extrn   UMBlargest:byte
	extrn   UMBstart:byte
	extrn   AvailUMB:near
	extrn   LargestUMB:near
LAST    ENDS


	page
;******************************************************************************
;                       S E G M E N T   D E F I N I T I O N
;******************************************************************************
;
;******************************************************************************
;
;       Code Segment R_CODE
;
;******************************************************************************
;
R_CODE  segment
	assume  CS:R_CODE, DS:R_CODE, ES:R_CODE
;
;       ELIM functions table    - far calls
;
EFunTab label   dword
	dw      offset  E_GetStatus
	dw      seg     R_CODE

	dw      offset  E_ONOFF
	dw      seg     R_CODE

	dw      offset  E_Weitek
	dw      seg     R_CODE

ifdef   QHKN
	dw      offset  E_Debug
	dw      seg     R_CODE
endif

EFUN_CNT        equ     ($-EFunTab)/4

	page
;******************************************************************************
;       ELIM_Entry - entry point for general ELIM functions
;
;       THIS IS A FAR CALL ROUTINE
;
;       ENTRY:  REAL or VIRTUAL mode only
;               AH = 0  => get current status of VDM/EMM386
;               AH = 1  => ON/OFF/AUTO
;               AH = 2  => Weitek functions
;               AH = 3  => DEBUG entry
;               AH = 4  => Message Display
;               AH = 5  => Status Display
;
;       EXIT: EMM386 is activated/deactivated if possible
;             NC => no errors.
;             CY => ERROR occured.
;                       AH = error number
;                       AH= 01 =>invalid function.
;
;       USED: none
;
;******************************************************************************
ELIM_Entry      proc    far
;

	push    ebx
	push    ds
;
	mov     bx,seg R_CODE
	mov     ds,bx
	assume  ds:R_CODE
;
	cmp     ah,EFUN_CNT     ;Q: valid function #
	jae     SHORT EE_inv_func ;  N: return error
	xor     bx,bx           ;  Y: exec function
	mov     bl,ah           ; bx = function #
	shl     bx,2            ; dword index
	call    CS:EFunTab[bx]  ; call the function
;
EE_exit:
	pop     ds
	pop     ebx
	ret
;
EE_inv_func:
	mov     ah,01
	stc
	jmp     short EE_exit
;
ELIM_Entry      endp

;******************************************************************************
;       E_GetStatus - get ELIM/VDM status
;
;       ENTRY:  AH = 0
;               DS = R_CODE
;
;       EXIT:   AH = 0 => ELIM ON
;                  = 1 => ELIM OFF
;                  = 2 => ELIM in AUTO mode (ON)
;                  = 3 => ELIM in AUTO mode (OFF)
;
;       USED: none
;
;******************************************************************************
E_GetStatus     proc    far
;
	xor     ah,ah                   ; assume ON
	test    [Current_State],fState_Active
					;Q: CEMM currently ON?
	jnz     SHORT EGS_chkAUTO       ;  Y: chk for AUTO mode
	mov     ah,1                    ;  N: set to OFF
EGS_chkAUTO:
	cmp     [Current_Mode],MODE_AUTO        ;Q: Auto Mode?
	jne     SHORT EGS_exit                  ;  N: leave
	add     ah,2                            ;  Y: map to 2,3
EGS_exit:
	ret
;
E_GetStatus     endp

;******************************************************************************
;       E_ONOFF  - general ON/OFF code for ELIM
;
;       ENTRY:  AH = 1
;                AL = 0 => ON
;                AL = 1 => OFF
;                AL = 2 => AUTO
;               DS = R_CODE
;
;       EXIT:   Virtual mode and ELIM ON
;               OR Real mode and ELIM OFF
;
;       USED: none
;
;******************************************************************************
E_ONOFF proc    far
;
	cmp     al,0                    ;Q: -> CEMM ON ?
	jne     SHORT EOO_chkOFF        ;  N: check for OFF/AUTO

	mov     [Current_Mode],MODE_ON  ; set mode to ON
	mov     [Devname],'E'           ; set to allow presense detect
	jmp     SHORT EOO_ON            ;     go to ON state

EOO_chkOFF:
	cmp     al,1                    ;Q: -> CEMM OFF ?
	jne     SHORT EOO_chkAUTO       ;  N: check for AUTO
	CMP     [handle_count], 1       ; Q:  entries in handle dir <= 1?
	JA      EOO_inv                 ; N: refuse the request
	cmp     [UsedVCPIPages],0       ;Q: Any VCPI pages allocated
	jnz     EOO_inv                 ; Y: continue
ifdef QEMS
	MOV     AX, [free_pages]        ; Get original free 4K pages    ;@PIW
	CMP     AX, [free_4k_pages]     ; Q: Is any page (de)allocated? ;@PIW
	jne     EOO_inv                 ; Y:
endif
	cmp     cs:[UMBHMA],TRUE        ;Q: Are UMBs defined?
	je      EOO_inv                 ; Y: don't turn off
	mov     [Current_Mode],MODE_OFF ; N: set mode to OFF
	mov     [Devname],'$'           ;set to prevent presense detect
	jmp     SHORT EOO_OFF

EOO_chkAUTO:
	cmp     al,2                            ;Q: -> CEMM AUTO ?
	jne     SHORT EOO_inv                   ; N: invalid function call
	mov     [Current_Mode],MODE_AUTO        ; Y: set mode to AUTO

	or      [Auto_State],fAuto_Users        ; assume users: active

	cmp     [handle_count],1                ;Q: EMS users active?
	jne     short EOOcont                   ; Y: continue
	cmp     cs:[UMBHMA],TRUE                ;Q: Is virtual HMA/UMB provided?
	je      short EOOcont                   ; Y: continue
	cmp     [UsedVCPIPages],0               ;Q: Any VCPI pages allocated
	jnz     EOOcont                         ; Y: continue   
ifdef QEMS
	mov     ax,[free_pages]                 ; Get original free 4K pages
	cmp     ax,[free_4k_pages]              ;Q: Is any page allocated?
	jne     short EOOcont                   ; Y: continue
endif
	and     [Auto_State],not fAuto_Users    ; N: CEMM may be turned inactive

EOOcont:
	mov     [Devname],'E'           ;set to allow presense detect
	cmp     [Auto_State],0          ;Q: turn on for AUTO mode ?
	je      SHORT EOO_OFF           ;  N: go to OFF state
					;  Y: go to ON state

	;
	; go to Virtual Mode operation and activate CEMM
	;
EOO_ON:
	test    [Current_State],fState_Active   ;Q: currently active ?
	jnz     SHORT EOO_OK                    ;  Y: just leave
	call    GoVirtual                       ;  N: go to virtual mode & (sbp)
	jc      short EOOerror
	or      [Current_State],fState_Active   ;     set active flag      (sbp)
	jmp     short EOO_OK
	;
	; go to Real Mode operation and deactivate CEMM
	;
EOOerror:
	and     [Current_State],not fState_Active; make inactive
	mov     [Current_Mode],MODE_OFF          ; set mode to OFF
	mov     [Devname],'$'                    ; set to prevent presense detect

EOO_OFF:
	test    [Current_State],fState_Active   ;Q: currently inactive ?
	jz      SHORT EOO_OK                    ;  Y: just leave
	and     [Current_State],NOT fState_Active ;N: reset active flag &
	push    ax                              ; and return to real mode
	pushf
	cli                             ;;; protect this sequence
	mov     al,0Fh                  ;;;
	out     84h,al                  ;;; port 84/85 return to real
	mov     al,00h                  ;;;     sequence ...
	out     85h,al                  ;;;
	jmp     $+2                     ;;; clear prefetch/avoid race cond
	popf
	pop     ax
	cmp     [Current_Mode],MODE_OFF
	jne     short EOO_OK
;
;   leave with no errors
;
EOO_OK:
	clc
EOO_exit:
	ret
;
;  invalid ON/OFF/AUTO function call
;
EOO_inv:
	stc
	ret
;
E_ONOFF endp

;******************************************************************************
;       E_Weitek  - Weitek support functions
;
;       ENTRY:  AH = 2
;                AL = 0 => sense current Weitek state
;                AL = 1 => turn Weitek ON
;                AL = 2 => turn Weitek OFF
;               DS = R_CODE
;
;       EXIT:   STC and AH = 1 for invalid subfunction (AL)
;               for AL = 0 (sense Weitek state)
;                   AL -> bit 0 = Weitek installed flag
;                         bit 1 = Weitek mapped flag
;               for AL = 1 or 2
;                   STC and AH = 2 => Weitek not installed
;                       CEMM ON or OFF depending on current
;                       CEMM mode (ON/OFF/AUTO).
;
;       USED: none
;
;******************************************************************************
E_Weitek        proc    far
;
	push    bx
	cmp     al,0                    ;Q: sense status ?
	jne     SHORT EW_chkON          ;  N: check next function code
	mov     al,[Weitek_State]       ;  Y: return current state
	jmp     EW_OK

;
; Weitek ON function
;   When Weitek state is set to ON, CEMM goes active whenever it is in
;   AUTO mode and the page table mapping is set to point to the Weitek.
;
EW_chkON:
	cmp     al,1                    ;Q: Weitek ON function ?
	jne     SHORT EW_chkOFF         ;    N: check for OFF function
	test    [Weitek_State],fWeitek_Inst ;Y: Q: Weitek installed ?
	jz      SHORT EWerror               ;     N: report error

	call    dword ptr [checkXMMFar] ;Q: Is there an XMM in the system
	jc      short EWok              ; N: OK to take HMA for WEITEK

	test    [GenFlags],fHMA         ;Q: Does CEMM own the HMA?
	jnz     short EWok              ; Y: map WEITEK

	call    dword ptr [XMMAllocHMAFar]
					;Q: Is the HMA available
	jc      short EWerror           ; N: report error

EWok:
	or      [Weitek_State],fWeitek_Map  ;     Y: set Weitek ON
	or      [Auto_State],fAuto_Weitek   ;        and auto mode flag
	;
	; update CEMM's state
	;   if CEMM is inactive, check for AUTO mode.
	;      if AUTO mode, CEMM goes active.
	;
	test    [Current_State],fState_Active   ;Q: CEMM active ?
	jnz     SHORT EW_ONPg                   ; Y: nothing to do here ...

	cmp     [Current_Mode],MODE_AUTO        ;Q: CEMM in AUTO mode ?
	jne     SHORT EW_ONPg                   ; N: CEMM stays inactive

	call    GoVirtual                       ;(sbp)  Y: go to virtual mode &
	jc      short EWerror
	or      [Current_State],fState_Active   ;(sbp)     set active flag
	;
	; now change 1meg wraparound to point to Weitek addresses
	;
EW_ONPg:
	mov     bx,0            ; Weitek mapping ON
	jmp     SHORT EW_UpdPageMap
;
; HMA not available for WEITEK
EWerror:
	mov     ah,2
	stc
	jmp     SHORT EW_error

;
; Weitek OFF function
;   When Weitek state is set to OFF, CEMM active/inactive state is unaffected
;   by Weitek in AUTO mode.  The 1Meg wraparound is placed back into the
;   page tables.
;
EW_chkOFF:
	cmp     al,2                    ;Q: Weitek OFF function ?
	jne     SHORT EW_InvFunc        ;    N: invalid Weitek subfunction
	test    [Weitek_State],fWeitek_Inst ;Y: Q: Weitek installed ?
	jz      short EWerror           ;         N: report error

	call    dword ptr [checkXMMFar] ;Q: Is there an XMM in the system
	jc      short EWOok             ; N: OK to release HMA for WEITEK

	test    [GenFlags],fHMA         ;Q: Does CEMM own the HMA?
	jz      short EWOok             ; N: OK to release HMA for WEITEK

	call    dword ptr [XMMDeallHMAFar]
					;Q: Is the HMA released?
	jc      short EWerror           ; N: report error

EWOok:
	and     [Weitek_State],NOT fWeitek_Map  ; Y: set Weitek OFF
	and     [Auto_State],NOT fAuto_Weitek   ;    and reset auto mode flag
	;
	; update CEMM's state
	;   if CEMM is in AUTO mode, it is active and CEMM may be able
	;    to go inactive now.
	;
	cmp     [Current_Mode],MODE_AUTO        ;Q: CEMM in AUTO mode ?
	jne     SHORT EW_OFFPg                  ;  N: then no CEMM state change
	cmp     [Auto_State],0                  ;  Y: Q: CEMM stays active ?
	jne     SHORT EW_OFFPg                  ;       Y: then leave
	and     [Current_State],NOT fState_Active ;     N: reset active flag &
	pushf                                   ; and return to real mode
	cli                             ;;; protect this sequence
	mov     al,0Fh                  ;;;
	out     84h,al                  ;;; port 84/85 return to real
	mov     al,00h                  ;;;     sequence ...
	out     85h,al                  ;;;
	jmp     $+2                     ;;; clear prefetch/avoid race cond
	popf
	;
	; now enable 1meg wraparound
	;
EW_OFFPg:
	mov     bx,1            ; Weitek mapping OFF
;
;  Update page table mapping of 1meg linear wraparound area
;       Entry: BX = 0 => Weitek mapping ON
;                 = 1 => 1 meg wraparound (Weitek OFF)
;
EW_UpdPageMap:
	test    [Current_State],fState_Active   ;Q: CEMM active?
	jz      SHORT EW_InactMap               ;  N: change mapping
	pushf                                   ;  Y: prot mode call to chg it
	cli                             ;;; protect this sequence
	Call_CEMM_PMF   CEMM_84_Weitek
	popf
	jmp     SHORT EW_OK

EW_InactMap:                    ; CEMM inactive, update Weitek mapping
EW_OK:
	clc
EW_exit:
	pop     bx
	ret

EW_InvFunc:
	mov     ah,1
	stc
	jmp     SHORT EW_error
EW_error:               ; error exit
	stc
	jmp     EW_exit
;
E_Weitek        endp

;LEO ;******************************************************************************
;LEO ; WeitekPageMap - change tables to include/exclude Weitek in page tables
;LEO ;
;LEO ;  NOTE: THIS IS A FAR ROUTINE
;LEO ;
;LEO ;   ENTRY: PROTECTED or REAL mode ONLY
;LEO ;          ES -> page tables
;LEO ;          BX = 0 => Weitek mapping ON
;LEO ;             = 1 => Weitek mapping OFF (1meg wraparound)
;LEO ;   EXIT: same as entry
;LEO ;   USED: none
;LEO ;******************************************************************************
;LEO WeitekPageMap      proc    far
;LEO    pushad
;LEO    cld
;LEO    cmp     bx,0                    ;Q: weitek map on function ?
;LEO    jne     SHORT WPM_chkoff        ;  N: check for off function
;LEO    ;                               ;  Y: change page tables
;LEO    ;  For Weitek 1167 mapping addresses,
;LEO    ; change page table entries for (00100000h,0010EFFFh) ->
;LEO    ;                               (C0000000h,C000EFFFh)
;LEO    ;
;LEO    mov     eax,0C0000000h  ; start with physical addr = C0000000h
;LEO    jmp     SHORT WPM_set_PT        ; set page tables
;LEO
;LEO WPM_chkoff:
;LEO    cmp     bx,1                    ;Q: weitek map off function ?
;LEO    jne     SHORT WPM_exit          ;  N: leave
;LEO    xor     eax,eax                 ;  Y: 1meg wraparound
;LEO
;LEO    ;
;LEO    ; set 60k worth of entries in page tables for 1meg linear
;LEO    ; entry: EAX = begin physical addr
;LEO    ;
;LEO WPM_set_PT:
;LEO    mov     di,100h*4       ; ES:DI -> PTE for 1Meg linear
;LEO    or      al,P_AVAIL              ; make pages available to all
;LEO    mov     cx,0Fh                  ; set 60k worth of entries
;LEO WPM_set_entry:
;LEO    stosd                           ; store EAX to ES:[DI]
;LEO                                    ; ES:[DI] pts to next page table entry
;LEO    add     eax,1000h               ; EAX = next physical page (with attrs)
;LEO    loop    WPM_set_entry           ;Q: done with page table entries ?
;LEO                                    ;  N: loop again
;LEO                                    ;  Y: all done
;LEO WPM_exit:
;LEO    mov     eax,cr3         ; clear the TLB !!!
;LEO    mov     cr3,eax
;LEO    popad
;LEO    ret
;LEO WeitekPageMap      endp

ifdef   QHKN

	page
;******************************************************************************
;       Debug Functions table
;******************************************************************************
;
DebugTab        label   word
	dw      offset  DebugR_GetPTE
	dw      offset  DebugR_PhysIO
DEBTAB_CNT      equ     ($-DebugTab)/2

;******************************************************************************
;       E_Debug  - Debug functions entry point
;
;       ENTRY:  REAL or VIRTUAL mode
;               AH = 3
;                AL = 0 => Get physical address
;                AL = 1 => Get physical DMA contents
;               DS = R_CODE
;
;       EXIT:   Same processor mode as entry
;               CLC => no errors
;               STC => error
;
;       USED: BX
;
;******************************************************************************
E_Debug proc    far
;
	cmp     al,DEBTAB_CNT   ;Q: valid function #
	jae     SHORT ED_inv_func ;  N: return error
	xor     bx,bx           ;  Y: exec function
	mov     bl,al           ; bx = function #
	shl     bx,1            ; word index
	call    CS:DebugTab[bx] ; call the function
;
ED_exit:
	ret
ED_inv_func:
	stc
	ret
;
E_Debug endp
;
	page
;******************************************************************************
;       DebugR_GetPTE  - Returns the Page Table Entry for a Linear Address
;
;       ENTRY:  REAL or VIRTUAL mode
;               AH = 3
;               AL = 0 => Get page table entry
;               ECX = linear address
;               DX = 0  => don't map linear address first (for >1meg addrs)
;               DX = 1  => map linear address first
;               DS = R_CODE
;
;       EXIT:   Same processor mode as entry
;               STC => error
;               CLC => no errors and
;                       ECX = page table entry
;
;       USED: none
;
;******************************************************************************
DebugR_GetPTE   proc    near
	test    [Current_State], fState_Active  ;Q: in Real mode now ?
	jnz     SHORT DRGP_VM                   ;  N: go to Virtual Mode hndlng
						;  Y: ok ..
	push    eax
	push    di
	push    es
	mov     ebx,[PageD_Addr]        ; EBX = 32 bit addr of page dir
	shr     ebx,4                   ; BX = seg addr of page dir
	mov     es,bx                   ; ES -> page dir
	mov     eax,ecx                 ; EAX = linear addr
	PDOff   ax                      ; EAX = page dir offset
	mov     di,ax                   ; DI = page dir offset for this addr
	mov     ebx,ES:[di]             ; EBX = PTE for page table
	test    bx,P_PRES               ;Q: is this page table present ?
	jz      SHORT DRGP_RM_error     ;  N: report error
	and     bx,(P_SIZE-1)           ;  Y: remove status bits
	shr     ebx,4                   ; BX = seg addr of page table
	mov     es,bx                   ; ES -> page table
	mov     eax,ecx                 ; EAX = linear addr
	PTOff   ax                      ; EAX = page table offset
	mov     di,ax                   ; DI = page table offset for this addr
	mov     ecx,ES:[di]             ; ECX = PTE for page table
	clc                     ; no errors

DRGP_RM_exit:
	pop     es
	pop     di
	pop     eax
	ret
DRGP_RM_error:
	stc
	jmp     DRGP_RM_exit
;
; In virtual mode now.  We need to go to protected mode to be sure we can
; access the page tables.
DRGP_VM:
	push    bx
	mov     bl,al                   ; BL = Diag function # for GetPTE
	Call_CEMM_PMF   CEMM_84_Diag    ; exec diag function
	pop     bx
	ret
DebugR_GetPTE   endp

	page
;******************************************************************************
;       DebugR_PhysIO - do physical I/O (at ring 0 PM privilege level)
;
;       ENTRY:  REAL or VIRTUAL mode
;               AH = 3
;               AL = 1 => Do Physical I/O
;                   DX = I/O address
;                   ECX/CX/CL = for OUTs, the value to output
;                   SI = 0 for input
;                      = 1 for output
;                   DI = 0 for byte I/O
;                      = 1 for word I/O
;                      = 2 for dword I/O
;               DS = R_CODE
;
;       EXIT:   Same processor mode as entry
;               STC => error
;               CLC => no errors and
;                   ECX/CX/CL = value input
;
;       USED: none
;
;******************************************************************************
DebugR_PhysIO   proc    near
	test    [Current_State], fState_Active  ;Q: in Real mode now ?
	jnz     SHORT DRPIO_VM                  ;  N: go to Virtual Mode hndlng
	call    FAR PTR Debug_PhysIO            ;  Y: do I/O in real mode
	ret                                     ;     and return
;
; here if virtual mode  => call CEMM Protected Mode Function
;
DRPIO_VM:
	push    bx
	mov     bl,al                   ; BL = Diag function # for PhysIO
	Call_CEMM_PMF   CEMM_84_Diag    ; exec diag function
	pop     bx
	ret
DebugR_PhysIO   endp

	page
;******************************************************************************
;       Debug_PhysIO - do physical I/O
;
;       ENTRY:  REAL MODE or Ring 0 PROT MODE
;                   DX = I/O address
;                   ECX/CX/CL = for OUTs, the value to output
;                   SI =  0 for input
;                      <> 0 for output
;                   DI = 0 for byte I/O
;                      = 1 for word I/O
;                      = 2 for dword I/O
;               DS = R_CODE
;
;       EXIT:   Same processor mode as entry
;                   ECX/CX/CL = value input
;               CLC => no error
;               STC => invalid input
;
;       USED: none
;
;******************************************************************************
Debug_PhysIO    proc    far
	push    eax
	or      si,si           ;Q: Input ?
	jnz     SHORT DPIO_Out  ;  N: do output
				;  Y: do input
	cmp     di,0            ;Q: byte input ?
	jne     SHORT DPIO_InW  ;  N: chk for word
	in      al,dx           ;  Y: do input
	mov     cl,al           ;     and set value into CL
	jmp     SHORT DPIO_OK   ;      and leave
DPIO_InW:
	cmp     di,1            ;Q: word input ?
	jne     SHORT DPIO_InDW ;  N: chk for dword
	in      ax,dx           ;  Y: do input
	mov     cx,ax           ;     and set value into CL
	jmp     SHORT DPIO_OK   ;      and leave
DPIO_InDW:
	cmp     di,2            ;Q: dword input ?
	jne     SHORT DPIO_error ;  N: bad xfer size
	in      eax,dx          ;  Y: do input
	mov     ecx,eax         ;     and set value into CL
	jmp     SHORT DPIO_OK   ;      and leave

DPIO_Out:
	cmp     di,0            ;Q: byte output ?
	jne     SHORT DPIO_OutW ;  N: chk for word
	mov     al,cl           ;  Y: get byte for out
	out     dx,al           ;     do output
	jmp     SHORT DPIO_OK   ;      and leave

DPIO_OutW:
	cmp     di,0            ;Q: word output ?
	jne     DPIO_OutW       ;  N: chk for dword
	mov     ax,cx           ;  Y: get word for out
	out     dx,ax           ;     do output
	jmp     SHORT DPIO_OK   ;      and leave

DPIO_OutDW:
	cmp     di,2            ;Q: dword output ?
	jne     SHORT DPIO_error;  N: bad xfer size
	mov     eax,ecx         ;  Y: get dword for out
	out     dx,eax          ;     do output
				;      and leave
DPIO_OK:
	clc
DPIO_exit:
	pop     eax
	ret

DPIO_error:
	stc
	jmp     DPIO_exit
Debug_PhysIO    endp

endif

R_CODE  ENDS

LAST    segment
	assume  CS:LAST, DS:LAST, ES:R_CODE


;******************************************************************************
;       I_Message_Display - display banner
;
;       ENTRY:  NONE
;
;       EXIT:   none
;
;       USED: none
;
;******************************************************************************
I_Message_Display       PROC    near

	push    ds
	mov     dx, cs
	mov     ds, dx
	mov     dx,offset LAST:InitMessage
	mov     ah,PRINT_STRING
	int     MS_DOS                  ; output init message
	pop     ds
	RET
I_Message_Display       ENDP

;******************************************************************************
;       E_XStatus_Display - display ELIM/VDM status
;
;       ENTRY:  DS = R_CODE
;
;       EXIT:   none
;
;       USED: none
;
;******************************************************************************
E_XStatus_Display       proc    near
;

	push    ds
	push    es
	push    di

	push    ds
	pop     es      ; es = R_CODE

	mov     ax, cs  ; si = LAST
	mov     ds, ax  ; ds = LAST

	mov     dx,offset LAST:NoEMSmess        ; assume EMS N/A

;;      cmp     cs:[NoEMSset],TRUE      ;Q: Is EMS available?
;;      je      short EXSprint          ; N: print EMS N/A message

	cmp     es:[VCPIset], -1        ; Q: has noems been specifed
	jne     EXSprint                ; Y: print EMS N/A message

EXSDcont:
ifdef QEMS
	mov     ax,es:[free_4k_pages]
	shl     ax,2                    ; amount in K
endif
	mov     ax,es:[TopOfHandleSpace]        ; top of free EMS handle space
	sub     ax,FIRST_HANDLE_PTE     ; subtract start of handle space
	sub     ax,es:[UsedVCPIPages]   ; number of free EMS pages
	shr     ax,2                    ; convert to 16K pages
	sub     ax,es:[UsedEMSPages]    ; number of free EMS pages
	shl     ax,4                    ; number in KBs
	mov     di,offset LAST:ISizeMess; store decimal size in ASCII here.
	mov     cx,5
	call    b2asc10                 ; convert to ASCII...(R_CODE)

	mov     dx,offset LAST:MemSizeMess
	mov     ah,PRINT_STRING
	int     MS_DOS                  ; output message

	mov     al,EMM_VERSION
	xor     ah,ah
	ror     ax,4
	shr     ah,4
	or      ax,'00'
	mov     di,offset LAST:LIMVerMess
;;      stosb
	mov     byte ptr ds:[di], al
	inc     di

	inc     di
	xchg    al,ah
;;      stosb
	mov     byte ptr ds:[di], al
	inc     di

	mov     ax,es:[TopOfHandleSpace]; top of free EMS handle space
	sub     ax,FIRST_HANDLE_PTE     ; subtract start of handle space
	shr     ax,2
;QEMS   mov     ax,es:[total_4k_pages]
;QEMS   shr     ax,1
;QEMS   shr     ax,1
	mov     cx,4
	mov     di,offset LAST:TotalPagesMess
	call    b2asc10

	mov     ax,es:[TopOfHandleSpace]; top of free EMS handle space
	sub     ax,FIRST_HANDLE_PTE     ; subtract start of handle space
	sub     ax,es:[UsedVCPIPages]   ; number of free EMS pages
	shr     ax,2                    ; convert to 16K pages
	sub     ax,es:[UsedEMSPages]    ; number of free EMS pages
;QEMS   mov     ax,es:[free_4k_pages]
;QEMS   shr     ax,1
;QEMS   shr     ax,1
	mov     cx,4
	mov     di,offset LAST:AvailPagesMess
	call    b2asc10
	mov     ax,es:[ttl_hndls]
	mov     cx,4
	mov     di,offset LAST:TotalHanMess
	call    b2asc10

	mov     ax,es:[handle_count]
	mov     cx,4
	mov     di,offset LAST:AvailHanMess
	call    b2asc10

	CMP     es:[PF_Base], FREE      ; Q: Is there a page frame?     ;@PIW
	JE      SHORT get_status_mess   ; N: Skip this part             ;@PIW
	mov     ax,es:[PF_Base]         ; page frame base addr
	mov     di,offset LAST:PFBAMess ; here for page frame base addr
	call    b2ascHEX
	; Append " H" to hex value
        MOV     BYTE PTR [DI], ' '      ; Ensure blank for localized ver (IPG)
	MOV     BYTE PTR [DI+1], 'H'    ; Put H at end of the segment   ;@PIW

get_status_mess:
	mov     dx,offset LAST:StatusMess
EXSprint:
	mov     ah,PRINT_STRING
	int     MS_DOS                  ; output message

ifndef  MSFLAG
	call    dword ptr es:[checkXMMFar]  
					;Q: Is there an XMM in the system
	jc      short EXSexit           ; N: exit
endif

	cmp     es:[UMBptr],0           ;Q: Any UMBs?
	je      short EXSexit           ; N: exit

	call    AvailUMB
	shr     ax,6
	mov     di,offset LAST:UMBavail; store decimal size in ASCII here.
	mov     cx,4
	call    b2asc10                 ; convert to ASCII...(R_CODE)

	call    LargestUMB
	shr     ax,6
	mov     di,offset LAST:UMBlargest; store decimal size in ASCII here.
	mov     cx,4
	call    b2asc10                 ; convert to ASCII...(R_CODE)

	mov     ax,es:[UMBptr]           ; first UMB address
	mov     di,offset LAST:UMBstart
	call    b2ascHEX
	mov     byte ptr [di+1],'H'     ; Put H at end of the segment

	mov     dx,offset LAST:UMBStatusMess
	mov     ah,PRINT_STRING
	int     MS_DOS                  ; output message

EXSexit:
	pop     di
	pop     es
	pop     ds
	ret
;
E_XStatus_Display       endp

;******************************************************************************
;
;       b2asc10 - Converts binary to ascii decimal and stores at ES:DI.
;                 Stores CX ascii chars (decimal # is right justified and
;                 filled on left with blanks).
;
;       entry:  ax = binary number
;               cx = digits to display
;               es:di = place to store ascii chars.
;
;       exit:   ASCII decimal representation of number stored at DS:DI
;
;       used:   none
;
;       stack:
;
;******************************************************************************
;
power10         dw      1,10,100,1000,10000
;
b2asc10_far     proc    far
	call    b2asc10
	ret
b2asc10_far     endp
;
b2asc10 proc    near
;
	push    ax
	push    bx
	push    cx
	push    dx
	push    si
;
	mov     si,cx                   ; index to base 10 table
	dec     si
	shl     si,1                    ;word index
	xor     bl,bl                   ; leading zeroes flag
	cld
;
;   convert binary number to decimal ascii
;
b2_loop:
	xor     dx,dx                   ; clear word extension
	mov     cx,cs:power10[si]
	div     cx                      ; divide by power of 10
	or      bl,bl
	jnz     short b2_ascii
;
	or      ax,ax                   ; q: zero result?
	jnz     short b2_ascii          ;  n: go convert to ascii
;
	mov     al,' '                  ;  y: go blank fill
	jmp     short b2_make_strg              ;
;
b2_ascii:
	add     al,'0'                  ; put into ascii format
	mov     bl,1                    ; leading zeroes on
;
b2_make_strg:
;;      stosb                           ; put ascii number into string
	mov     byte ptr ds:[di], al
	inc     di

	mov     ax,dx
	sub     si,2                    ; decrement power of 10 pointer
	jg      short b2_loop           ; Q: Last digit?  N: Jump if not
	mov     al,dl
	and     al,0Fh
	add     al,'0'
;;      stosb
	mov     byte ptr ds:[di], al
	inc     di

;
	pop     si
	pop     dx
	pop     cx
	pop     bx
	pop     ax
	ret                             ; *** return ***
;
b2asc10 endp

;******************************************************************************
;
;       b2ascHEX- converts binary to ascii HEX and store at ES:DI
;                 stores 4 ascii chars (HEX # is right justified and
;                 filled on left with blanks)
;
;       entry:  ax = binary number
;               es:di = place to store ascii chars.
;
;       exit:   ASCII HEX representation of number stored at DS:DI
;
;       used:   none
;
;       stack:
;
;******************************************************************************
;
hextab          db      "0123456789ABCDEF"
;
b2ascHEX_far    proc    far
	call    b2ascHEX
	ret
b2ascHEX_far    endp
;
b2ascHEX proc   near
;
	push    ax
	push    bx
	push    cx
	push    dx

	cld                             ;forward,increment
	mov     dx,ax
	mov     cx,12
b2hex_loop:
	mov     bx,dx
	shr     bx,cl                   ; get highest nibble
	and     bx,0Fh                  ; nibble only
	mov     al,CS:hextab[bx]        ; get ASCII for it
;;      stosb                           ; store ASCII
	mov     byte ptr ds:[di], al
	inc     di

	sub     cx,4
	jge     short b2hex_loop

	pop     dx
	pop     cx
	pop     bx
	pop     ax
	ret
;
b2ascHEX endp

LAST    ends
	end
