649 lines
17 KiB
NASM
649 lines
17 KiB
NASM
PAGE 58,132
|
|
;******************************************************************************
|
|
TITLE VFLATD.ASM - Virtual Flat Device
|
|
;******************************************************************************
|
|
;
|
|
; (C) Copyright MICROSOFT Corp., 1987, 1988, 1989
|
|
;
|
|
; Title: VFLATD.ASM - Virtual flat video buffer Device
|
|
;
|
|
; This virtual device simulates a flat video display buffer on
|
|
; hardware that is designed to map video memory 64k at a time
|
|
; at segment A000. The video card is assumed to have 512K VRAM
|
|
;
|
|
; It does this by alocating 512k of linear address space and
|
|
; handling the pages faults in this memory
|
|
;
|
|
; Our PageFault handler is last in the chain, it will only be called
|
|
; by Win386 on pages it does not reconize (ie PT_RESERVED2 pages)
|
|
; this keeps the PageFault overhead to a minimum.
|
|
;
|
|
; Only 16 pages are marked present at a time these corespond to
|
|
; the current 64k hunk of memory mapped by the video card at A0000.
|
|
;
|
|
; When a PageFault occurs the 16 curently present pages are marked
|
|
; not present and a new set of 16 are marked as present. The
|
|
; Video hardware is instructed to map in the 64k page that caused
|
|
; the page fault.
|
|
;
|
|
; PM API Services:
|
|
;
|
|
; Get_Ver (DX = 0000)
|
|
;
|
|
; returns
|
|
; AX version of VFLATD (1.0)
|
|
;
|
|
; Get_Video_Base (DX = 0001)
|
|
;
|
|
; returns
|
|
; AX selector to the video buffer
|
|
; EDX Linear Address of video buffer
|
|
;
|
|
; Reset (DX = 0002)
|
|
; Assume the hardware 64k bank has been modifed and readjust
|
|
; the PageTable mapping
|
|
;
|
|
; returns
|
|
; nothing
|
|
;
|
|
; Version: 1.00
|
|
;
|
|
; Date: 15-Sep-1989
|
|
;
|
|
; Author: LDS
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; Change log:
|
|
;
|
|
; DATE REV DESCRIPTION
|
|
; ----------- --- -----------------------------------------------------------
|
|
; 15-Sep-1989 LDS Original
|
|
;
|
|
;==============================================================================
|
|
;
|
|
; DESCRIPTION:
|
|
;
|
|
;
|
|
;******************************************************************************
|
|
|
|
.386p
|
|
|
|
;******************************************************************************
|
|
; I N C L U D E S
|
|
;******************************************************************************
|
|
|
|
IFDEF WIN31
|
|
%OUT SUPPORT FOR Windows 3.1
|
|
WIN31COMPAT=1
|
|
ENDIF
|
|
.XLIST
|
|
INCLUDE VMM.Inc
|
|
;; INCLUDE Debug.Inc
|
|
INCLUDE VFLATD.Inc
|
|
.LIST
|
|
|
|
;******************************************************************************
|
|
; V I R T U A L D E V I C E D E C L A R A T I O N
|
|
;******************************************************************************
|
|
|
|
Declare_Virtual_Device VflatD, \
|
|
<VflatD_Version shr 8>, \
|
|
<VflatD_Version and 255>,\
|
|
VFLATD_Control, \
|
|
VFLATD_Device_ID, \
|
|
UNDEFINED_INIT_ORDER, \
|
|
0, \
|
|
VFLATD_PM_API_Handler
|
|
|
|
;******************************************************************************
|
|
; L O C A L D A T A
|
|
;******************************************************************************
|
|
|
|
VxD_LOCKED_DATA_SEG
|
|
|
|
VFLATD_Video_Sel dw 0 ; GDT Selector to virtual frame buffer
|
|
|
|
VFLATD_SlidingWindowBase dd ? ;base of 64k sliding window
|
|
VFLATD_GDTBase df ? ;base of GDT
|
|
VFLATD_VideoSelGDT dd ? ;ptr to video sel's GDT entry
|
|
|
|
VxD_LOCKED_DATA_ENDS
|
|
|
|
IFDEF WIN31
|
|
VIDEO_BASE equ 0A0000h ; Physical start of VRAM
|
|
VIDEO_LIMIT equ 0100000h-1 ; 1M VRAM
|
|
VIDEO_NPAGES equ ((VIDEO_LIMIT + 4095) / 4096)
|
|
ENDIF
|
|
|
|
MAXBANKSWITCHSIZE equ 100 ;maximum size of bank switch code
|
|
|
|
;******************************************************************************
|
|
; D E V I C E C O N T R O L P R O C E D U R E
|
|
;******************************************************************************
|
|
|
|
VxD_LOCKED_CODE_SEG
|
|
|
|
;******************************************************************************
|
|
;
|
|
; VFLATD_Control
|
|
;
|
|
; DESCRIPTION:
|
|
; This is the VFLATD's control procedure.
|
|
;
|
|
; ENTRY:
|
|
; EAX = Control call ID
|
|
;
|
|
; EXIT:
|
|
; If carry clear then
|
|
; Successful
|
|
; else
|
|
; Control call failed
|
|
;
|
|
; USES:
|
|
; EAX, EBX, ECX, EDX, ESI, EDI, Flags
|
|
;
|
|
;==============================================================================
|
|
|
|
BeginProc VFLATD_Control
|
|
|
|
Control_Dispatch Device_Init, VFLATD_Device_Init
|
|
|
|
IFDEF DEBUG
|
|
Control_Dispatch Debug_Query, VFLATD_Debug_Query
|
|
ENDIF
|
|
clc ; Ignore other control calls
|
|
ret
|
|
|
|
EndProc VFLATD_Control
|
|
|
|
;******************************************************************************
|
|
; A P I H A N D L E R S F O R P M V M ' S
|
|
;******************************************************************************
|
|
|
|
VxD_DATA_SEG
|
|
|
|
VFLATD_API_Call_Table LABEL DWORD
|
|
dd OFFSET32 VFLATD_PM_API_Get_Ver
|
|
dd OFFSET32 VFLATD_PM_API_Get_Video_Base
|
|
dd OFFSET32 VFLATD_PM_API_Reset
|
|
|
|
VFLATD_Max_API_Function = ($ - VFLATD_API_Call_Table) / 4 - 1
|
|
|
|
VxD_DATA_ENDS
|
|
|
|
;******************************************************************************
|
|
;
|
|
; VFLATD_Device_Init
|
|
;
|
|
; DESCRIPTION:
|
|
;
|
|
; ENTRY:
|
|
;
|
|
; EXIT:
|
|
; C for error
|
|
;
|
|
; USES:
|
|
; All registers and flags
|
|
;
|
|
;==============================================================================
|
|
|
|
BeginProc VFLATD_Device_Init
|
|
|
|
clc
|
|
ret
|
|
|
|
EndProc VFLATD_Device_Init
|
|
|
|
;******************************************************************************
|
|
;
|
|
; VFLATD_PM_API_Handler
|
|
;
|
|
; DESCRIPTION:
|
|
;
|
|
; ENTRY:
|
|
; EBX = Handle of VM that called API
|
|
; EBP -> Client register structure
|
|
;
|
|
; EXIT:
|
|
; Client registers and flags may be altered
|
|
;
|
|
; USES:
|
|
; All registers and flags
|
|
;
|
|
;==============================================================================
|
|
|
|
BeginProc VFLATD_PM_API_Handler
|
|
|
|
movzx eax, [ebp.Client_DX]
|
|
cmp eax, VFLATD_Max_API_Function ; Q: Is this a valid function?
|
|
ja SHORT VFLATD_PM_API_Failed
|
|
CallRet VFLATD_API_Call_Table[eax*4]
|
|
|
|
VFLATD_PM_API_Failed:
|
|
or [ebp.Client_EFlags], CF_Mask
|
|
ret
|
|
|
|
VFLATD_PM_API_Success:
|
|
and [ebp.Client_EFlags], NOT CF_Mask
|
|
ret
|
|
|
|
EndProc VFLATD_PM_API_Handler
|
|
|
|
;******************************************************************************
|
|
;
|
|
; VFLATD_PM_API_Get_Ver
|
|
;
|
|
; DESCRIPTION:
|
|
; Return the VFLATD version
|
|
;
|
|
; ENTRY:
|
|
; Client_DX = 0
|
|
;
|
|
; EXIT:
|
|
; Client_AX = 200h
|
|
; Client carry flag clear
|
|
;
|
|
; USES:
|
|
; EAX, Flags, Client_AX, Client_Flags
|
|
;
|
|
;==============================================================================
|
|
|
|
BeginProc VFLATD_PM_API_Get_Ver
|
|
|
|
mov [ebp.Client_AX], VflatD_Version
|
|
jmp VFLATD_PM_API_Success
|
|
|
|
EndProc VFLATD_PM_API_Get_Ver
|
|
|
|
;******************************************************************************
|
|
;
|
|
; VFLATD_PM_API_Get_Video_Base
|
|
;
|
|
; DESCRIPTION:
|
|
; Return a GDT selector to the flat video buffer
|
|
;
|
|
; ENTRY:
|
|
; Client_DX = 1
|
|
; Client_AX = # of pages of video memory
|
|
; Client_CX = size of bank switch code
|
|
; Client_ES:DI -> bank switch code
|
|
;~~~~~ document guidlines for bank switch code
|
|
;
|
|
; EXIT:
|
|
; Client_AX = Selector to flat video buffer
|
|
; Client_EDX = Linear base of flat video buffer (not usable)
|
|
; Client carry flag clear
|
|
;
|
|
; USES:
|
|
; EAX, Flags, Client_AX, Client_Flags
|
|
;
|
|
;==============================================================================
|
|
|
|
BeginProc VFLATD_PM_API_Get_Video_Base
|
|
|
|
cmp [ebp.Client_CX],MAXBANKSWITCHSIZE
|
|
ja VFLATD_PM_API_Failed ;bank switch code too big
|
|
|
|
cmp [VFLATD_Video_sel], 0
|
|
jne already_initialized
|
|
|
|
IFNDEF WIN31
|
|
movzx eax, [ebp.Client_AX]
|
|
add eax, eax
|
|
add eax, 64/4
|
|
push eax
|
|
VMMCall _MMReserve, <PR_SYSTEM, eax, PR_FIXED>
|
|
pop ecx
|
|
inc eax
|
|
jz VFLATD_PM_API_Failed
|
|
add eax, (64*1024-2)
|
|
ELSE
|
|
|
|
; allocate a hunk of linear address space to use as a virtual
|
|
; frame buffer eax = handle, edx = linear addr
|
|
;
|
|
|
|
VMMCall _MapPhysToLinear, <3*1024*1024*1024 - (2*1024*1024+64*1024),2*1024*1024+64*1024,0>
|
|
or eax, eax
|
|
jz VFLATD_PM_API_Failed
|
|
add eax,(64*1024-1)
|
|
ENDIF
|
|
|
|
|
|
; round up to 64Kb boundary
|
|
|
|
and eax, 0FFFF0000h
|
|
mov edx, eax
|
|
|
|
; Save linear addr of video buffer
|
|
;
|
|
mov esi, edx
|
|
|
|
IFNDEF WIN31
|
|
mov [VFLATD_Video_Base], edx
|
|
sub ecx, 64/4
|
|
shl ecx, 12 ; # of bytes in allocated region
|
|
dec ecx
|
|
lea ecx, [edx+ecx]
|
|
mov [VFLATD_Video_Top], ecx
|
|
|
|
shr esi, 12 ; virt page # of start of region
|
|
movzx ecx, [ebp.Client_AX]
|
|
add esi, ecx
|
|
VMMCall _MMCommitPhys, <esi, 16, 0A0h, PC_INCR+PC_USER+PC_WRITEABLE>
|
|
or eax, eax
|
|
jz VFLATD_PM_API_Failed
|
|
|
|
ELSE
|
|
mov [VFLATD_Video_Base],edx
|
|
mov eax,edx
|
|
add eax,2*VIDEO_LIMIT+1
|
|
mov [VFLATD_Video_Top],eax
|
|
|
|
; NOTE I dont handle the case where the frame buffer
|
|
; crosses multiple page tables, if it does, FAIL
|
|
;
|
|
shr edx,12
|
|
and edx,3FFh ; edx = page number
|
|
cmp edx,0400h - VIDEO_NPAGES
|
|
jg VFLATD_PM_API_Failed
|
|
|
|
; find the PTE that describes the base of video memory
|
|
;
|
|
mov eax,cr3 ; eax --> Physical base of page dir
|
|
VMMCall _MapPhysToLinear, <eax,4*1024,0>
|
|
mov edi,eax ; edi --> Linear base of page dir
|
|
|
|
mov eax,esi ; eax = linear video buffer base
|
|
shr eax,22 ; eax = page dir number
|
|
mov edi,[edi + 4*eax] ; edi = page dir entry (PDE)
|
|
and edi,not 0FFFh ; edi = physical addr of PT
|
|
|
|
mov eax,esi ; eax = linear video buffer base
|
|
shr eax,12
|
|
and eax,3FFh ; eax = page number
|
|
lea edi,[edi + 4*eax] ; edi = physical addr of PTE
|
|
|
|
VMMCall _MapPhysToLinear, <edi,VIDEO_NPAGES*4,0>
|
|
|
|
; now eax contains the Linear addr of our page table
|
|
;
|
|
; mark all pages as not present and set the page type to PT_RESERVED2
|
|
;
|
|
mov edi,eax
|
|
mov eax,PG_RESERVED2 OR P_WRITE OR P_USER
|
|
mov ecx,VIDEO_NPAGES
|
|
rep stosd
|
|
|
|
; mark the next 64K present and map it to the 64k of video memory.
|
|
|
|
m = 0
|
|
n = 0
|
|
|
|
REPT 16
|
|
mov dword ptr [edi+m],((VIDEO_BASE+n) OR PG_RESERVED2 OR P_AVAIL)
|
|
n = n + 1000h
|
|
m = m + 4
|
|
ENDM
|
|
add edi,m
|
|
|
|
; mark the next (VIDEO_NPAGES - 16) pages as not present.
|
|
|
|
mov eax,PG_RESERVED2 OR P_WRITE OR P_USER
|
|
mov ecx,VIDEO_NPAGES - 16
|
|
rep stosd
|
|
|
|
ENDIF
|
|
|
|
; allocate a GDT selector to give to PM programs
|
|
;
|
|
mov eax, [VFLATD_Video_Base]
|
|
movzx ecx, [ebp.Client_AX]
|
|
dec ecx
|
|
VMMCall _BuildDescriptorDWORDs, <eax,ecx,RW_Data_Type,D_GRAN_PAGE,0>
|
|
VMMCall _Allocate_GDT_Selector, <edx,eax,0>
|
|
mov [VFLATD_Video_sel],ax
|
|
or eax, eax
|
|
jz VFLATD_PM_API_Failed
|
|
|
|
mov edx, [VFLATD_Video_Base]
|
|
shr edx, 16
|
|
mov [VFLATD_SlidingWindowBase], edx
|
|
add edx, (1024*1024 SHR 16)
|
|
mov [VFLATD_PresentWindowBase], edx
|
|
|
|
sgdt [VFLATD_GDTBase]
|
|
mov edx, dword ptr [VFLATD_GDTBase+2]
|
|
and eax, 0fff8h
|
|
add edx, eax ;-> base of sel's GDT entry
|
|
add edx, 4
|
|
mov [VFLATD_VideoSelGDT_B2], edx
|
|
add edx, 3
|
|
mov [VFLATD_VideoSelGDT_B3], edx
|
|
|
|
pushfd
|
|
cli
|
|
sidt [VFLATD_GDTBase]
|
|
mov eax, dword ptr [VFLATD_GDTBase+2]
|
|
add eax, 14*8
|
|
mov esi, OFFSET32 VFLATD_Direct_PageFault_Handler
|
|
xchg word ptr [eax], si ; LSW
|
|
ror esi, 16
|
|
xchg word ptr [eax+6], si ; MSW
|
|
ror esi, 16 ; esi = old handler offset
|
|
sub esi, OFFSET32 next_handler + 4
|
|
mov [next_handler], esi
|
|
popfd
|
|
|
|
; make space for copying in the device specific bank switch code in the page
|
|
; fault handler and copy the code in.
|
|
|
|
mov esi, OFFSET32 VFLATD_EndOfDPH - 1
|
|
movzx edi, [ebp.Client_CX]
|
|
add edi, esi
|
|
std
|
|
mov ecx, VFLATD_EndOfDPH - VFLATD_DPH_BankSwitchCode
|
|
rep movsb
|
|
cld
|
|
|
|
Client_Ptr_Flat esi, ES, DI
|
|
mov edi, OFFSET32 VFLATD_DPH_BankSwitchCode
|
|
movzx ecx, [ebp.Client_CX]
|
|
rep movsb
|
|
|
|
already_initialized:
|
|
mov ax, [VFLATD_Video_Sel]
|
|
mov [ebp.Client_AX], ax
|
|
|
|
mov eax, [VFLATD_Video_Base]
|
|
mov [ebp.Client_EDX], eax
|
|
|
|
jmp VFLATD_PM_API_Success
|
|
|
|
EndProc VFLATD_PM_API_Get_Video_Base
|
|
|
|
;******************************************************************************
|
|
;
|
|
; VFLATD_PM_API_Reset
|
|
;
|
|
; DESCRIPTION:
|
|
; Called when Video card 64k page mapping has changed by someone other
|
|
; than VFLATD, We mark not present any pages we think are currently
|
|
; mapped to the hardware.
|
|
;
|
|
; ENTRY:
|
|
; Client_DX = 2
|
|
;
|
|
; EXIT:
|
|
; Client carry flag clear
|
|
;
|
|
; USES:
|
|
; EAX, Flags, Client_AX, Client_Flags
|
|
;
|
|
;==============================================================================
|
|
|
|
BeginProc VFLATD_PM_API_Reset
|
|
|
|
; pretend we got a page fault on page zero so the bank gets
|
|
; setup right.
|
|
;
|
|
; we need to fake up a fault frame, and jump into the
|
|
; fault handler.
|
|
|
|
; int 3
|
|
|
|
pushfd ; iretd frame flags
|
|
push cs
|
|
push OFFSET32 VFLATD_PM_API_Success ; iretd frame return
|
|
push 0 ; fault type
|
|
push 0 ; saved eax (cr2)
|
|
mov eax,[VFLATD_Video_Base] ; faulting address (fake cr2)
|
|
jmp short VFLATD_Handle_Fault
|
|
|
|
EndProc VFLATD_PM_API_Reset
|
|
|
|
;******************************************************************************
|
|
; H A R D W A R E I N T E R R U P T P R O C E D U R E S
|
|
;******************************************************************************
|
|
|
|
;******************************************************************************
|
|
;
|
|
; BeginProc VFLATD_Direct_PageFault_Handler
|
|
;
|
|
; DESCRIPTION:
|
|
;
|
|
; ENTRY:
|
|
;
|
|
; EXIT:
|
|
;
|
|
; USES:
|
|
;
|
|
;==============================================================================
|
|
|
|
BeginProc VFLATD_Direct_PageFault_Handler, NO_PROLOG, HIGH_FREQ
|
|
|
|
push eax
|
|
mov eax,cr2
|
|
|
|
; Is the fault for us? or in other words does it fall in our
|
|
; virtual video buffer.
|
|
;
|
|
cmp eax,12345678h
|
|
VFLATD_Video_Base equ dword ptr $-4
|
|
|
|
jb short VFLATD_Chain_Fault
|
|
|
|
cmp eax,12345678h
|
|
VFLATD_Video_Top equ dword ptr $-4
|
|
|
|
jb short VFLATD_Handle_Fault
|
|
|
|
VFLATD_Chain_Fault: ;Chain the PageFault to the next guy in the chain
|
|
pop eax
|
|
;; jmp next_handler
|
|
db 0E9h
|
|
next_handler dd ?
|
|
|
|
; NOTE we jump here from VFLATD_PM_API_Reset
|
|
|
|
VFLATD_Handle_Fault:
|
|
push ds
|
|
push es
|
|
push edx
|
|
|
|
; Calculate what 64k bank the fault occured in.
|
|
;
|
|
shr eax, 16
|
|
sub eax, ss:[VFLATD_SlidingWindowBase] ; eax = bank #
|
|
|
|
;==============================================================================
|
|
; >>>>>>>>>>>>> BANK SWITCH CODE GETS INSERTED HERE <<<<<<<<<<<<<<<<<<
|
|
;==============================================================================
|
|
VFLATD_DPH_BankSwitchCode label byte
|
|
|
|
; we shift the code from here upto the label "VFLATD_EndOfDPH" down to
|
|
; accomodate device specific bank switch code.
|
|
|
|
;==============================================================================
|
|
|
|
mov edx, 12345678h
|
|
VFLATD_PresentWindowBase equ dword ptr $-4
|
|
|
|
sub edx, eax
|
|
mov ss:[VFLATD_SlidingWindowBase], edx
|
|
;
|
|
; modify the selector base
|
|
;
|
|
mov ss:[12345678h], dl
|
|
VFLATD_VideoSelGDT_B2 equ dword ptr $-4
|
|
|
|
mov ss:[12345678h], dh
|
|
VFLATD_VideoSelGDT_B3 equ dword ptr $-4
|
|
|
|
pop edx
|
|
pop es
|
|
pop ds
|
|
pop eax
|
|
add esp, 4
|
|
iretd
|
|
|
|
EndProc VFLATD_Direct_PageFault_Handler
|
|
|
|
VFLATD_EndOfDPH label byte
|
|
db MAXBANKSWITCHSIZE dup (?) ;space for handler to grow when bank
|
|
; switching
|
|
|
|
VxD_LOCKED_CODE_ENDS
|
|
|
|
;******************************************************************************
|
|
; D E B U G G I N G C O D E
|
|
;******************************************************************************
|
|
|
|
;******************************************************************************
|
|
;
|
|
; VFLATD_Debug_Query
|
|
;
|
|
; DESCRIPTION:
|
|
; This procedure is only assembled in the debug version of VFLATD.
|
|
;
|
|
; Note that since this procedure can be called at any time by the
|
|
; debugger it is not allowed to call any non-asynchronous services and
|
|
; it must be in a LOCKED code segment.
|
|
;
|
|
; ENTRY:
|
|
; EAX = Debug_Query (equate)
|
|
;
|
|
; EXIT:
|
|
; None
|
|
;
|
|
; USES:
|
|
; EBX, ECX, EDX, ESI, Flags
|
|
;
|
|
;==============================================================================
|
|
|
|
IFDEF DEBUG
|
|
|
|
VxD_LOCKED_CODE_SEG
|
|
|
|
BeginProc VFLATD_Debug_Query
|
|
|
|
; Trace_Out "******* VFLATD Debug_Query *******"
|
|
|
|
mov eax, VFLATD_Video_Base
|
|
; Trace_Out "Video_Base: #EAX"
|
|
|
|
mov ax, VFLATD_Video_Sel
|
|
; Trace_Out "Video_Sel: #AX"
|
|
|
|
VFLATD_DQ_Exit:
|
|
ret
|
|
|
|
EndProc VFLATD_Debug_Query
|
|
|
|
VxD_LOCKED_CODE_ENDS
|
|
|
|
ENDIF
|
|
|
|
END
|