📄 _vflat.asm
字号:
;****************************************************************************
;*
;* SciTech OS Portability Manager Library
;*
;* ========================================================================
;*
;* The contents of this file are subject to the SciTech MGL Public
;* License Version 1.0 (the "License"); you may not use this file
;* except in compliance with the License. You may obtain a copy of
;* the License at http://www.scitechsoft.com/mgl-license.txt
;*
;* Software distributed under the License is distributed on an
;* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
;* implied. See the License for the specific language governing
;* rights and limitations under the License.
;*
;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
;*
;* The Initial Developer of the Original Code is SciTech Software, Inc.
;* All Rights Reserved.
;*
;* ========================================================================
;*
;* Based on original code Copyright 1994 Otto Chrons
;*
;* Language: 80386 Assembler, TASM 4.0 or later
;* Environment: IBM PC 32 bit protected mode
;*
;* Description: Low level page fault handler for virtual linear framebuffers.
;*
;****************************************************************************
IDEAL
JUMPS
include "scitech.mac" ; Memory model macros
header _vflat ; Set up memory model
VFLAT_START EQU 0F0000000h
VFLAT_END EQU 0F03FFFFFh
PAGE_PRESENT EQU 1
PAGE_NOTPRESENT EQU 0
PAGE_READ EQU 0
PAGE_WRITE EQU 2
ifdef DOS4GW
;----------------------------------------------------------------------------
; DOS4G/W flat linear framebuffer emulation.
;----------------------------------------------------------------------------
begdataseg _vflat
; Near pointers to the page directory base and our page tables. All of
; this memory is always located in the first Mb of DOS memory.
PDBR dd 0 ; Page directory base register (CR3)
accessPageAddr dd 0
accessPageTable dd 0
; CauseWay page directory & 1st page table linear addresses.
CauseWayDIRLinear dd 0
CauseWay1stLinear dd 0
; Place to store a copy of the original Page Table Directory before we
; intialised our virtual buffer code.
pageDirectory: resd 1024 ; Saved page table directory
ValidCS dw 0 ; Valid CS for page faults
Ring0CS dw 0 ; Our ring 0 code selector
LastPage dd 0 ; Last page we mapped in
BankFuncBuf: resb 101 ; Place to store bank switch code
BankFuncPtr dd offset BankFuncBuf
INT14Gate:
INT14Offset dd 0 ; eip of original vector
INT14Selector dw 0 ; cs of original vector
cextern _PM_savedDS,USHORT
cextern VF_haveCauseWay,BOOL
enddataseg _vflat
begcodeseg _vflat ; Start of code segment
cextern VF_malloc,FPTR
;----------------------------------------------------------------------------
; PF_handler64k - Page fault handler for 64k banks
;----------------------------------------------------------------------------
; The handler below is a 32 bit ring 0 page fault handler. It receives
; control immediately after any page fault or after an IRQ6 (hardware
; interrupt). This provides the fastest possible handling of page faults
; since it jump directly here. If this is a page fault, the number
; immediately on the stack will be an error code, at offset 4 will be
; the eip of the faulting instruction, at offset 8 will be the cs of the
; faulting instruction. If it is a hardware interrupt, it will not have
; the error code and the eflags will be at offset 8.
;----------------------------------------------------------------------------
cprocfar PF_handler64k
; Check if this is a processor exeception or a page fault
push eax
mov ax,[cs:ValidCS] ; Use CS override to access data
cmp [ss:esp+12],ax ; Is this a page fault?
jne @@ToOldHandler ; Nope, jump to the previous handler
; Get address of page fault and check if within our handlers range
mov eax,cr2 ; EBX has page fault linear address
cmp eax,VFLAT_START ; Is the fault less than ours?
jb @@ToOldHandler ; Yep, go to previous handler
cmp eax,VFLAT_END ; Is the fault more than ours?
jae @@ToOldHandler ; Yep, go to previous handler
; This is our page fault, so we need to handle it
pushad
push ds
push es
mov ebx,eax ; EBX := page fault address
and ebx,invert 0FFFFh ; Mask to 64k bank boundary
mov ds,[cs:_PM_savedDS]; Load segment registers
mov es,[cs:_PM_savedDS]
; Map in the page table for our virtual framebuffer area for modification
mov edi,[PDBR] ; EDI points to page directory
mov edx,ebx ; EDX = linear address
shr edx,22 ; EDX = offset to page directory
mov edx,[edx*4+edi] ; EDX = physical page table address
mov eax,edx
mov edx,[accessPageTable]
or eax,7
mov [edx],eax
mov eax,cr3
mov cr3,eax ; Update page table cache
; Mark all pages valid for the new page fault area
mov esi,ebx ; ESI := linear address for page
shr esi,10
and esi,0FFFh ; Offset into page table
add esi,[accessPageAddr]
ifdef USE_NASM
%assign off 0
%rep 16
or [DWORD esi+off],0000000001h ; Enable pages
%assign off off+4
%endrep
else
off = 0
REPT 16
or [DWORD esi+off],0000000001h ; Enable pages
off = off+4
ENDM
endif
; Mark all pages invalid for the previously mapped area
xchg esi,[LastPage] ; Save last page for next page fault
test esi,esi
jz @@DoneMapping ; Dont update if first time round
ifdef USE_NASM
%assign off 0
%rep 16
or [DWORD esi+off],0FFFFFFFEh ; Disable pages
%assign off off+4
%endrep
else
off = 0
REPT 16
and [DWORD esi+off],0FFFFFFFEh ; Disable pages
off = off+4
ENDM
endif
@@DoneMapping:
mov eax,cr3
mov cr3,eax ; Flush the TLB
; Now program the new SuperVGA starting bank address
mov eax,ebx ; EAX := page fault address
shr eax,16
and eax,0FFh ; Mask to 0-255
call [BankFuncPtr] ; Call the bank switch function
pop es
pop ds
popad
pop eax
add esp,4 ; Pop the error code from stack
iretd ; Return to faulting instruction
@@ToOldHandler:
pop eax
ifdef USE_NASM
jmp far dword [cs:INT14Gate]; Chain to previous handler
else
jmp [FWORD cs:INT14Gate]; Chain to previous handler
endif
cprocend
;----------------------------------------------------------------------------
; PF_handler4k - Page fault handler for 4k banks
;----------------------------------------------------------------------------
; The handler below is a 32 bit ring 0 page fault handler. It receives
; control immediately after any page fault or after an IRQ6 (hardware
; interrupt). This provides the fastest possible handling of page faults
; since it jump directly here. If this is a page fault, the number
; immediately on the stack will be an error code, at offset 4 will be
; the eip of the faulting instruction, at offset 8 will be the cs of the
; faulting instruction. If it is a hardware interrupt, it will not have
; the error code and the eflags will be at offset 8.
;----------------------------------------------------------------------------
cprocfar PF_handler4k
; Fill in when we have tested all the 64Kb code
ifdef USE_NASM
jmp far dword [cs:INT14Gate]; Chain to previous handler
else
jmp [FWORD cs:INT14Gate]; Chain to previous handler
endif
cprocend
;----------------------------------------------------------------------------
; void InstallFaultHandler(void *baseAddr,int bankSize)
;----------------------------------------------------------------------------
; Installes the page fault handler directly int the interrupt descriptor
; table for maximum performance. This of course requires ring 0 access,
; but none of this stuff will run without ring 0!
;----------------------------------------------------------------------------
cprocstart InstallFaultHandler
ARG baseAddr:ULONG, bankSize:UINT
enter_c
mov [DWORD LastPage],0 ; No pages have been mapped
mov ax,cs
mov [ValidCS],ax ; Save CS value for page faults
; Put address of our page fault handler into the IDT directly
sub esp,6 ; Allocate space on stack
ifdef USE_NASM
sidt [ss:esp] ; Store pointer to IDT
else
sidt [FWORD ss:esp] ; Store pointer to IDT
endif
pop ax ; add esp,2
pop eax ; Absolute address of IDT
add eax,14*8 ; Point to Int #14
; Note that Interrupt gates do not have the high and low word of the
; offset in adjacent words in memory, there are 4 bytes separating them.
mov ecx,[eax] ; Get cs and low 16 bits of offset
mov edx,[eax+6] ; Get high 16 bits of offset in dx
shl edx,16
mov dx,cx ; edx has offset
mov [INT14Offset],edx ; Save offset
shr ecx,16
mov [INT14Selector],cx ; Save original cs
mov [eax+2],cs ; Install new cs
mov edx,offset PF_handler64k
cmp [UINT bankSize],4
jne @@1
mov edx,offset PF_handler4k
@@1: mov [eax],dx ; Install low word of offset
shr edx,16
mov [eax+6],dx ; Install high word of offset
leave_c
ret
cprocend
;----------------------------------------------------------------------------
; void RemoveFaultHandler(void)
;----------------------------------------------------------------------------
; Closes down the virtual framebuffer services and restores the previous
; page fault handler.
;----------------------------------------------------------------------------
cprocstart RemoveFaultHandler
enter_c
; Remove page fault handler from IDT
sub esp,6 ; Allocate space on stack
ifdef USE_NASM
sidt [ss:esp] ; Store pointer to IDT
else
sidt [FWORD ss:esp] ; Store pointer to IDT
endif
pop ax ; add esp,2
pop eax ; Absolute address of IDT
add eax,14*8 ; Point to Int #14
mov cx,[INT14Selector]
mov [eax+2],cx ; Restore original CS
mov edx,[INT14Offset]
mov [eax],dx ; Install low word of offset
shr edx,16
mov [eax+6],dx ; Install high word of offset
leave_c
ret
cprocend
;----------------------------------------------------------------------------
; void InstallBankFunc(int codeLen,void *bankFunc)
;----------------------------------------------------------------------------
; Installs the bank switch function by relocating it into our data segment
; and making it into a callable function. We do it this way to make the
; code identical to the way that the VflatD devices work under Windows.
;----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -