📄 _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 JUMPSinclude "scitech.mac" ; Memory model macrosheader _vflat ; Set up memory modelVFLAT_START EQU 0F0000000hVFLAT_END EQU 0F03FFFFFhPAGE_PRESENT EQU 1PAGE_NOTPRESENT EQU 0PAGE_READ EQU 0PAGE_WRITE EQU 2ifdef 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 0accessPageTable dd 0; CauseWay page directory & 1st page table linear addresses.CauseWayDIRLinear dd 0CauseWay1stLinear 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 directoryValidCS dw 0 ; Valid CS for page faultsRing0CS dw 0 ; Our ring 0 code selectorLastPage dd 0 ; Last page we mapped inBankFuncBuf: resb 101 ; Place to store bank switch codeBankFuncPtr dd offset BankFuncBufINT14Gate:INT14Offset dd 0 ; eip of original vectorINT14Selector dw 0 ; cs of original vector cextern _PM_savedDS,USHORT cextern VF_haveCauseWay,BOOLenddataseg _vflatbegcodeseg _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%endrepelseoff = 0REPT 16 or [DWORD esi+off],0000000001h ; Enable pagesoff = off+4ENDMendif; 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 roundifdef USE_NASM%assign off 0%rep 16 or [DWORD esi+off],0FFFFFFFEh ; Disable pages%assign off off+4%endrepelseoff = 0REPT 16 and [DWORD esi+off],0FFFFFFFEh ; Disable pagesoff = off+4ENDMendif@@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 eaxifdef USE_NASM jmp far dword [cs:INT14Gate]; Chain to previous handlerelse jmp [FWORD cs:INT14Gate]; Chain to previous handlerendifcprocend;----------------------------------------------------------------------------; 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 codeifdef USE_NASM jmp far dword [cs:INT14Gate]; Chain to previous handlerelse jmp [FWORD cs:INT14Gate]; Chain to previous handlerendifcprocend;----------------------------------------------------------------------------; 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 stackifdef USE_NASM sidt [ss:esp] ; Store pointer to IDTelse sidt [FWORD ss:esp] ; Store pointer to IDTendif 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 retcprocend;----------------------------------------------------------------------------; 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 stackifdef USE_NASM sidt [ss:esp] ; Store pointer to IDTelse sidt [FWORD ss:esp] ; Store pointer to IDTendif 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 retcprocend;----------------------------------------------------------------------------; 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 + -