windows-nt/Source/XPSP1/NT/multimedia/media/avi/drawdib.16/vflatd/vflatd.asm
2020-09-26 16:20:57 +08:00

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