aboutsummaryrefslogtreecommitdiff
path: root/board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm
diff options
context:
space:
mode:
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm')
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm652
1 files changed, 652 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm b/board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm
new file mode 100644
index 000000000..34985a9d8
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm
@@ -0,0 +1,652 @@
+;****************************************************************************
+;*
+;* 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.
+;----------------------------------------------------------------------------
+cprocstart InstallBankFunc
+
+ ARG codeLen:UINT, bankFunc:DPTR
+
+ enter_c
+
+ 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
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; 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
+;----------------------------------------------------------------------------
+cprocstart InitPaging
+
+ push ebx
+ push ecx
+ push edx
+ push esi
+ push edi
+
+; Are we running under CauseWay?
+
+ mov ax,0FFF9h
+ int 31h
+ jc @@NotCauseway
+ cmp ecx,"CAUS"
+ jnz @@NotCauseway
+ cmp edx,"EWAY"
+ jnz @@NotCauseway
+
+ mov [BOOL VF_haveCauseWay],1
+ mov [CauseWayDIRLinear],esi
+ mov [CauseWay1stLinear],edi
+
+; Check for DPMI
+
+ mov ax,0ff00h
+ push es
+ int 31h
+ pop es
+ shr edi,2
+ and edi,3
+ cmp edi,2
+ jz @@ErrExit ; Not supported under DPMI
+
+ mov eax,[CauseWayDIRLinear]
+ jmp @@CopyCR3
+
+@@NotCauseway:
+ 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
+
+@@CopyCR3:
+ 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 [DWORD 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
+ cmp [BOOL VF_haveCauseWay],0
+ jz @@NotCW0
+ mov ebx,[CauseWay1stLinear]
+ jmp @@Put1st
+
+@@NotCW0:
+ mov ebx,[PDBR]
+ mov ebx,[ebx]
+ and ebx,0FFFFF000h ; Page table for 1st megabyte
+
+@@Put1st:
+ add eax,ebx
+ mov [accessPageTable],eax
+ sub eax,eax ; No error
+ jmp @@Exit
+
+@@ErrExit:
+ mov eax,-1
+
+@@Exit: pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void ClosePaging(void)
+;----------------------------------------------------------------------------
+; Closes the paging system
+;----------------------------------------------------------------------------
+cprocstart ClosePaging
+
+ push eax
+ push ecx
+ push edx
+ push esi
+ push edi
+
+ 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
+
+@@Exit: pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop eax
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; 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
+;----------------------------------------------------------------------------
+cprocstatic 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
+
+cprocend
+
+;----------------------------------------------------------------------------
+; long GetPhysicalAddress(long linear)
+;----------------------------------------------------------------------------
+; Returns the physical address of linear address
+; Entry: EAX - Linear address to convert
+; Exit: EAX - Physical address
+;----------------------------------------------------------------------------
+cprocstatic GetPhysicalAddress
+
+ push ebx
+ push edx
+ 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 edx
+ pop ebx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void CreatePageTable(long pageDEntry)
+;----------------------------------------------------------------------------
+; Creates a page table for specific address (4MB)
+; Entry: EAX - Page directory entry (top 10-bits of address)
+;----------------------------------------------------------------------------
+cprocstatic CreatePageTable
+
+ push ebx
+ push ecx
+ push edx
+ push edi
+ 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 edi
+ pop edx
+ pop ecx
+ pop ebx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; 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)
+;----------------------------------------------------------------------------
+cprocstart MapPhysical2Linear
+
+ ARG pAddr:ULONG, lAddr:ULONG, pages:UINT, pflags:UINT
+
+ enter_c
+
+ and [ULONG pAddr],0FFFFF000h; Page boundary
+ and [ULONG 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
+
+ leave_c
+ ret
+
+cprocend
+
+endcodeseg _vflat
+
+endif
+
+ END ; End of module