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_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, 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, 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, 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, ; 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, VMMCall _Allocate_GDT_Selector, 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