;****************************************************************************
;*
;* VFlat - DOS Virtual Flat Linear Framebuffer
;*
;* Copyright (C) 1996 SciTech Software
;* All rights reserved.
;*
;* Based on original code Copyright 1994 Otto Chrons
;*
;* Filename: $Workfile: _vflat.asm $
;* Version: $Revision: 1.1 $
;*
;* Language: 80386 Assembler, TASM 4.0 or later
;* Environment: IBM PC 32 bit protected mode
;*
;* Description: Low level page fault handler for re-mapping the SuperVGA
;* to the new bank.
;*
;* $Date: 12 Feb 1996 21:58:56 $ $Author: KendallB $
;*
;****************************************************************************
IDEAL
JUMPS
INCLUDE "model.mac" ; Memory model macros
header _vflat ; Set up memory model
VFLAT_START = 0F0000000h
VFLAT_END = 0F03FFFFFh
PAGE_PRESENT = 1
PAGE_NOTPRESENT = 0
PAGE_READ = 0
PAGE_WRITE = 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
; Place to store a copy of the original Page Table Directory before we
; intialised our virtual buffer code.
pageDirectory dd 1024 DUP(?) ; 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 db 101 dup (?) ; Place to store bank switch code
BankFuncPtr dd offset BankFuncBuf
label INT14Gate FWORD
INT14Offset dd 0 ; eip of original vector
INT14Selector dw 0 ; cs of original vector
$EXTRN _PM_savedDS,USHORT
$EXTRN _VF_zeroSel,USHORT
$EXTRN _VF_haveCauseWay,BOOL
enddataseg _vflat
begcodeseg _vflat ; Start of code segment
EXTRN _VF_malloc:FPTR
;----------------------------------------------------------------------------
; EnableRing0
;----------------------------------------------------------------------------
; Enables ring 0 operation using DOS extender specific functions. Note
; that this is a 16 bit protected mode function, not 32 bit code so it needs
; to remain in a separate file.
;----------------------------------------------------------------------------
PROC EnableRing0
pusha
cmp [_VF_haveCauseWay],0
je @@Exit
; TODO: Enable Ring 0 under CauseWay
@@Exit: popa
ret
ENDP
;----------------------------------------------------------------------------
; DisableRing0
;----------------------------------------------------------------------------
; Enables ring 0 operation using DOS extender specific functions.
;----------------------------------------------------------------------------
PROC DisableRing0
pusha
cmp [_VF_haveCauseWay],0
je @@Exit
; TODO: Disable Ring 0 under CauseWay
@@Exit: popa
ret
ENDP
;----------------------------------------------------------------------------
; 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.
;----------------------------------------------------------------------------
PROC PF_handler64k far
; 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 es ds
mov ebx,eax ; EBX := page fault address
and ebx,not 0FFFFh ; Mask to 64k bank boundary
mov ds,[cs:_PM_savedDS] ; Load segment registers
mov es,[_VF_zeroSel]
; 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]
off = 0
REPT 16
or [DWORD esi+off],0000000001h ; Enable pages
off = off+4
ENDM
; 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
off = 0
REPT 16
and [DWORD esi+off],0FFFFFFFEh ; Disable pages
off = off+4
ENDM
@@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 ds es
popad
pop eax
add esp,4 ; Pop the error code from stack
iretd ; Return to faulting instruction
@@ToOldHandler:
pop eax
jmp [cs:INT14Gate] ; Chain to previous handler
ENDP PF_handler64k
;----------------------------------------------------------------------------
; 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.
;----------------------------------------------------------------------------
PROC PF_handler4k far
; Fill in when we have tested all the 64Kb code
jmp [cs:INT14Gate] ; Chain to previous handler
ENDP PF_handler4k
;----------------------------------------------------------------------------
; 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!
;----------------------------------------------------------------------------
procstart _InstallFaultHandler
ARG baseAddr:ULONG, bankSize:UINT
enter_c 0
mov [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
sidt [FWORD ss:esp] ; Store pointer to IDT
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 [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_nolocal
ret
procend _InstallFaultHandler
;----------------------------------------------------------------------------
; void RemoveFaultHandler(void)
;----------------------------------------------------------------------------
; Closes down the virtual framebuffer services and restores the previous
; page fault handler.
;----------------------------------------------------------------------------
procstart _RemoveFaultHandler
enter_c 0
; Remove page fault handler from IDT
sub esp,6 ; Allocate space on stack
sidt [FWORD ss:esp] ; Store pointer to IDT
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_nolocal
ret
procend _RemoveFaultHandler
;----------------------------------------------------------------------------
; 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.
;----------------------------------------------------------------------------
procstart _InstallBankFunc
ARG codeLen:UINT, bankFunc:DPTR
enter_c 0
mov esi,[bankFunc] ; Copy the code into buffer
mov edi,offset bankFuncBuf
mov ecx,[codeLen]
rep movsb
mov [BYTE edi],0C3h ; Terminate the function with a near ret
leave_c_nolocal
ret
procend _InstallBankFunc
;----------------------------------------------------------------------------
; int InitPaging(void)
;----------------------------------------------------------------------------
; Initializes paging system. If paging is not enabled, builds a page table
; directory and page tables for physical memory
;
; Exit: 0 - Successful
; -1 - Couldn't initialize paging mechanism
;----------------------------------------------------------------------------
procstart _InitPaging
push ebx ecx edx esi edi
call EnableRing0 ; Enable ring 0 mode
mov ax,cs
test ax,3 ; Which ring are we running
jnz @@errexit ; Needs zero ring to access
; page tables (CR3)
mov eax,cr0 ; Load CR0
test eax,80000000h ; Is paging enabled?
jz @@errExit ; No, we must have paging!
mov eax,cr3 ; Load directory address
and eax,0FFFFF000h
mov [PDBR],eax ; Save it
mov esi,eax
mov edi,offset pageDirectory
mov ecx,1024
cld
rep movsd ; Copy the original page table directory
cmp [accessPageAddr],0 ; Check if we have allocated page
jne @@HaveRealMem ; table already (we cant free it)
mov eax,0100h ; DPMI DOS allocate
mov ebx,8192/16
int 31h ; Allocate 8192 bytes
and eax,0FFFFh
shl eax,4 ; EAX points to newly allocated memory
add eax,4095
and eax,0FFFFF000h ; Page align
mov [accessPageAddr],eax
@@HaveRealMem:
mov eax,[accessPageAddr] ; EAX -> page table in 1st Mb
shr eax,12
and eax,3FFh ; Page table offset
shl eax,2
mov ebx,[PDBR]
mov ebx,[ebx]
and ebx,0FFFFF000h ; Page table for 1st megabyte
add eax,ebx
mov [accessPageTable],eax
sub eax,eax ; No error
jmp @@exit
@@errExit:
mov eax,-1
@@exit: call DisableRing0 ; Return to ring 3 code
pop edi esi edx ecx ebx
ret
procend _InitPaging
;----------------------------------------------------------------------------
; void ClosePaging(void)
;----------------------------------------------------------------------------
; Closes the paging system
;----------------------------------------------------------------------------
procstart _ClosePaging
push eax esi edi ecx edx
call EnableRing0 ; Enable ring 0 mode
mov eax,[accessPageAddr]
call AccessPage ; Restore AccessPage mapping
mov edi,[PDBR]
mov esi,offset pageDirectory
mov ecx,1024
cld
rep movsd ; Restore the original page table directory
call DisableRing0 ; Return to ring 3 code
pop edx ecx edi esi eax
ret
procend _ClosePaging
;----------------------------------------------------------------------------
; long AccessPage(long phys)
;----------------------------------------------------------------------------
; Maps a known page to given physical memory
; Entry: EAX - Physical memory
; Exit: EAX - Linear memory address of mapped phys mem
;----------------------------------------------------------------------------
PROC AccessPage
push edx
mov edx,[accessPageTable]
or eax,7
mov [edx],eax
mov eax,cr3
mov cr3,eax ; Update page table cache
mov eax,[accessPageAddr]
pop edx
ret
ENDP
;----------------------------------------------------------------------------
; long GetPhysicalAddress(long linear)
;----------------------------------------------------------------------------
; Returns the physical address of linear address
; Entry: EAX - Linear address to convert
; Exit: EAX - Physical address
;----------------------------------------------------------------------------
PROC GetPhysicalAddress
push edx ebx
mov edx,eax
shr edx,22 ; EDX is the directory offset
mov ebx,[PDBR]
mov edx,[edx*4+ebx] ; Load page table address
push eax
mov eax,edx
call AccessPage ; Access the page table
mov edx,eax
pop eax
shr eax,12
and eax,03FFh ; EAX offset into page table
mov eax,[edx+eax*4] ; Load physical address
and eax,0FFFFF000h
pop ebx edx
ret
ENDP
;----------------------------------------------------------------------------
; void CreatePageTable(long pageDEntry)
;----------------------------------------------------------------------------
; Creates a page table for specific address (4MB)
; Entry: EAX - Page directory entry (top 10-bits of address)
;----------------------------------------------------------------------------
PROC CreatePageTable
push ebx edx edi ecx
mov ebx,eax ; Save address
mov eax,8192
push eax
call _VF_malloc ; Allocate page table directory
add esp,4
add eax,0FFFh
and eax,0FFFFF000h ; Page align (4KB)
mov edi,eax ; Save page table linear address
sub eax,eax ; Fill with zero
mov ecx,1024
cld
rep stosd ; Clear page table
sub edi,4096
mov eax,edi
call GetPhysicalAddress
mov edx,[PDBR]
or eax,7 ; Present/write/user bit
mov [edx+ebx*4],eax ; Save physical address into page directory
mov eax,cr3
mov cr3,eax ; Update page table cache
pop ecx edi edx ebx
ret
ENDP
;----------------------------------------------------------------------------
; void MapPhysical2Linear(ulong pAddr, ulong lAddr, int pages, int flags);
;----------------------------------------------------------------------------
; Maps physical memory into linear memory
; Entry: pAddr - Physical address
; lAddr - Linear address
; pages - Number of 4K pages to map
; flags - Page flags
; bit 0 = present
; bit 1 = Read(0)/Write(1)
;----------------------------------------------------------------------------
procstart _MapPhysical2Linear
ARG pAddr:ULONG, lAddr:ULONG, pages:UINT, pflags:UINT
enter_c 0
call EnableRing0 ; Enable ring 0 mode
and [pAddr],0FFFFF000h ; Page boundary
and [lAddr],0FFFFF000h ; Page boundary
mov ecx,[pFlags]
and ecx,11b ; Just two bits
or ecx,100b ; Supervisor bit
mov [pflags],ecx
mov edx,[lAddr]
shr edx,22 ; EDX = Directory
mov esi,[PDBR]
mov edi,[pages] ; EDI page count
mov ebx,[lAddr]
@@CreateLoop:
mov ecx,[esi+edx*4] ; Load page table address
test ecx,1 ; Is it present?
jnz @@TableOK
mov eax,edx
call CreatePageTable ; Create a page table
@@TableOK:
mov eax,ebx
shr eax,12
and eax,3FFh
sub eax,1024
neg eax ; EAX = page count in this table
inc edx ; Next table
mov ebx,0 ; Next time we'll map 1K pages
sub edi,eax ; Subtract mapped pages from page count
jns @@CreateLoop ; Create more tables if necessary
mov ecx,[pages] ; ECX = Page count
mov esi,[lAddr]
shr esi,12 ; Offset part isn't needed
mov edi,[pAddr]
@@MappingLoop:
mov eax,esi
shr eax,10 ; EAX = offset to page directory
mov ebx,[PDBR]
mov eax,[eax*4+ebx] ; EAX = page table address
call AccessPage
mov ebx,esi
and ebx,3FFh ; EBX = offset to page table
mov edx,edi
add edi,4096 ; Next physical address
inc esi ; Next linear page
or edx,[pflags] ; Update flags...
mov [eax+ebx*4],edx ; Store page table entry
loop @@mappingLoop
mov eax,cr3
mov cr3,eax ; Update page table cache
call DisableRing0 ; Return to ring 3 code
leave_c_nolocal
ret
procend _MapPhysical2Linear
endcodeseg _vflat
endif
ifdef X32VM
;----------------------------------------------------------------------------
; FlashTek X32 flat linear framebuffer emulation. Based on original code
; graciously contributed by Kevin Aguilar. Thanks Kevin!
;----------------------------------------------------------------------------
begdataseg _vflat
Installed dd 0 ; Is our handler installed?
ValidCS dw 0 ; Valid CS for page faults
Ring0CS dw 0 ; Our ring 0 code selector
LastPage dd 0h ; Page table addr of last mapped in page
BankFuncBuf db 101 dup (?) ; Place to store bank switch code
BankFuncPtr dd offset BankFuncBuf
label INT14Gate FWORD
INT14Offset dd 0 ; eip of original vector
INT14Selector dw 0 ; cs of original vector
$EXTRN _PM_savedDS,USHORT
$EXTRN __x386_zero_base_selector,WORD
$EXTRN __x386_zero_base_ptr,DWORD
ZeroBase EQU [__x386_zero_base_ptr]
enddataseg _vflat
begcodeseg _vflat ; Start of code segment
;----------------------------------------------------------------------------
; 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.
;----------------------------------------------------------------------------
PROC PF_handler64k far
; Check if this is a processor exeception or a page fault
movzx esp,sp
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 es ds
mov ebx,eax ; Save for bank switch code below
and ebx,not 0FFFFh ; Mask to 64k bank boundary
mov ds,[cs:_PM_savedDS] ; Load segment registers
mov es,[cs:__x386_zero_base_selector]
; Mark all pages valid for the new page fault area
shr eax,10 ; Divide by 1024
and al,0c0h ; Group page tables in 64k blocks
add eax,400000h ; Point to page table block
mov edi,eax ; Use as a pointer
off = 0
REPT 16
or [DWORD esi+off],0000000001h ; Enable pages
off = off+4
ENDM
; Mark all pages invalid for the previously mapped area
xchg edi,[LastPage] ; Save last page for next page fault
test edi,edi
jz @@DoneMapping ; Dont update if first time round
off = 0
REPT 16
and [DWORD esi+off],0FFFFFFFEh ; Disable pages
off = off+4
ENDM
@@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 ds es
popad
pop eax
add esp,4 ; Pop the error code from stack
iretd ; Return to faulting instruction
@@ToOldHandler:
pop eax
jmp [cs:INT14Gate] ; Chain to previous handler
ENDP PF_handler64k
;----------------------------------------------------------------------------
; PF_handler4k - Page fault handler for 4k banks
;----------------------------------------------------------------------------
PROC PF_handler4k far
; TODO: Copy 64Kb bank code when this is completed
jmp [cs:INT14Gate] ; Chain to previous handler
ENDP PF_handler4k
;----------------------------------------------------------------------------
; bool VF_available(void)
;----------------------------------------------------------------------------
; Returns true if the virtual linear framebuffer code is available.
;----------------------------------------------------------------------------
procstart _VF_available
xor eax,eax ; Assume not available
mov cx,cs
cmp cx,2Bh ; If CS == 2Bh then we are under DOS+X32
jne @@1
mov eax,1 ; Yep, paging will be available
; This is not working at the moment so we fail it for X32
xor eax,eax
@@1: ret
procend _VF_available
;----------------------------------------------------------------------------
; void * VF_init(ulong baseAddr,int bankSize,int codeLen,void *bankFunc)
;----------------------------------------------------------------------------
; Parameters: baseAddr - Base address of framebuffer bank window
; bankSize - Physical size of banks in Kb (4 or 64)
; codeLen - Length of 32 bit bank switch function
; bankFunc - Pointer to protected mode bank function
; Returns: Near pointer to virtual framebuffer, or NULL on failure.
;
; Description: Installs the virtual linear framebuffer handling.
;----------------------------------------------------------------------------
procstart _VF_init
ARG baseAddr:ULONG, bankSize:UINT, codeLen:UINT, bankFunc:DPTR
enter_c 0
push es
cmp [Installed],0
jne @@Exit
cmp [codeLen],100
jg @@Fail ; Code length must be less than 100 bytes
mov ax,cs
mov [ValidCS],ax ; Save our valid CS for later
mov [LastPage],0 ; No pages have been mapped
mov es,[__x386_zero_base_selector]
; Map a 4Mb framebuffer memory region
mov edi,VFLAT_START ; This is the starting point
shr edi,10 ; Divide by 1024
add edi,400000h ; Point to page table block
mov eax,[baseAddr] ; EAX := base address of framebuffer
mov ecx,4096 ; Map a 4Mb virtual buffer
@@NextPage:
mov [es:edi],eax ; Map page in and invalidate
add edi,4
dec ecx
jnz @@NextPage
; We will now create a new data selector, and convert it into a ring 0 code
; selector with the same base address as the current CS
movzx ebx,[Ring0CS] ; Get previous ring 0 selector
test ebx,ebx ; Have we already allocated it?
jnz @@InstallInIDT
mov ax,3501h
int 21h ; Allocate a protected mode selector
jc @@Fail
mov [Ring0CS],bx ; Save ring 0 selector for next time
sub esp,6 ; Allocate space on the stack
sgdt [FWORD ss:esp] ; Get address of GDT
pop ax ; Add esp,2
pop eax ; Absolute address of GDT
add eax,ZeroBase
movzx ebx,bx ; Zero high word of ebx
and bl,0f8h ; Make index into GDT, set RPL to 0
xor ecx,ecx
mov ecx,cs
and cl,0f8h ; Make index into GDT for current CS
add ecx,eax ; Make ptr to GDT for current CS
add eax,ebx ; Make ptr to GDT entry for allocated selector
mov edx,[ecx] ; Get first 4 bytes of current cs descriptor
mov [eax],edx ; Initialize first 4 bytes of ring 0 CS
mov edx,[ecx+4] ; Get second dword of current cs descriptor
and dh,10011111b ; Set DPL bits to zero, make it a ring 0 selector
mov [eax+4],edx ; Initialize second dword of new cs descriptor
; New descriptor contained in bx now has identical characteristics to the
; original CS except it is ring 0, it has same base address, same limit and
; it is a 32 bit executable selector. We now need to place this new CS in
; the Interrupt Descriptor Table or IDT.
@@InstallInIDT:
sub esp,6 ; Allocate space on stack
sidt [FWORD ss:esp] ; Store pointer to IDT
pop ax ; add esp,2
pop eax ; Absolute address of IDT
add eax,ZeroBase ; Make near pointer to 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],bx ; Install new cs
mov edx,offset PF_handler64k
cmp [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
; Copy the bank switch function. We copy it into a buffer in our data
; segment, so that the interface of our function is identical to the
; interface required by the DVA.386 and VFLATD.386 virtual framebuffer
; devices under Windows.
mov esi,[bankFunc] ; Copy the code into buffer
mov edi,offset bankFuncBuf
mov ecx,[codeLen]
rep movsb
mov [BYTE edi],0C3h ; Terminate the function with a near ret
@@Done: mov [Installed],1 ; Our handler is now installed
mov eax,VFLAT_START ; Return the virtual buffer address
@@Exit: pop es
leave_c_nolocal
ret
@@Fail: xor eax,eax ; Install failed!
jmp @@Exit
procend _VF_init
;----------------------------------------------------------------------------
; void VF_exit(void)
;----------------------------------------------------------------------------
; Closes down the virtual framebuffer services and restores the previous
; page fault handler.
;----------------------------------------------------------------------------
procstart _VF_exit
enter_c 0
cmp [Installed],0
je @@Exit
; Remove page fault handler from IDT
sub esp,6 ; Allocate space on stack
sidt [FWORD ss:esp] ; Store pointer to IDT
pop ax ; add esp,2
pop eax ; Absolute address of IDT
add eax,ZeroBase ; Make near pointer to 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
mov [Installed],0
@@Exit: leave_c_nolocal
ret
procend _VF_exit
endcodeseg _vflat
endif
END ; End of module