summaryrefslogtreecommitdiffstats
path: root/board/MAI/bios_emulator/scitech/src/pm/common
diff options
context:
space:
mode:
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm/common')
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_cpuinfo.asm600
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_dma.asm246
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_int64.asm309
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_joy.asm230
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_mtrr.asm272
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_pcihelp.asm358
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/agp.c190
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/keyboard.c450
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/malloc.c205
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/mtrr.c867
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/pcilib.c747
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/unixio.c306
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/vgastate.c377
13 files changed, 5157 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_cpuinfo.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_cpuinfo.asm
new file mode 100644
index 0000000000..60ebed713f
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_cpuinfo.asm
@@ -0,0 +1,600 @@
+;****************************************************************************
+;*
+;* 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.
+;*
+;* ========================================================================
+;*
+;* Language: NASM or TASM Assembler
+;* Environment: Intel 32 bit Protected Mode.
+;*
+;* Description: Code to determine the Intel processor type.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac"
+
+header _cpuinfo
+
+begdataseg _cpuinfo ; Start of data segment
+
+cache_id db "01234567890123456"
+intel_id db "GenuineIntel" ; Intel vendor ID
+cyrix_id db "CyrixInstead" ; Cyrix vendor ID
+amd_id db "AuthenticAMD" ; AMD vendor ID
+idt_id db "CentaurHauls" ; IDT vendor ID
+
+CPU_IDT EQU 01000h ; Flag for IDT processors
+CPU_Cyrix EQU 02000h ; Flag for Cyrix processors
+CPU_AMD EQU 04000h ; Flag for AMD processors
+CPU_Intel EQU 08000h ; Flag for Intel processors
+
+enddataseg _cpuinfo
+
+begcodeseg _cpuinfo ; Start of code segment
+
+ifdef USE_NASM
+%macro mCPU_ID 0
+db 00Fh,0A2h
+%endmacro
+else
+MACRO mCPU_ID
+db 00Fh,0A2h
+ENDM
+endif
+
+ifdef USE_NASM
+%macro mRDTSC 0
+db 00Fh,031h
+%endmacro
+else
+MACRO mRDTSC
+db 00Fh,031h
+ENDM
+endif
+
+;----------------------------------------------------------------------------
+; bool _CPU_check80386(void)
+;----------------------------------------------------------------------------
+; Determines if we have an i386 processor.
+;----------------------------------------------------------------------------
+cprocstart _CPU_check80386
+
+ enter_c
+
+ xor edx,edx ; EDX = 0, not an 80386
+ mov bx, sp
+ifdef USE_NASM
+ and sp, ~3
+else
+ and sp, not 3
+endif
+ pushfd ; Push original EFLAGS
+ pop eax ; Get original EFLAGS
+ mov ecx, eax ; Save original EFLAGS
+ xor eax, 40000h ; Flip AC bit in EFLAGS
+ push eax ; Save new EFLAGS value on
+ ; stack
+ popfd ; Replace current EFLAGS value
+ pushfd ; Get new EFLAGS
+ pop eax ; Store new EFLAGS in EAX
+ xor eax, ecx ; Can't toggle AC bit,
+ ; processor=80386
+ jnz @@Done ; Jump if not an 80386 processor
+ inc edx ; We have an 80386
+
+@@Done: push ecx
+ popfd
+ mov sp, bx
+ mov eax, edx
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; bool _CPU_check80486(void)
+;----------------------------------------------------------------------------
+; Determines if we have an i486 processor.
+;----------------------------------------------------------------------------
+cprocstart _CPU_check80486
+
+ enter_c
+
+; Distinguish between the i486 and Pentium by the ability to set the ID flag
+; in the EFLAGS register. If the ID flag is set, then we can use the CPUID
+; instruction to determine the final version of the chip. Otherwise we
+; simply have an 80486.
+
+; Distinguish between the i486 and Pentium by the ability to set the ID flag
+; in the EFLAGS register. If the ID flag is set, then we can use the CPUID
+; instruction to determine the final version of the chip. Otherwise we
+; simply have an 80486.
+
+ pushfd ; Get original EFLAGS
+ pop eax
+ mov ecx, eax
+ xor eax, 200000h ; Flip ID bit in EFLAGS
+ push eax ; Save new EFLAGS value on stack
+ popfd ; Replace current EFLAGS value
+ pushfd ; Get new EFLAGS
+ pop eax ; Store new EFLAGS in EAX
+ xor eax, ecx ; Can not toggle ID bit,
+ jnz @@1 ; Processor=80486
+ mov eax,1 ; We dont have a Pentium
+ jmp @@Done
+@@1: mov eax,0 ; We have Pentium or later
+@@Done: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; bool _CPU_checkClone(void)
+;----------------------------------------------------------------------------
+; Checks if the i386 or i486 processor is a clone or genuine Intel.
+;----------------------------------------------------------------------------
+cprocstart _CPU_checkClone
+
+ enter_c
+
+ mov ax,5555h ; Check to make sure this is a 32-bit processor
+ xor dx,dx
+ mov cx,2h
+ div cx ; Perform Division
+ clc
+ jnz @@NoClone
+ jmp @@Clone
+@@NoClone:
+ stc
+@@Clone:
+ pushfd
+ pop eax ; Get the flags
+ and eax,1
+ xor eax,1 ; EAX=0 is probably Intel, EAX=1 is a Clone
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; bool _CPU_haveCPUID(void)
+;----------------------------------------------------------------------------
+; Determines if we have support for the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_haveCPUID
+
+ enter_c
+
+ifdef flatmodel
+ pushfd ; Get original EFLAGS
+ pop eax
+ mov ecx, eax
+ xor eax, 200000h ; Flip ID bit in EFLAGS
+ push eax ; Save new EFLAGS value on stack
+ popfd ; Replace current EFLAGS value
+ pushfd ; Get new EFLAGS
+ pop eax ; Store new EFLAGS in EAX
+ xor eax, ecx ; Can not toggle ID bit,
+ jnz @@1 ; Processor=80486
+ mov eax,0 ; We dont have CPUID support
+ jmp @@Done
+@@1: mov eax,1 ; We have CPUID support
+else
+ mov eax,0 ; CPUID requires 32-bit pmode
+endif
+@@Done: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_checkCPUID(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_checkCPUID
+
+ enter_c
+
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax, 1 ; Make sure 1 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ xor eax,eax ; Assume vendor is unknown
+
+; Check for GenuineIntel processors
+
+ LEA_L esi,intel_id
+ cmp [DWORD esi], ebx
+ jne @@NotIntel
+ cmp [DWORD esi+4], edx
+ jne @@NotIntel
+ cmp [DWORD esi+8], ecx
+ jne @@NotIntel
+ mov eax,CPU_Intel ; Flag that we have GenuineIntel
+ jmp @@FoundVendor
+
+; Check for CyrixInstead processors
+
+@@NotIntel:
+ LEA_L esi,cyrix_id
+ cmp [DWORD esi], ebx
+ jne @@NotCyrix
+ cmp [DWORD esi+4], edx
+ jne @@NotCyrix
+ cmp [DWORD esi+8], ecx
+ jne @@NotCyrix
+ mov eax,CPU_Cyrix ; Flag that we have CyrixInstead
+ jmp @@FoundVendor
+
+; Check for AuthenticAMD processors
+
+@@NotCyrix:
+ LEA_L esi,amd_id
+ cmp [DWORD esi], ebx
+ jne @@NotAMD
+ cmp [DWORD esi+4], edx
+ jne @@NotAMD
+ cmp [DWORD esi+8], ecx
+ jne @@NotAMD
+ mov eax,CPU_AMD ; Flag that we have AuthenticAMD
+ jmp @@FoundVendor
+
+; Check for CentaurHauls processors
+
+@@NotAMD:
+ LEA_L esi,idt_id
+ cmp [DWORD esi], ebx
+ jne @@NotIDT
+ cmp [DWORD esi+4], edx
+ jne @@NotIDT
+ cmp [DWORD esi+8], ecx
+ jne @@NotIDT
+ mov eax,CPU_IDT ; Flag that we have AuthenticIDT
+ jmp @@FoundVendor
+
+@@NotIDT:
+
+@@FoundVendor:
+ push eax
+ xor eax, eax
+ inc eax
+ mCPU_ID ; Get family/model/stepping/features
+ and eax, 0F00h
+ shr eax, 8 ; Isolate family
+ and eax, 0Fh
+ pop ecx
+ or eax,ecx ; Combine in the clone flag
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_getCPUIDModel(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_getCPUIDModel
+
+ enter_c
+
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax, 1 ; Make sure 1 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ xor eax, eax
+ inc eax
+ mCPU_ID ; Get family/model/stepping/features
+ and eax, 0F0h
+ shr eax, 4 ; Isolate model
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_getCPUIDStepping(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_getCPUIDStepping
+
+ enter_c
+
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax, 1 ; Make sure 1 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ xor eax, eax
+ inc eax
+ mCPU_ID ; Get family/model/stepping/features
+ and eax, 00Fh ; Isolate stepping
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_getCPUIDFeatures(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_getCPUIDFeatures
+
+ enter_c
+
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax, 1 ; Make sure 1 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ xor eax, eax
+ inc eax
+ mCPU_ID ; Get family/model/stepping/features
+ mov eax, edx
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_getCacheSize(void)
+;----------------------------------------------------------------------------
+; Determines the CPU cache size for Intel processors
+;----------------------------------------------------------------------------
+cprocstart _CPU_getCacheSize
+
+ enter_c
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax,2 ; Make sure 2 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ mov eax,2
+ mCPU_ID ; Get cache descriptors
+ LEA_L esi,cache_id ; Get address of cache ID (-fPIC aware)
+ shr eax,8
+ mov [esi+0],eax
+ mov [esi+3],ebx
+ mov [esi+7],ecx
+ mov [esi+11],edx
+ xor eax,eax
+ LEA_L esi,cache_id ; Get address of cache ID (-fPIC aware)
+ mov edi,15
+@@ScanLoop:
+ cmp [BYTE esi],41h
+ mov eax,128
+ je @@Done
+ cmp [BYTE esi],42h
+ mov eax,256
+ je @@Done
+ cmp [BYTE esi],43h
+ mov eax,512
+ je @@Done
+ cmp [BYTE esi],44h
+ mov eax,1024
+ je @@Done
+ cmp [BYTE esi],45h
+ mov eax,2048
+ je @@Done
+ inc esi
+ dec edi
+ jnz @@ScanLoop
+
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_have3DNow(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_have3DNow
+
+ enter_c
+
+ mov eax,80000000h ; Query for extended functions
+ mCPU_ID ; Get extended function limit
+ cmp eax,80000001h
+ jbe @@Fail ; Nope, we dont have function 800000001h
+ mov eax,80000001h ; Setup extended function 800000001h
+ mCPU_ID ; and get the information
+ test edx,80000000h ; Bit 31 is set if 3DNow! present
+ jz @@Fail ; Nope, we dont have 3DNow support
+ mov eax,1 ; Yep, we have 3DNow! support!
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _CPU_quickRDTSC(void)
+;----------------------------------------------------------------------------
+; Reads the time stamp counter and returns the low order 32-bits
+;----------------------------------------------------------------------------
+cprocstart _CPU_quickRDTSC
+
+ mRDTSC
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _CPU_runBSFLoop(ulong interations)
+;----------------------------------------------------------------------------
+; Runs a loop of BSF instructions for the specified number of iterations
+;----------------------------------------------------------------------------
+cprocstart _CPU_runBSFLoop
+
+ ARG iterations:ULONG
+
+ push _bp
+ mov _bp,_sp
+ push _bx
+
+ mov edx,[iterations]
+ mov eax,80000000h
+ mov ebx,edx
+
+ ALIGN 4
+
+@@loop: bsf ecx,eax
+ dec ebx
+ jnz @@loop
+
+ pop _bx
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _CPU_readTimeStamp(CPU_largeInteger *time);
+;----------------------------------------------------------------------------
+; Reads the time stamp counter and returns the 64-bit result.
+;----------------------------------------------------------------------------
+cprocstart _CPU_readTimeStamp
+
+ mRDTSC
+ mov ecx,[esp+4] ; Access directly without stack frame
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _CPU_diffTime64(CPU_largeInteger *t1,CPU_largeInteger *t2,CPU_largeInteger *t)
+;----------------------------------------------------------------------------
+; Computes the difference between two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _CPU_diffTime64
+
+ ARG t1:DPTR, t2:DPTR, t:DPTR
+
+ enter_c
+
+ mov ecx,[t2]
+ mov eax,[ecx] ; EAX := t2.low
+ mov ecx,[t1]
+ sub eax,[ecx]
+ mov edx,eax ; EDX := low difference
+ mov ecx,[t2]
+ mov eax,[ecx+4] ; ECX := t2.high
+ mov ecx,[t1]
+ sbb eax,[ecx+4] ; EAX := high difference
+
+ mov ebx,[t] ; Store the result
+ mov [ebx],edx ; Store low part
+ mov [ebx+4],eax ; Store high part
+ mov eax,edx ; Return low part
+ifndef flatmodel
+ shld edx,eax,16 ; Return in DX:AX
+endif
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _CPU_calcMicroSec(CPU_largeInteger *count,ulong freq);
+;----------------------------------------------------------------------------
+; Computes the value in microseconds for the elapsed time with maximum
+; precision. The formula we use is:
+;
+; us = (((diff * 0x100000) / freq) * 1000000) / 0x100000)
+;
+; The power of two multiple before the first divide allows us to scale the
+; 64-bit difference using simple shifts, and then the divide brings the
+; final result into the range to fit into a 32-bit integer.
+;----------------------------------------------------------------------------
+cprocstart _CPU_calcMicroSec
+
+ ARG count:DPTR, freq:ULONG
+
+ enter_c
+
+ mov ecx,[count]
+ mov eax,[ecx] ; EAX := low part
+ mov edx,[ecx+4] ; EDX := high part
+ shld edx,eax,20
+ shl eax,20 ; diff * 0x100000
+ div [DWORD freq] ; (diff * 0x100000) / freq
+ mov ecx,1000000
+ xor edx,edx
+ mul ecx ; ((diff * 0x100000) / freq) * 1000000)
+ shrd eax,edx,20 ; ((diff * 0x100000) / freq) * 1000000) / 0x100000
+ifndef flatmodel
+ shld edx,eax,16 ; Return in DX:AX
+endif
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _CPU_mulDiv(ulong a,ulong b,ulong c);
+;----------------------------------------------------------------------------
+; Computes the following with 64-bit integer precision:
+;
+; result = (a * b) / c
+;
+;----------------------------------------------------------------------------
+cprocstart _CPU_mulDiv
+
+ ARG a:ULONG, b:ULONG, c:ULONG
+
+ enter_c
+ mov eax,[a]
+ imul [ULONG b]
+ idiv [ULONG c]
+ifndef flatmodel
+ shld edx,eax,16 ; Return in DX:AX
+endif
+ leave_c
+ ret
+
+cprocend
+
+endcodeseg _cpuinfo
+
+ END
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_dma.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_dma.asm
new file mode 100644
index 0000000000..2b6e1e8b56
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_dma.asm
@@ -0,0 +1,246 @@
+;****************************************************************************
+;*
+;* 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.
+;*
+;* ========================================================================
+;*
+;* Language: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: 16/32 bit Ring 0 device driver
+;*
+;* Description: Assembler support routines for ISA DMA controller.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _dma ; Set up memory model
+
+begdataseg _dma ; Start of data segment
+
+cpublic _PM_DMADataStart
+
+; DMA register I/O addresses for channels 0-7 (except 4)
+
+DMAC_page db 087h,083h,081h,082h, -1,08Bh,089h,08Ah
+DMAC_addr db 000h,002h,004h,006h, -1,0C4h,0C8h,0CCh
+DMAC_cnt db 001h,003h,005h,007h, -1,0C6h,0CAh,0CEh
+DMAC_mask db 00Ah,00Ah,00Ah,00Ah, -1,0D4h,0D4h,0D4h
+DMAC_mode db 00Bh,00Bh,00Bh,00Bh, -1,0D6h,0D6h,0D6h
+DMAC_FF db 00Ch,00Ch,00Ch,00Ch, -1,0D8h,0D8h,0D8h
+
+cpublic _PM_DMADataEnd
+
+enddataseg _dma
+
+begcodeseg _dma ; Start of code segment
+
+ifdef flatmodel
+
+cpublic _PM_DMACodeStart
+
+;----------------------------------------------------------------------------
+; void PM_DMACDisable(int channel);
+;----------------------------------------------------------------------------
+; Masks DMA channel, inhibiting DMA transfers
+;----------------------------------------------------------------------------
+cprocstart PM_DMACDisable
+
+ ARG channel:UINT
+
+ push ebp
+ mov ebp,esp
+ mov ecx,[channel] ; ECX indexes DMAC register tables
+ mov dh,0 ; DH = 0 for DMAC register port access
+ mov al,cl
+ and al,11b
+ or al,100b ; AL = (channel & 3) | "set mask bit"
+ mov dl,[DMAC_mask+ecx]
+ out dx,al
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_DMACEnable(int channel);
+;----------------------------------------------------------------------------
+; Unmasks DMA channel, enabling DMA transfers
+;----------------------------------------------------------------------------
+cprocstart PM_DMACEnable
+
+ ARG channel:UINT
+
+ push ebp
+ mov ebp,esp
+ mov ecx,[channel] ; ECX indexes DMAC register tables
+ mov dh,0 ; DH = 0 for DMAC register port access
+ mov al,cl
+ and al,11b ; AL = (channel & 3), "set mask bit"=0
+ mov dl,[DMAC_mask+ecx]
+ out dx,al
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_DMACProgram(int channel,int mode,ulong bufferPhys,int count);
+;----------------------------------------------------------------------------
+; Purpose: Program DMA controller to perform transfer from first 16MB
+; based on previously selected mode and channel. DMA transfer may be enabled
+; by subsequent call to PM_DMACEnable.
+;
+; Entry: channel - DMA channel in use (0-7)
+; mode - Selected DMAMODE type for transfer
+; buffer - 32-bit physical address of DMA buffer
+; count - DMA byte count (1-65536 bytes)
+;----------------------------------------------------------------------------
+cprocstart PM_DMACProgram
+
+ ARG channel:UINT, mode:UINT, bufferPhys:ULONG, count:UINT
+
+ enter_c
+ pushfd
+ cli ; Disable interrupts
+
+; Mask DMA channel to disable it
+
+ mov ebx,[channel] ; EBX indexes DMAC register tables
+ mov dh,0 ; DH = 0 for DMAC register port access
+ mov al,bl
+ and al,11b
+ or al,100b ; AL = (channel & 3) | "set mask bit"
+ mov dl,[DMAC_mask+ebx]
+ out dx,al
+
+; Generate IOW to clear FF toggle state
+
+ mov al,0
+ mov dl,[DMAC_FF+ebx]
+ out dx,al
+
+; Compute buffer address to program
+
+ mov eax,[bufferPhys] ; AX := DMA address offset
+ mov ecx,eax
+ shr ecx,16 ; CL := bufferPhys >> 16 (DMA page)
+ mov esi,[count] ; ESI = # of bytes to transfer
+ cmp ebx,4 ; 16-bit channel?
+ jb @@WriteDMAC ; No, program DMAC
+ shr eax,1 ; Yes, convert address and count
+ shr esi,1 ; to 16-bit, 128K/page format
+
+; Set the DMA address word (bits 0-15)
+
+@@WriteDMAC:
+ mov dl,[DMAC_addr+ebx]
+ out dx,al
+ mov al,ah
+ out dx,al
+
+; Set DMA transfer count
+
+ mov eax,esi
+ dec eax ; ESI = # of bytes to transfer - 1
+ mov dl,[DMAC_cnt+ebx]
+ out dx,al
+ mov al,ah
+ out dx,al
+
+; Set DMA page byte (bits 16-23)
+
+ mov al,cl
+ mov dl,[DMAC_page+ebx]
+ out dx,al
+
+; Set the DMA channel mode
+
+ mov al,bl
+ and al,11b
+ or al,[BYTE mode] ; EAX = (channel & 3) | mode
+ mov dl,[DMAC_mode+ebx]
+ out dx,al
+
+ pop eax ; SMP safe interrupt state restore!
+ test eax,200h
+ jz @@1
+ sti
+@@1: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong PMAPI PM_DMACPosition(int channel);
+;----------------------------------------------------------------------------
+; Returns the current position in a dma transfer. Interrupts should be
+; disabled before calling this function.
+;----------------------------------------------------------------------------
+cprocstart PM_DMACPosition
+
+ ARG channel:UINT
+
+ enter_c
+ mov ecx,[channel] ; ECX indexes DMAC register tables
+ mov dh,0 ; DH = 0 for DMAC register port access
+
+; Generate IOW to clear FF toggle state
+
+ mov al,0
+ mov dl,[DMAC_FF+ebx]
+ out dx,al
+ xor eax,eax
+ xor ecx,ecx
+
+; Now read the current position for the channel
+
+@@ReadLoop:
+ mov dl,[DMAC_cnt+ebx]
+ out dx,al
+ in al,dx
+ mov cl,al
+ in al,dx
+ mov ch,al ; ECX := first count read
+ in al,dx
+ mov ah,al
+ in al,dx
+ xchg al,ah ; EAX := second count read
+ sub ecx,eax
+ cmp ecx,40h
+ jg @@ReadLoop
+ cmp ebx,4 ; 16-bit channel?
+ jb @@Exit ; No, we are done
+ shl eax,1 ; Yes, adjust to byte address
+
+@@Exit: leave_c
+ ret
+
+cprocend
+
+
+cpublic _PM_DMACodeEnd
+
+endif
+
+endcodeseg _dma
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_int64.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_int64.asm
new file mode 100644
index 0000000000..fdec1b58d8
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_int64.asm
@@ -0,0 +1,309 @@
+;****************************************************************************
+;*
+;* 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.
+;*
+;* ========================================================================
+;*
+;* Language: NASM or TASM Assembler
+;* Environment: Intel 32 bit Protected Mode.
+;*
+;* Description: Code for 64-bit arhithmetic
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac"
+
+header _int64
+
+begcodeseg _int64 ; Start of code segment
+
+a_low EQU 04h ; Access a_low directly on stack
+a_high EQU 08h ; Access a_high directly on stack
+b_low EQU 0Ch ; Access b_low directly on stack
+shift EQU 0Ch ; Access shift directly on stack
+result_2 EQU 0Ch ; Access result directly on stack
+b_high EQU 10h ; Access b_high directly on stack
+result_3 EQU 10h ; Access result directly on stack
+result_4 EQU 14h ; Access result directly on stack
+
+;----------------------------------------------------------------------------
+; void _PM_add64(u32 a_low,u32 a_high,u32 b_low,u32 b_high,__u64 *result);
+;----------------------------------------------------------------------------
+; Adds two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _PM_add64
+
+ mov eax,[esp+a_low]
+ add eax,[esp+b_low]
+ mov edx,[esp+a_high]
+ adc edx,[esp+b_high]
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_sub64(u32 a_low,u32 a_high,u32 b_low,u32 b_high,__u64 *result);
+;----------------------------------------------------------------------------
+; Subtracts two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _PM_sub64
+
+ mov eax,[esp+a_low]
+ sub eax,[esp+b_low]
+ mov edx,[esp+a_high]
+ sbb edx,[esp+b_high]
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_mul64(u32 a_high,u32 a_low,u32 b_high,u32 b_low,__u64 *result);
+;----------------------------------------------------------------------------
+; Multiples two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _PM_mul64
+
+ mov eax,[esp+a_high]
+ mov ecx,[esp+b_high]
+ or ecx,eax
+ mov ecx,[esp+b_low]
+ jnz @@FullMultiply
+ mov eax,[esp+a_low] ; EDX:EAX = b.low * a.low
+ mul ecx
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+@@FullMultiply:
+ push ebx
+ mul ecx ; EDX:EAX = a.high * b.low
+ mov ebx,eax
+ mov eax,[esp+a_low+4]
+ mul [DWORD esp+b_high+4] ; EDX:EAX = b.high * a.low
+ add ebx,eax
+ mov eax,[esp+a_low+4]
+ mul ecx ; EDX:EAX = a.low * b.low
+ add edx,ebx
+ pop ebx
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_div64(u32 a_low,u32 a_high,u32 b_low,u32 b_high,__u64 *result);
+;----------------------------------------------------------------------------
+; Divides two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _PM_div64
+
+ push edi
+ push esi
+ push ebx
+ xor edi,edi
+ mov eax,[esp+a_high+0Ch]
+ or eax,eax
+ jns @@ANotNeg
+
+; Dividend is negative, so negate it and save result for later
+
+ inc edi
+ mov edx,[esp+a_low+0Ch]
+ neg eax
+ neg edx
+ sbb eax,0
+ mov [esp+a_high+0Ch],eax
+ mov [esp+a_low+0Ch],edx
+
+@@ANotNeg:
+ mov eax,[esp+b_high+0Ch]
+ or eax,eax
+ jns @@BNotNeg
+
+; Divisor is negative, so negate it and save result for later
+
+ inc edi
+ mov edx,[esp+b_low+0Ch]
+ neg eax
+ neg edx
+ sbb eax,0
+ mov [esp+b_high+0Ch],eax
+ mov [esp+b_low+0Ch],edx
+
+@@BNotNeg:
+ or eax,eax
+ jnz @@BHighNotZero
+
+; b.high is zero, so handle this faster
+
+ mov ecx,[esp+b_low+0Ch]
+ mov eax,[esp+a_high+0Ch]
+ xor edx,edx
+ div ecx
+ mov ebx,eax
+ mov eax,[esp+a_low+0Ch]
+ div ecx
+ mov edx,ebx
+ jmp @@BHighZero
+
+@@BHighNotZero:
+ mov ebx,eax
+ mov ecx,[esp+b_low+0Ch]
+ mov edx,[esp+a_high+0Ch]
+ mov eax,[esp+a_low+0Ch]
+
+; Shift values right until b.high becomes zero
+
+@@ShiftLoop:
+ shr ebx,1
+ rcr ecx,1
+ shr edx,1
+ rcr eax,1
+ or ebx,ebx
+ jnz @@ShiftLoop
+
+; Now complete the divide process
+
+ div ecx
+ mov esi,eax
+ mul [DWORD esp+b_high+0Ch]
+ mov ecx,eax
+ mov eax,[esp+b_low+0Ch]
+ mul esi
+ add edx,ecx
+ jb @@8
+ cmp edx,[esp+a_high+0Ch]
+ ja @@8
+ jb @@9
+ cmp eax,[esp+a_low+0Ch]
+ jbe @@9
+@@8: dec esi
+@@9: xor edx,edx
+ mov eax,esi
+
+@@BHighZero:
+ dec edi
+ jnz @@Done
+
+; The result needs to be negated as either a or b was negative
+
+ neg edx
+ neg eax
+ sbb edx,0
+
+@@Done: pop ebx
+ pop esi
+ pop edi
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; __i64 _PM_shr64(u32 a_low,s32 a_high,s32 shift,__u64 *result);
+;----------------------------------------------------------------------------
+; Shift a 64-bit number right
+;----------------------------------------------------------------------------
+cprocstart _PM_shr64
+
+ mov eax,[esp+a_low]
+ mov edx,[esp+a_high]
+ mov cl,[esp+shift]
+ shrd edx,eax,cl
+ mov ecx,[esp+result_3]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; __i64 _PM_sar64(u32 a_low,s32 a_high,s32 shift,__u64 *result);
+;----------------------------------------------------------------------------
+; Shift a 64-bit number right (signed)
+;----------------------------------------------------------------------------
+cprocstart _PM_sar64
+
+ mov eax,[esp+a_low]
+ mov edx,[esp+a_high]
+ mov cl,[esp+shift]
+ sar edx,cl
+ rcr eax,cl
+ mov ecx,[esp+result_3]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; __i64 _PM_shl64(u32 a_low,s32 a_high,s32 shift,__u64 *result);
+;----------------------------------------------------------------------------
+; Shift a 64-bit number left
+;----------------------------------------------------------------------------
+cprocstart _PM_shl64
+
+ mov eax,[esp+a_low]
+ mov edx,[esp+a_high]
+ mov cl,[esp+shift]
+ shld edx,eax,cl
+ mov ecx,[esp+result_3]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; __i64 _PM_neg64(u32 a_low,s32 a_high,__u64 *result);
+;----------------------------------------------------------------------------
+; Shift a 64-bit number left
+;----------------------------------------------------------------------------
+cprocstart _PM_neg64
+
+ mov eax,[esp+a_low]
+ mov edx,[esp+a_high]
+ neg eax
+ neg edx
+ sbb eax,0
+ mov ecx,[esp+result_2]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+
+endcodeseg _int64
+
+ END
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_joy.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_joy.asm
new file mode 100644
index 0000000000..0ff1ecf55d
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_joy.asm
@@ -0,0 +1,230 @@
+;****************************************************************************
+;*
+;* 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.
+;*
+;* ========================================================================
+;*
+;* Language: 80386 Assembler
+;* Environment: Intel x86, any OS
+;*
+;* Description: Assembly language support routines for reading analogue
+;* joysticks.
+;*
+;****************************************************************************
+
+ ideal
+
+include "scitech.mac" ; Memory model macros
+
+ifdef flatmodel
+
+header _joy ; Set up memory model
+
+begcodeseg _joy ; Start of code segment
+
+;----------------------------------------------------------------------------
+; initTimer
+;----------------------------------------------------------------------------
+; Sets up 8253 timer 2 (PC speaker) to start timing, but not produce output.
+;----------------------------------------------------------------------------
+cprocstatic initTimer
+
+; Start timer 2 counting
+
+ in al,61h
+ and al,0FDh ; Disable speaker output (just in case)
+ or al,1
+ out 61h,al
+
+; Set the timer 2 count to 0 again to start the timing interval.
+
+ mov al,10110100b ; set up to load initial (timer 2)
+ out 43h,al ; timer count
+ sub al,al
+ out 42h,al ; load count lsb
+ out 42h,al ; load count msb
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; readTimer2
+;----------------------------------------------------------------------------
+; Reads the number of ticks from the 8253 timer chip using channel 2 (PC
+; speaker). This is non-destructive and does not screw up other libraries.
+;----------------------------------------------------------------------------
+cprocstatic readTimer
+
+ xor al,al ; Latch timer 0 command
+ out 43h,al ; Latch timer
+ in al,42h ; least significant byte
+ mov ah,al
+ in al,42h ; most significant byte
+ xchg ah,al
+ and eax,0FFFFh
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; exitTimer
+;----------------------------------------------------------------------------
+; Stops the 8253 timer 2 (PC speaker) counting
+;----------------------------------------------------------------------------
+cprocstatic exitTimer
+
+; Stop timer 2 from counting
+
+ push eax
+ in al,61h
+ and al,0FEh
+ out 61h,al
+
+; Some programs have a problem if we change the control port; better change it
+; to something they expect (mode 3 - square wave generator)...
+ mov al,0B6h
+ out 43h,al
+
+ pop eax
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int _EVT_readJoyAxis(int jmask,int *axis);
+;----------------------------------------------------------------------------
+; Function to poll the joystick to read the current axis positions.
+;----------------------------------------------------------------------------
+cprocstart _EVT_readJoyAxis
+
+ ARG jmask:UINT, axis:DPTR
+
+ LOCAL firstTick:UINT, lastTick:UINT, totalTicks:UINT = LocalSize
+
+ enter_c
+
+ mov ebx,[jmask]
+ mov edi,[axis]
+ mov ecx,(1193180/100)
+ and ebx,01111b ; Mask out supported axes
+ mov dx,201h ; DX := joystick I/O port
+ call initTimer ; Start timer 2 counting
+ call readTimer ; Returns counter in EAX
+ mov [lastTick],eax
+
+@@WaitStable:
+ in al,dx
+ and al,bl ; Wait for the axes in question to be
+ jz @@Stable ; done reading...
+ call readTimer ; Returns counter in EAX
+ xchg eax,[lastTick]
+ cmp eax,[lastTick]
+ jb @@1
+ sub eax,[lastTick]
+@@1: add [totalTicks],eax
+ cmp [totalTicks],ecx ; Check for timeout
+ jae @@Stable
+ jmp @@WaitStable
+
+@@Stable:
+ mov al,0FFh
+ out dx,al ; Start joystick reading
+ call initTimer ; Start timer 2 counting
+ call readTimer ; Returns counter in EAX
+ mov [firstTick],eax ; Store initial count
+ mov [lastTick],eax
+ mov [DWORD totalTicks],0
+ cli
+
+@@PollLoop:
+ in al,dx ; Read Joystick port
+ not al
+ and al,bl ; Mask off channels we don't want to read
+ jnz @@AxisFlipped ; See if any of the channels flipped
+ call readTimer ; Returns counter in EAX
+ xchg eax,[lastTick]
+ cmp eax,[lastTick]
+ jb @@2
+ sub eax,[lastTick]
+@@2: add [totalTicks],eax
+ cmp [totalTicks],ecx ; Check for timeout
+ jae @@TimedOut
+ jmp @@PollLoop
+
+@@AxisFlipped:
+ xor esi,esi
+ mov ah,1
+ test al,ah
+ jnz @@StoreCount ; Joystick 1, X axis flipped
+ add esi,4
+ mov ah,2
+ test al,ah
+ jnz @@StoreCount ; Joystick 1, Y axis flipped
+ add esi,4
+ mov ah,4
+ test al,ah
+ jnz @@StoreCount ; Joystick 2, X axis flipped
+ add esi,4 ; Joystick 2, Y axis flipped
+ mov ah,8
+
+@@StoreCount:
+ or bh,ah ; Indicate this axis is active
+ xor bl,ah ; Unmark the channels that just tripped
+ call readTimer ; Returns counter in EAX
+ xchg eax,[lastTick]
+ cmp eax,[lastTick]
+ jb @@3
+ sub eax,[lastTick]
+@@3: add [totalTicks],eax
+ mov eax,[totalTicks]
+ mov [edi+esi],eax ; Record the time this channel flipped
+ cmp bl,0 ; If there are more channels to read,
+ jne @@PollLoop ; keep looping
+
+@@TimedOut:
+ sti
+ call exitTimer ; Stop timer 2 counting
+ movzx eax,bh ; Return the mask of working axes
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int _EVT_readJoyButtons(void);
+;----------------------------------------------------------------------------
+; Function to poll the current joystick buttons
+;----------------------------------------------------------------------------
+cprocstart _EVT_readJoyButtons
+
+ mov dx,0201h
+ in al,dx
+ shr al,4
+ not al
+ and eax,0Fh
+ ret
+
+cprocend
+
+endcodeseg _joy
+
+endif
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_mtrr.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_mtrr.asm
new file mode 100644
index 0000000000..1e0a6966ce
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_mtrr.asm
@@ -0,0 +1,272 @@
+;****************************************************************************
+;*
+;* 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.
+;*
+;* ========================================================================
+;*
+;* Language: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: 16/32 bit Ring 0 device driver
+;*
+;* Description: Assembler support routines for the Memory Type Range Register
+;* (MTRR) module.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _mtrr ; Set up memory model
+
+begdataseg _mtrr
+
+ifdef DOS4GW
+ cextern _PM_haveCauseWay,UINT
+endif
+
+enddataseg _mtrr
+
+begcodeseg _mtrr ; Start of code segment
+
+P586
+
+;----------------------------------------------------------------------------
+; ibool _MTRR_isRing0(void);
+;----------------------------------------------------------------------------
+; Checks to see if we are running at ring 0. This check is only relevant
+; for 32-bit DOS4GW and compatible programs. If we are not running under
+; DOS4GW, then we simply assume we are a ring 0 device driver.
+;----------------------------------------------------------------------------
+cprocnear _MTRR_isRing0
+
+; Are we running under CauseWay?
+
+ifdef DOS4GW
+ enter_c
+ mov ax,cs
+ and eax,3
+ xor eax,3
+ jnz @@Exit
+
+; CauseWay runs the apps at ring 3, but implements support for specific
+; ring 0 instructions that we need to get stuff done under real DOS.
+
+ mov eax,1
+ cmp [UINT _PM_haveCauseWay],0
+ jnz @@Exit
+@@Fail: xor eax,eax
+@@Exit: leave_c
+ ret
+else
+ifdef __SMX32__
+ mov eax,1 ; SMX is ring 0!
+ ret
+else
+ifdef __VXD__
+ mov eax,1 ; VxD is ring 0!
+ ret
+else
+ifdef __NT_DRIVER__
+ mov eax,1 ; NT/W2K is ring 0!
+ ret
+else
+else
+ xor eax,eax ; Assume ring 3 for 32-bit DOS
+ ret
+endif
+endif
+endif
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _MTRR_disableInt(void);
+;----------------------------------------------------------------------------
+; Return processor interrupt status and disable interrupts.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_disableInt
+
+ pushfd ; Put flag word on stack
+ cli ; Disable interrupts!
+ pop eax ; deposit flag word in return register
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_restoreInt(ulong ps);
+;----------------------------------------------------------------------------
+; Restore processor interrupt status.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_restoreInt
+
+ ARG ps:ULONG
+
+ push ebp
+ mov ebp,esp ; Set up stack frame
+ mov ecx,[ps]
+ test ecx,200h ; SMP safe interrupt flag restore!
+ jz @@1
+ sti
+@@1: pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _MTRR_saveCR4(void);
+;----------------------------------------------------------------------------
+; Save the value of CR4 and clear the Page Global Enable (bit 7). We also
+; disable and flush the caches.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_saveCR4
+
+ enter_c
+
+; Save value of CR4 and clear Page Global Enable (bit 7)
+
+ mov ebx,cr4
+ mov eax,ebx
+ and al,7Fh
+ mov cr4,eax
+
+; Disable and flush caches
+
+ mov eax,cr0
+ or eax,40000000h
+ wbinvd
+ mov cr0,eax
+ wbinvd
+
+; Return value from CR4
+
+ mov eax,ebx
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_restoreCR4(ulong cr4Val)
+;----------------------------------------------------------------------------
+; Save the value of CR4 and clear the Page Global Enable (bit 7). We also
+; disable and flush the caches.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_restoreCR4
+
+ ARG cr4Val:ULONG
+
+ enter_c
+
+; Enable caches
+
+ mov eax,cr0
+ and eax,0BFFFFFFFh
+ mov cr0,eax
+ mov eax,[cr4Val]
+ mov cr4,eax
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uchar _MTRR_getCx86(uchar reg);
+;----------------------------------------------------------------------------
+; Read a Cyrix CPU indexed register
+;----------------------------------------------------------------------------
+cprocstart _MTRR_getCx86
+
+ ARG reg:UCHAR
+
+ enter_c
+ mov al,[reg]
+ out 22h,al
+ in al,23h
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uchar _MTRR_setCx86(uchar reg,uchar val);
+;----------------------------------------------------------------------------
+; Write a Cyrix CPU indexed register
+;----------------------------------------------------------------------------
+cprocstart _MTRR_setCx86
+
+ ARG reg:UCHAR, val:UCHAR
+
+ enter_c
+ mov al,[reg]
+ out 22h,al
+ mov al,[val]
+ out 23h,al
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_readMSR(uong reg, ulong FAR *eax, ulong FAR *edx);
+;----------------------------------------------------------------------------
+; Writes the specific Machine Status Register used on the newer Intel
+; Pentium Pro and Pentium II motherboards.
+;----------------------------------------------------------------------------
+cprocnear _MTRR_readMSR
+
+ ARG reg:ULONG, v_eax:DPTR, v_edx:DPTR
+
+ enter_c
+ mov ecx,[reg]
+ rdmsr
+ mov ebx,[v_eax]
+ mov [ebx],eax
+ mov ebx,[v_edx]
+ mov [ebx],edx
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_writeMSR(uong reg, ulong eax, ulong edx);
+;----------------------------------------------------------------------------
+; Writes the specific Machine Status Register used on the newer Intel
+; Pentium Pro and Pentium II motherboards.
+;----------------------------------------------------------------------------
+cprocnear _MTRR_writeMSR
+
+ ARG reg:ULONG, v_eax:ULONG, v_edx:ULONG
+
+ enter_c
+ mov ecx,[reg]
+ mov eax,[v_eax]
+ mov edx,[v_edx]
+ wrmsr
+ leave_c
+ ret
+
+cprocend
+
+endcodeseg _mtrr
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_pcihelp.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_pcihelp.asm
new file mode 100644
index 0000000000..5b8dbcc73a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_pcihelp.asm
@@ -0,0 +1,358 @@
+;****************************************************************************
+;*
+;* 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.
+;*
+;* ========================================================================
+;*
+;* Language: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: Any
+;*
+;* Description: Helper assembler functions for PCI access module.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pcilib
+
+begcodeseg _pcilib
+
+ifdef flatmodel
+
+;----------------------------------------------------------------------------
+; uchar _ASMAPI _BIOS32_service(
+; ulong service,
+; ulong func,
+; ulong *physBase,
+; ulong *length,
+; ulong *serviceOffset,
+; PCIBIOS_entry entry);
+;----------------------------------------------------------------------------
+; Call the BIOS32 services directory
+;----------------------------------------------------------------------------
+cprocstart _BIOS32_service
+
+ ARG service:ULONG, func:ULONG, physBase:DPTR, len:DPTR, off:DPTR, entry:QWORD
+
+ enter_c
+ mov eax,[service]
+ mov ebx,[func]
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+ mov esi,[physBase]
+ mov [esi],ebx
+ mov esi,[len]
+ mov [esi],ecx
+ mov esi,[off]
+ mov [esi],edx
+ leave_c
+ ret
+
+cprocend
+
+endif
+
+;----------------------------------------------------------------------------
+; ushort _ASMAPI _PCIBIOS_isPresent(ulong i_eax,ulong *o_edx,ushort *oeax,
+; uchar *o_cl,PCIBIOS_entry entry)
+;----------------------------------------------------------------------------
+; Call the PCI BIOS to determine if it is present.
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_isPresent
+
+ ARG i_eax:ULONG, o_edx:DPTR, oeax:DPTR, o_cl:DPTR, entry:QWORD
+
+ enter_c
+ mov eax,[i_eax]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ _les _si,[o_edx]
+ mov [_ES _si],edx
+ _les _si,[oeax]
+ mov [_ES _si],ax
+ _les _si,[o_cl]
+ mov [_ES _si],cl
+ mov ax,bx
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _PCIBIOS_service(ulong r_eax,ulong r_ebx,ulong r_edi,ulong r_ecx,
+; PCIBIOS_entry entry)
+;----------------------------------------------------------------------------
+; Call the PCI BIOS services, either via the 32-bit protected mode entry
+; point or via the Int 1Ah 16-bit interrupt.
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_service
+
+ ARG r_eax:ULONG, r_ebx:ULONG, r_edi:ULONG, r_ecx:ULONG, entry:QWORD
+
+ enter_c
+ mov eax,[r_eax]
+ mov ebx,[r_ebx]
+ mov edi,[r_edi]
+ mov ecx,[r_ecx]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ mov eax,ecx
+ifndef flatmodel
+ shld edx,eax,16 ; Return result in DX:AX
+endif
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int _PCIBIOS_getRouting(PCIRoutingOptionsBuffer *buf,PCIBIOS_entry entry);
+;----------------------------------------------------------------------------
+; Get the routing options for PCI devices
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_getRouting
+
+ ARG buf:DPTR, entry:QWORD
+
+ enter_c
+ mov eax,0B10Eh
+ mov bx,0
+ _les _di,[buf]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ movzx eax,ah
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ibool _PCIBIOS_setIRQ(int busDev,int intPin,int IRQ,PCIBIOS_entry entry);
+;----------------------------------------------------------------------------
+; Change the IRQ routing for the PCI device
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_setIRQ
+
+ ARG busDev:UINT, intPin:UINT, IRQ:UINT, entry:QWORD
+
+ enter_c
+ mov eax,0B10Fh
+ mov bx,[USHORT busDev]
+ mov cl,[BYTE intPin]
+ mov ch,[BYTE IRQ]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ mov eax,1
+ jnc @@1
+ xor eax,eax ; Function failed!
+@@1: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _PCIBIOS_specialCycle(int bus,ulong data,PCIBIOS_entry entry);
+;----------------------------------------------------------------------------
+; Generate a special cycle via the PCI BIOS.
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_specialCycle
+
+ ARG bus:UINT, data:ULONG, entry:QWORD
+
+ enter_c
+ mov eax,0B106h
+ mov bh,[BYTE bus]
+ mov ecx,[data]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ushort _PCI_getCS(void)
+;----------------------------------------------------------------------------
+cprocstart _PCI_getCS
+
+ mov ax,cs
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_inpb(int port)
+;----------------------------------------------------------------------------
+; Reads a byte from the specified port
+;----------------------------------------------------------------------------
+cprocstart PM_inpb
+
+ ARG port:UINT
+
+ push _bp
+ mov _bp,_sp
+ xor _ax,_ax
+ mov _dx,[port]
+ in al,dx
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_inpw(int port)
+;----------------------------------------------------------------------------
+; Reads a word from the specified port
+;----------------------------------------------------------------------------
+cprocstart PM_inpw
+
+ ARG port:UINT
+
+ push _bp
+ mov _bp,_sp
+ xor _ax,_ax
+ mov _dx,[port]
+ in ax,dx
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong PM_inpd(int port)
+;----------------------------------------------------------------------------
+; Reads a word from the specified port
+;----------------------------------------------------------------------------
+cprocstart PM_inpd
+
+ ARG port:UINT
+
+ push _bp
+ mov _bp,_sp
+ mov _dx,[port]
+ in eax,dx
+ifndef flatmodel
+ shld edx,eax,16 ; DX:AX = result
+endif
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_outpb(int port,int value)
+;----------------------------------------------------------------------------
+; Write a byte to the specified port.
+;----------------------------------------------------------------------------
+cprocstart PM_outpb
+
+ ARG port:UINT, value:UINT
+
+ push _bp
+ mov _bp,_sp
+ mov _dx,[port]
+ mov _ax,[value]
+ out dx,al
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_outpw(int port,int value)
+;----------------------------------------------------------------------------
+; Write a word to the specified port.
+;----------------------------------------------------------------------------
+cprocstart PM_outpw
+
+ ARG port:UINT, value:UINT
+
+ push _bp
+ mov _bp,_sp
+ mov _dx,[port]
+ mov _ax,[value]
+ out dx,ax
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_outpd(int port,ulong value)
+;----------------------------------------------------------------------------
+; Write a word to the specified port.
+;----------------------------------------------------------------------------
+cprocstart PM_outpd
+
+ ARG port:UINT, value:ULONG
+
+ push _bp
+ mov _bp,_sp
+ mov _dx,[port]
+ mov eax,[value]
+ out dx,eax
+ pop _bp
+ ret
+
+cprocend
+
+endcodeseg _pcilib
+
+ END
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/agp.c b/board/MAI/bios_emulator/scitech/src/pm/common/agp.c
new file mode 100644
index 0000000000..23f7e1e145
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/agp.c
@@ -0,0 +1,190 @@
+/****************************************************************************
+*
+* 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.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: 32-bit Ring 0 device driver
+*
+* Description: Generic module to implement AGP support functions using the
+* SciTech Nucleus AGP support drivers. If the OS provides
+* native AGP support, this module should *NOT* be used. Instead
+* wrappers should be placed around the OS support functions
+* to implement this functionality.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#ifndef REALMODE
+#include "nucleus/agp.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+static AGP_devCtx *agp;
+static AGP_driverFuncs driver;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+RETURNS:
+Size of AGP aperture in MB on success, 0 on failure.
+
+REMARKS:
+This function initialises the AGP driver in the system and returns the
+size of the available AGP aperture in megabytes.
+****************************************************************************/
+ulong PMAPI PM_agpInit(void)
+{
+ if ((agp = AGP_loadDriver(0)) == NULL)
+ return 0;
+ driver.dwSize = sizeof(driver);
+ if (!agp->QueryFunctions(AGP_GET_DRIVERFUNCS,&driver))
+ return 0;
+ switch (driver.GetApertureSize()) {
+ case agpSize4MB: return 4;
+ case agpSize8MB: return 8;
+ case agpSize16MB: return 16;
+ case agpSize32MB: return 32;
+ case agpSize64MB: return 64;
+ case agpSize128MB: return 128;
+ case agpSize256MB: return 256;
+ case agpSize512MB: return 512;
+ case agpSize1GB: return 1024;
+ case agpSize2GB: return 2048;
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+This function closes down the loaded AGP driver.
+****************************************************************************/
+void PMAPI PM_agpExit(void)
+{
+ AGP_unloadDriver(agp);
+}
+
+/****************************************************************************
+PARAMETERS:
+numPages - Number of memory pages that should be reserved
+type - Type of memory to allocate
+physContext - Returns the physical context handle for the mapping
+physAddr - Returns the physical address for the mapping
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function reserves a range of physical memory addresses on the system
+bus which the AGP controller will respond to. If this function succeeds,
+the AGP controller can respond to the reserved physical address range on
+the bus. However you must first call AGP_commitPhysical to cause this memory
+to actually be committed for use before it can be accessed.
+****************************************************************************/
+ibool PMAPI PM_agpReservePhysical(
+ ulong numPages,
+ int type,
+ void **physContext,
+ PM_physAddr *physAddr)
+{
+ switch (type) {
+ case PM_agpUncached:
+ type = agpUncached;
+ break;
+ case PM_agpWriteCombine:
+ type = agpWriteCombine;
+ break;
+ case PM_agpIntelDCACHE:
+ type = agpIntelDCACHE;
+ break;
+ default:
+ return false;
+ }
+ return driver.ReservePhysical(numPages,type,physContext,physAddr) == nOK;
+}
+
+/****************************************************************************
+PARAMETERS:
+physContext - Physical AGP context to release
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function releases a range of physical memory addresses on the system
+bus which the AGP controller will respond to. All committed memory for
+the physical address range covered by the context will be released.
+****************************************************************************/
+ibool PMAPI PM_agpReleasePhysical(
+ void *physContext)
+{
+ return driver.ReleasePhysical(physContext) == nOK;
+}
+
+/****************************************************************************
+PARAMETERS:
+physContext - Physical AGP context to commit memory for
+numPages - Number of pages to be committed
+startOffset - Offset in pages into the reserved physical context
+physAddr - Returns the physical address of the committed memory
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function commits into the specified physical context that was previously
+reserved by a call to ReservePhysical. You can use the startOffset and
+numPages parameters to only commit portions of the reserved memory range at
+a time.
+****************************************************************************/
+ibool PMAPI PM_agpCommitPhysical(
+ void *physContext,
+ ulong numPages,
+ ulong startOffset,
+ PM_physAddr *physAddr)
+{
+ return driver.CommitPhysical(physContext,numPages,startOffset,physAddr) == nOK;
+}
+
+/****************************************************************************
+PARAMETERS:
+physContext - Physical AGP context to free memory for
+numPages - Number of pages to be freed
+startOffset - Offset in pages into the reserved physical context
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function frees memory previously committed by the CommitPhysical
+function. Note that you can free a portion of a memory range that was
+previously committed if you wish.
+****************************************************************************/
+ibool PMAPI PM_agpFreePhysical(
+ void *physContext,
+ ulong numPages,
+ ulong startOffset)
+{
+ return driver.FreePhysical(physContext,numPages,startOffset) == nOK;
+}
+
+#endif /* !REALMODE */
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/keyboard.c b/board/MAI/bios_emulator/scitech/src/pm/common/keyboard.c
new file mode 100644
index 0000000000..79b4040ac1
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/keyboard.c
@@ -0,0 +1,450 @@
+/****************************************************************************
+*
+* 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.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+*
+* Description: Direct keyboard event handling module. This module contains
+* code to process raw scan code information, convert it to
+* virtual scan codes and do code page translation to ASCII
+* for different international keyboard layouts.
+*
+****************************************************************************/
+
+/*---------------------------- Implementation -----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+scanCode - Keyboard scan code to translate
+table - Code page table to search
+count - Number of entries in the code page table
+
+REMARKS:
+This function translates the scan codes from keyboard scan codes to ASCII
+codes using a binary search on the code page table.
+****************************************************************************/
+static uchar translateScan(
+ uchar scanCode,
+ codepage_entry_t *table,
+ int count)
+{
+ codepage_entry_t *test;
+ int n,pivot,val;
+
+ for (n = count; n > 0; ) {
+ pivot = n >> 1;
+ test = table + pivot;
+ val = scanCode - test->scanCode;
+ if (val < 0)
+ n = pivot;
+ else if (val == 0)
+ return test->asciiCode;
+ else {
+ table = test + 1;
+ n -= pivot + 1;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+This macro/function is used to converts the scan codes reported by the
+keyboard to our event libraries normalised format. We only have one scan
+code for the 'A' key, and use shift modifiers to determine if it is a
+Ctrl-F1, Alt-F1 etc. The raw scan codes from the keyboard work this way,
+but the OS gives us 'cooked' scan codes, we have to translate them back
+to the raw format.
+{secret}
+****************************************************************************/
+void _EVT_maskKeyCode(
+ event_t *evt)
+{
+ int ascii,scan = EVT_scanCode(evt->message);
+
+ evt->message &= ~0xFF;
+ if (evt->modifiers & EVT_NUMLOCK) {
+ if ((ascii = translateScan(scan,EVT.codePage->numPad,EVT.codePage->numPadLen)) != 0) {
+ evt->message |= ascii;
+ return;
+ }
+ }
+ if (evt->modifiers & EVT_CTRLSTATE) {
+ evt->message |= translateScan(scan,EVT.codePage->ctrl,EVT.codePage->ctrlLen);
+ return;
+ }
+ if (evt->modifiers & EVT_CAPSLOCK) {
+ if (evt->modifiers & EVT_SHIFTKEY) {
+ if ((ascii = translateScan(scan,EVT.codePage->shiftCaps,EVT.codePage->shiftCapsLen)) != 0) {
+ evt->message |= ascii;
+ return;
+ }
+ }
+ else {
+ if ((ascii = translateScan(scan,EVT.codePage->caps,EVT.codePage->capsLen)) != 0) {
+ evt->message |= ascii;
+ return;
+ }
+ }
+ }
+ if (evt->modifiers & EVT_SHIFTKEY) {
+ if ((ascii = translateScan(scan,EVT.codePage->shift,EVT.codePage->shiftLen)) != 0) {
+ evt->message |= ascii;
+ return;
+ }
+ }
+ evt->message |= translateScan(scan,EVT.codePage->normal,EVT.codePage->normalLen);
+}
+
+/****************************************************************************
+REMARKS:
+Returns true if the key with the specified scan code is being held down.
+****************************************************************************/
+static ibool _EVT_isKeyDown(
+ uchar scanCode)
+{
+ if (scanCode > 0x7F)
+ return false;
+ else
+ return EVT.keyTable[scanCode] != 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+what - Event code
+message - Event message (ASCII code and scan code)
+
+REMARKS:
+Adds a new keyboard event to the event queue. This routine is called from
+within the keyboard interrupt subroutine!
+
+NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
+ and we leave them OFF the entire time.
+****************************************************************************/
+static void addKeyEvent(
+ uint what,
+ uint message)
+{
+ event_t evt;
+
+ if (EVT.count < EVENTQSIZE) {
+ /* Save information in event record */
+ evt.when = _EVT_getTicks();
+ evt.what = what;
+ evt.message = message | 0x10000UL;
+ evt.where_x = 0;
+ evt.where_y = 0;
+ evt.relative_x = 0;
+ evt.relative_y = 0;
+ evt.modifiers = EVT.keyModifiers;
+ if (evt.what == EVT_KEYREPEAT) {
+ if (EVT.oldKey != -1)
+ EVT.evtq[EVT.oldKey].message += 0x10000UL;
+ else {
+ EVT.oldKey = EVT.freeHead;
+ addEvent(&evt); /* Add to tail of event queue */
+ }
+ }
+ else {
+#ifdef __QNX__
+ _EVT_maskKeyCode(&evt);
+#endif
+ addEvent(&evt); /* Add to tail of event queue */
+ }
+ EVT.oldMove = -1;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+This function waits for the keyboard controller to set the ready-for-write
+bit.
+****************************************************************************/
+static int kbWaitForWriteReady(void)
+{
+ int timeout = 8192;
+ while ((timeout > 0) && (PM_inpb(0x64) & 0x02))
+ timeout--;
+ return (timeout > 0);
+}
+
+/****************************************************************************
+REMARKS:
+This function waits for the keyboard controller to set the ready-for-read
+bit.
+****************************************************************************/
+static int kbWaitForReadReady(void)
+{
+ int timeout = 8192;
+ while ((timeout > 0) && (!(PM_inpb(0x64) & 0x01)))
+ timeout--;
+ return (timeout > 0);
+}
+
+/****************************************************************************
+PARAMETERS:
+data - Data to send to the keyboard
+
+REMARKS:
+This function sends a data byte to the keyboard controller.
+****************************************************************************/
+static int kbSendData(
+ uchar data)
+{
+ int resends = 4;
+ int timeout, temp;
+
+ do {
+ if (!kbWaitForWriteReady())
+ return 0;
+ PM_outpb(0x60,data);
+ timeout = 8192;
+ while (--timeout > 0) {
+ if (!kbWaitForReadReady())
+ return 0;
+ temp = PM_inpb(0x60);
+ if (temp == 0xFA)
+ return 1;
+ if (temp == 0xFE)
+ break;
+ }
+ } while ((resends-- > 0) && (timeout > 0));
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+modifiers - Keyboard modifier flags
+
+REMARKS:
+This function re-programs the LED's on the keyboard to the values stored
+in the passed in modifier flags. If the 'allowLEDS' flag is false, this
+function does nothing.
+****************************************************************************/
+static void setLEDS(
+ uint modifiers)
+{
+ if (EVT.allowLEDS) {
+ if (!kbSendData(0xED) || !kbSendData((modifiers>>9) & 7)) {
+ kbSendData(0xF4);
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Function to process raw scan codes read from the keyboard controller.
+
+NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
+ and we leave them OFF the entire time.
+{secret}
+****************************************************************************/
+void processRawScanCode(
+ int scan)
+{
+ static int pauseLoop = 0;
+ static int extended = 0;
+ int what;
+
+ if (pauseLoop) {
+ /* Skip scan codes until the pause key sequence has been read */
+ pauseLoop--;
+ }
+ else if (scan == 0xE0) {
+ /* This signals the start of an extended scan code sequence */
+ extended = 1;
+ }
+ else if (scan == 0xE1) {
+ /* The Pause key sends a strange scan code sequence, which is:
+ *
+ * E1 1D 52 E1 9D D2
+ *
+ * However there is never any release code nor any auto-repeat for
+ * this key. For this reason we simply ignore the key and skip the
+ * next 5 scan codes read from the keyboard.
+ */
+ pauseLoop = 5;
+ }
+ else {
+ /* Process the scan code normally (it may be an extended code
+ * however!). Bit 7 means key was released, and bits 0-6 are the
+ * scan code.
+ */
+ what = (scan & 0x80) ? EVT_KEYUP : EVT_KEYDOWN;
+ scan &= 0x7F;
+ if (extended) {
+ extended = 0;
+ if (scan == 0x2A || scan == 0x36) {
+ /* Ignore these extended scan code sequences. These are
+ * used by the keyboard controller to wrap around certain
+ * key sequences for the keypad (and when NUMLOCK is down
+ * internally).
+ */
+ return;
+ }
+
+ /* Convert extended codes for key sequences that we map to
+ * virtual scan codes so the user can detect them in their
+ * code.
+ */
+ switch (scan) {
+ case KB_leftCtrl: scan = KB_rightCtrl; break;
+ case KB_leftAlt: scan = KB_rightAlt; break;
+ case KB_divide: scan = KB_padDivide; break;
+ case KB_enter: scan = KB_padEnter; break;
+ case KB_padTimes: scan = KB_sysReq; break;
+ }
+ }
+ else {
+ /* Convert regular scan codes for key sequences that we map to
+ * virtual scan codes so the user can detect them in their
+ * code.
+ */
+ switch (scan) {
+ case KB_left: scan = KB_padLeft; break;
+ case KB_right: scan = KB_padRight; break;
+ case KB_up: scan = KB_padUp; break;
+ case KB_down: scan = KB_padDown; break;
+ case KB_insert: scan = KB_padInsert; break;
+ case KB_delete: scan = KB_padDelete; break;
+ case KB_home: scan = KB_padHome; break;
+ case KB_end: scan = KB_padEnd; break;
+ case KB_pageUp: scan = KB_padPageUp; break;
+ case KB_pageDown: scan = KB_padPageDown; break;
+ }
+ }
+
+ /* Determine if the key is an UP, DOWN or REPEAT and maintain the
+ * up/down status of all keys in our global key array.
+ */
+ if (what == EVT_KEYDOWN) {
+ if (EVT.keyTable[scan])
+ what = EVT_KEYREPEAT;
+ else
+ EVT.keyTable[scan] = scan;
+ }
+ else {
+ EVT.keyTable[scan] = 0;
+ }
+
+ /* Handle shift key modifiers */
+ if (what != EVT_KEYREPEAT) {
+ switch (scan) {
+ case KB_capsLock:
+ if (what == EVT_KEYDOWN)
+ EVT.keyModifiers ^= EVT_CAPSLOCK;
+ setLEDS(EVT.keyModifiers);
+ break;
+ case KB_numLock:
+ if (what == EVT_KEYDOWN)
+ EVT.keyModifiers ^= EVT_NUMLOCK;
+ setLEDS(EVT.keyModifiers);
+ break;
+ case KB_scrollLock:
+ if (what == EVT_KEYDOWN)
+ EVT.keyModifiers ^= EVT_SCROLLLOCK;
+ setLEDS(EVT.keyModifiers);
+ break;
+ case KB_leftShift:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_LEFTSHIFT;
+ else
+ EVT.keyModifiers |= EVT_LEFTSHIFT;
+ break;
+ case KB_rightShift:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_RIGHTSHIFT;
+ else
+ EVT.keyModifiers |= EVT_RIGHTSHIFT;
+ break;
+ case KB_leftCtrl:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_LEFTCTRL;
+ else
+ EVT.keyModifiers |= EVT_LEFTCTRL;
+ break;
+ case KB_rightCtrl:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_RIGHTCTRL;
+ else
+ EVT.keyModifiers |= EVT_RIGHTCTRL;
+ break;
+ case KB_leftAlt:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_LEFTALT;
+ else
+ EVT.keyModifiers |= EVT_LEFTALT;
+ break;
+ case KB_rightAlt:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_RIGHTALT;
+ else
+ EVT.keyModifiers |= EVT_RIGHTALT;
+ break;
+#ifdef SUPPORT_CTRL_ALT_DEL
+ case KB_delete:
+ if ((EVT.keyModifiers & EVT_CTRLSTATE) && (EVT.keyModifiers & EVT_ALTSTATE))
+ Reboot();
+ break;
+#endif
+ }
+ }
+
+ /* Add the untranslated key code to the event queue. All
+ * translation to ASCII from the key codes occurs when the key
+ * is extracted from the queue, saving time in the low level
+ * interrupt handler.
+ */
+ addKeyEvent(what,scan << 8);
+ }
+}
+
+/****************************************************************************
+DESCRIPTION:
+Enables/disables the update of the keyboard LED status indicators.
+
+HEADER:
+event.h
+
+PARAMETERS:
+enable - True to enable, false to disable
+
+REMARKS:
+Enables the update of the keyboard LED status indicators. Sometimes it may
+be convenient in the application to turn off the updating of the LED
+status indicators (such as if a game is using the CAPSLOCK key for some
+function). Passing in a value of FALSE to this function will turn off all
+the LEDS, and stop updating them when the internal status changes (note
+however that internally we still keep track of the toggle key status!).
+****************************************************************************/
+void EVTAPI EVT_allowLEDS(
+ ibool enable)
+{
+ EVT.allowLEDS = true;
+ if (enable)
+ setLEDS(EVT.keyModifiers);
+ else
+ setLEDS(0);
+ EVT.allowLEDS = enable;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/malloc.c b/board/MAI/bios_emulator/scitech/src/pm/common/malloc.c
new file mode 100644
index 0000000000..83ef22113c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/malloc.c
@@ -0,0 +1,205 @@
+/****************************************************************************
+*
+* 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.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+*
+* Description: Module for implementing the PM library overrideable memory
+* allocator functions.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+void * (*__PM_malloc)(size_t size) = malloc;
+void * (*__PM_calloc)(size_t nelem,size_t size) = calloc;
+void * (*__PM_realloc)(void *ptr,size_t size) = realloc;
+void (*__PM_free)(void *p) = free;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+DESCRIPTION:
+Use local memory allocation routines.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+malloc - Pointer to new malloc routine to use
+calloc - Pointer to new caalloc routine to use
+realloc - Pointer to new realloc routine to use
+free - Pointer to new free routine to use
+
+REMARKS:
+Tells the PM library to use a set of user specified memory allocation
+routines instead of using the normal malloc/calloc/realloc/free standard
+C library functions. This is useful if you wish to use a third party
+debugging malloc library or perhaps a set of faster memory allocation
+functions with the PM library, or any apps that use the PM library (such as
+the MGL). Once you have registered your memory allocation routines, all
+calls to PM_malloc, PM_calloc, PM_realloc and PM_free will be revectored to
+your local memory allocation routines.
+
+This is also useful if you need to keep track of just how much physical
+memory your program has been using. You can use the PM_availableMemory
+function to find out how much physical memory is available when the program
+starts, and then you can use your own local memory allocation routines to
+keep track of how much memory has been used and freed.
+
+NOTE: This function should be called right at the start of your application,
+ before you initialise any other components or libraries.
+
+NOTE: Code compiled into Binary Portable DLL's and Drivers automatically
+ end up calling these functions via the BPD C runtime library.
+
+SEE ALSO:
+PM_malloc, PM_calloc, PM_realloc, PM_free, PM_availableMemory
+****************************************************************************/
+void PMAPI PM_useLocalMalloc(
+ void * (*malloc)(size_t size),
+ void * (*calloc)(size_t nelem,size_t size),
+ void * (*realloc)(void *ptr,size_t size),
+ void (*free)(void *p))
+{
+ __PM_malloc = malloc;
+ __PM_calloc = calloc;
+ __PM_realloc = realloc;
+ __PM_free = free;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Allocate a block of memory.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+size - Size of block to allocate in bytes
+
+RETURNS:
+Pointer to allocated block, or NULL if out of memory.
+
+REMARKS:
+Allocates a block of memory of length size. If you have changed the memory
+allocation routines with the PM_useLocalMalloc function, then calls to this
+function will actually make calls to the local memory allocation routines
+that you have registered.
+
+SEE ALSO:
+PM_calloc, PM_realloc, PM_free, PM_useLocalMalloc
+****************************************************************************/
+void * PMAPI PM_malloc(
+ size_t size)
+{
+ return __PM_malloc(size);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Allocate and clear a large memory block.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+nelem - number of contiguous size-byte units to allocate
+size - size of unit in bytes
+
+RETURNS:
+Pointer to allocated memory if successful, NULL if out of memory.
+
+REMARKS:
+Allocates a block of memory of length (size * nelem), and clears the
+allocated area with zeros (0). If you have changed the memory allocation
+routines with the PM_useLocalMalloc function, then calls to this function
+will actually make calls to the local memory allocation routines that you
+have registered.
+
+SEE ALSO:
+PM_malloc, PM_realloc, PM_free, PM_useLocalMalloc
+****************************************************************************/
+void * PMAPI PM_calloc(
+ size_t nelem,
+ size_t size)
+{
+ return __PM_calloc(nelem,size);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Re-allocate a block of memory
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+ptr - Pointer to block to resize
+size - size of unit in bytes
+
+RETURNS:
+Pointer to allocated memory if successful, NULL if out of memory.
+
+REMARKS:
+This function reallocates a block of memory that has been previously been
+allocated to the new of size. The new size may be smaller or larger than
+the original block of memory. If you have changed the memory allocation
+routines with the PM_useLocalMalloc function, then calls to this function
+will actually make calls to the local memory allocation routines that you
+have registered.
+
+SEE ALSO:
+PM_malloc, PM_calloc, PM_free, PM_useLocalMalloc
+****************************************************************************/
+void * PMAPI PM_realloc(
+ void *ptr,
+ size_t size)
+{
+ return __PM_realloc(ptr,size);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Frees a block of memory.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+p - Pointer to memory block to free
+
+REMARKS:
+Frees a block of memory previously allocated with either PM_malloc,
+PM_calloc or PM_realloc.
+
+SEE ALSO:
+PM_malloc, PM_calloc, PM_realloc, PM_useLocalMalloc
+****************************************************************************/
+void PMAPI PM_free(
+ void *p)
+{
+ __PM_free(p);
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/mtrr.c b/board/MAI/bios_emulator/scitech/src/pm/common/mtrr.c
new file mode 100644
index 0000000000..d6ced6eadc
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/mtrr.c
@@ -0,0 +1,867 @@
+/****************************************************************************
+*
+* 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.
+*
+* ========================================================================
+*
+* Heavily based on code copyright (C) Richard Gooch
+*
+* Language: ANSI C
+* Environment: 32-bit Ring 0 device driver
+*
+* Description: Generic Memory Type Range Register (MTRR) functions to
+* manipulate the MTRR registers on supported CPU's. This code
+* *must* run at ring 0, so you can't normally include this
+* code directly in normal applications (the except is DOS4GW
+* apps which run at ring 0 under real DOS). Thus this code
+* will normally be compiled into a ring 0 device driver for
+* the target operating system.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "ztimerc.h"
+#include "mtrr.h"
+
+#ifndef REALMODE
+
+/*--------------------------- Global variables ----------------------------*/
+
+/* Intel pre-defined MTRR registers */
+
+#define NUM_FIXED_RANGES 88
+#define INTEL_cap_MSR 0x0FE
+#define INTEL_defType_MSR 0x2FF
+#define INTEL_fix64K_00000_MSR 0x250
+#define INTEL_fix16K_80000_MSR 0x258
+#define INTEL_fix16K_A0000_MSR 0x259
+#define INTEL_fix4K_C0000_MSR 0x268
+#define INTEL_fix4K_C8000_MSR 0x269
+#define INTEL_fix4K_D0000_MSR 0x26A
+#define INTEL_fix4K_D8000_MSR 0x26B
+#define INTEL_fix4K_E0000_MSR 0x26C
+#define INTEL_fix4K_E8000_MSR 0x26D
+#define INTEL_fix4K_F0000_MSR 0x26E
+#define INTEL_fix4K_F8000_MSR 0x26F
+
+/* Macros to find the address of a paricular MSR register */
+
+#define INTEL_physBase_MSR(reg) (0x200 + 2 * (reg))
+#define INTEL_physMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+/* Cyrix CPU configuration register indexes */
+#define CX86_CCR0 0xC0
+#define CX86_CCR1 0xC1
+#define CX86_CCR2 0xC2
+#define CX86_CCR3 0xC3
+#define CX86_CCR4 0xE8
+#define CX86_CCR5 0xE9
+#define CX86_CCR6 0xEA
+#define CX86_DIR0 0xFE
+#define CX86_DIR1 0xFF
+#define CX86_ARR_BASE 0xC4
+#define CX86_RCR_BASE 0xDC
+
+/* Structure to maintain machine state while updating MTRR registers */
+
+typedef struct {
+ ulong flags;
+ ulong defTypeLo;
+ ulong defTypeHi;
+ ulong cr4Val;
+ ulong ccr3;
+ } MTRRContext;
+
+static int numMTRR = -1;
+static int cpuFamily,cpuType,cpuStepping;
+static void (*getMTRR)(uint reg,ulong *base,ulong *size,int *type) = NULL;
+static void (*setMTRR)(uint reg,ulong base,ulong size,int type) = NULL;
+static int (*getFreeRegion)(ulong base,ulong size) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+RETURNS:
+Returns non-zero if we have the write-combining memory type
+****************************************************************************/
+static int MTRR_haveWriteCombine(void)
+{
+ ulong config,dummy;
+
+ switch (cpuFamily) {
+ case CPU_AMD:
+ if (cpuType < CPU_AMDAthlon) {
+ /* AMD K6-2 stepping 8 and later support the MTRR registers.
+ * The earlier K6-2 steppings (300Mhz models) do not
+ * support MTRR's.
+ */
+ if ((cpuType < CPU_AMDK6_2) || (cpuType == CPU_AMDK6_2 && cpuStepping < 8))
+ return 0;
+ return 1;
+ }
+ /* Fall through for AMD Athlon which uses P6 style MTRR's */
+ case CPU_Intel:
+ _MTRR_readMSR(INTEL_cap_MSR,&config,&dummy);
+ return (config & (1 << 10));
+ case CPU_Cyrix:
+ /* Cyrix 6x86 and later support the MTRR registers */
+ if (cpuType < CPU_Cyrix6x86)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+
+RETURNS:
+The index of the region on success, else -1 on error.
+
+REMARKS:
+Generic function to find the location of a free MTRR register to be used
+for creating a new mapping.
+****************************************************************************/
+static int GENERIC_getFreeRegion(
+ ulong base,
+ ulong size)
+{
+ int i,ltype;
+ ulong lbase,lsize;
+
+ for (i = 0; i < numMTRR; i++) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lsize < 1)
+ return i;
+ }
+ (void)base;
+ (void)size;
+ return -1;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+
+RETURNS:
+The index of the region on success, else -1 on error.
+
+REMARKS:
+Generic function to find the location of a free MTRR register to be used
+for creating a new mapping.
+****************************************************************************/
+static int AMDK6_getFreeRegion(
+ ulong base,
+ ulong size)
+{
+ int i,ltype;
+ ulong lbase,lsize;
+
+ for (i = 0; i < numMTRR; i++) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lsize < 1)
+ return i;
+ }
+ (void)base;
+ (void)size;
+ return -1;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+
+RETURNS:
+The index of the region on success, else -1 on error.
+
+REMARKS:
+Cyrix specific function to find the location of a free MTRR register to be
+used for creating a new mapping.
+****************************************************************************/
+static int CYRIX_getFreeRegion(
+ ulong base,
+ ulong size)
+{
+ int i,ltype;
+ ulong lbase, lsize;
+
+ if (size > 0x2000000UL) {
+ /* If we are to set up a region >32M then look at ARR7 immediately */
+ getMTRR(7,&lbase,&lsize,&ltype);
+ if (lsize < 1)
+ return 7;
+ }
+ else {
+ /* Check ARR0-6 registers */
+ for (i = 0; i < 7; i++) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lsize < 1)
+ return i;
+ }
+ /* Try ARR7 but its size must be at least 256K */
+ getMTRR(7,&lbase,&lsize,&ltype);
+ if ((lsize < 1) && (size >= 0x40000))
+ return i;
+ }
+ (void)base;
+ return -1;
+}
+
+/****************************************************************************
+PARAMETERS:
+c - Place to store the machine context across the call
+
+REMARKS:
+Puts the processor into a state where MTRRs can be safely updated
+****************************************************************************/
+static void MTRR_beginUpdate(
+ MTRRContext *c)
+{
+ c->flags = _MTRR_disableInt();
+ if (cpuFamily != CPU_AMD || (cpuFamily == CPU_AMD && cpuType >= CPU_AMDAthlon)) {
+ switch (cpuFamily) {
+ case CPU_Intel:
+ case CPU_AMD:
+ /* Disable MTRRs, and set the default type to uncached */
+ c->cr4Val = _MTRR_saveCR4();
+ _MTRR_readMSR(INTEL_defType_MSR,&c->defTypeLo,&c->defTypeHi);
+ _MTRR_writeMSR(INTEL_defType_MSR,c->defTypeLo & 0xF300UL,c->defTypeHi);
+ break;
+ case CPU_Cyrix:
+ c->ccr3 = _MTRR_getCx86(CX86_CCR3);
+ _MTRR_setCx86(CX86_CCR3, (uchar)((c->ccr3 & 0x0F) | 0x10));
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+c - Place to restore the machine context from
+
+REMARKS:
+Restores the processor after updating any of the registers
+****************************************************************************/
+static void MTRR_endUpdate(
+ MTRRContext *c)
+{
+ if (cpuFamily != CPU_AMD || (cpuFamily == CPU_AMD && cpuType >= CPU_AMDAthlon)) {
+ PM_flushTLB();
+ switch (cpuFamily) {
+ case CPU_Intel:
+ case CPU_AMD:
+ _MTRR_writeMSR(INTEL_defType_MSR,c->defTypeLo,c->defTypeHi);
+ _MTRR_restoreCR4(c->cr4Val);
+ break;
+ case CPU_Cyrix:
+ _MTRR_setCx86(CX86_CCR3,(uchar)c->ccr3);
+ break;
+ }
+ }
+
+ /* Re-enable interrupts (if enabled previously) */
+ _MTRR_restoreInt(c->flags);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to read
+base - Place to store the starting physical base address of the region
+size - Place to store the size in bytes of the region
+type - Place to store the type of the MTRR register
+
+REMARKS:
+Intel specific function to read the value of a specific MTRR register.
+****************************************************************************/
+static void INTEL_getMTRR(
+ uint reg,
+ ulong *base,
+ ulong *size,
+ int *type)
+{
+ ulong hi,maskLo,baseLo;
+
+ _MTRR_readMSR(INTEL_physMask_MSR(reg),&maskLo,&hi);
+ if ((maskLo & 0x800) == 0) {
+ /* MTRR is disabled, so it is free */
+ *base = 0;
+ *size = 0;
+ *type = 0;
+ return;
+ }
+ _MTRR_readMSR(INTEL_physBase_MSR(reg),&baseLo,&hi);
+ maskLo = (maskLo & 0xFFFFF000UL);
+ *size = ~(maskLo - 1);
+ *base = (baseLo & 0xFFFFF000UL);
+ *type = (baseLo & 0xFF);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void INTEL_setMTRR(
+ uint reg,
+ ulong base,
+ ulong size,
+ int type)
+{
+ MTRRContext c;
+
+ MTRR_beginUpdate(&c);
+ if (size == 0) {
+ /* The invalid bit is kept in the mask, so we simply clear the
+ * relevant mask register to disable a range.
+ */
+ _MTRR_writeMSR(INTEL_physMask_MSR(reg),0,0);
+ }
+ else {
+ _MTRR_writeMSR(INTEL_physBase_MSR(reg),base | type,0);
+ _MTRR_writeMSR(INTEL_physMask_MSR(reg),~(size - 1) | 0x800,0);
+ }
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+REMARKS:
+Disabled banked write combing for Intel processors. We always disable this
+because it invariably causes problems with older hardware.
+****************************************************************************/
+static void INTEL_disableBankedWriteCombine(void)
+{
+ MTRRContext c;
+
+ MTRR_beginUpdate(&c);
+ _MTRR_writeMSR(INTEL_fix16K_A0000_MSR,0,0);
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void AMD_getMTRR(
+ uint reg,
+ ulong *base,
+ ulong *size,
+ int *type)
+{
+ ulong low,high;
+
+ /* Upper dword is region 1, lower is region 0 */
+ _MTRR_readMSR(0xC0000085, &low, &high);
+ if (reg == 1)
+ low = high;
+
+ /* Find the base and type for the region */
+ *base = low & 0xFFFE0000;
+ *type = 0;
+ if (low & 1)
+ *type = PM_MTRR_UNCACHABLE;
+ if (low & 2)
+ *type = PM_MTRR_WRCOMB;
+ if ((low & 3) == 0) {
+ *size = 0;
+ return;
+ }
+
+ /* This needs a little explaining. The size is stored as an
+ * inverted mask of bits of 128K granularity 15 bits long offset
+ * 2 bits
+ *
+ * So to get a size we do invert the mask and add 1 to the lowest
+ * mask bit (4 as its 2 bits in). This gives us a size we then shift
+ * to turn into 128K blocks
+ *
+ * eg 111 1111 1111 1100 is 512K
+ *
+ * invert 000 0000 0000 0011
+ * +1 000 0000 0000 0100
+ * *128K ...
+ */
+ low = (~low) & 0x0FFFC;
+ *size = (low + 4) << 15;
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void AMD_setMTRR(
+ uint reg,
+ ulong base,
+ ulong size,
+ int type)
+{
+ ulong low,high,newVal;
+ MTRRContext c;
+
+ MTRR_beginUpdate(&c);
+ _MTRR_readMSR(0xC0000085, &low, &high);
+ if (size == 0) {
+ /* Clear register to disable */
+ if (reg)
+ high = 0;
+ else
+ low = 0;
+ }
+ else {
+ /* Set the register to the base (already shifted for us), the
+ * type (off by one) and an inverted bitmask of the size
+ * The size is the only odd bit. We are fed say 512K
+ * We invert this and we get 111 1111 1111 1011 but
+ * if you subtract one and invert you get the desired
+ * 111 1111 1111 1100 mask
+ */
+ newVal = (((~(size-1)) >> 15) & 0x0001FFFC) | base | (type+1);
+ if (reg)
+ high = newVal;
+ else
+ low = newVal;
+ }
+
+ /* The writeback rule is quite specific. See the manual. Its
+ * disable local interrupts, write back the cache, set the MTRR
+ */
+ PM_flushTLB();
+ _MTRR_writeMSR(0xC0000085, low, high);
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void CYRIX_getMTRR(
+ uint reg,
+ ulong *base,
+ ulong *size,
+ int *type)
+{
+ MTRRContext c;
+ uchar arr = CX86_ARR_BASE + reg*3;
+ uchar rcr,shift;
+
+ /* Save flags and disable interrupts */
+ MTRR_beginUpdate(&c);
+ ((uchar*)base)[3] = _MTRR_getCx86(arr);
+ ((uchar*)base)[2] = _MTRR_getCx86((uchar)(arr+1));
+ ((uchar*)base)[1] = _MTRR_getCx86((uchar)(arr+2));
+ rcr = _MTRR_getCx86((uchar)(CX86_RCR_BASE + reg));
+ MTRR_endUpdate(&c);
+
+ /* Enable interrupts if it was enabled previously */
+ shift = ((uchar*)base)[1] & 0x0f;
+ *base &= 0xFFFFF000UL;
+
+ /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
+ * Note: shift==0xF means 4G, this is unsupported.
+ */
+ if (shift)
+ *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift;
+ else
+ *size = 0;
+
+ /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
+ if (reg < 7) {
+ switch (rcr) {
+ case 1: *type = PM_MTRR_UNCACHABLE; break;
+ case 8: *type = PM_MTRR_WRBACK; break;
+ case 9: *type = PM_MTRR_WRCOMB; break;
+ case 24:
+ default: *type = PM_MTRR_WRTHROUGH; break;
+ }
+ }
+ else {
+ switch (rcr) {
+ case 0: *type = PM_MTRR_UNCACHABLE; break;
+ case 8: *type = PM_MTRR_WRCOMB; break;
+ case 9: *type = PM_MTRR_WRBACK; break;
+ case 25:
+ default: *type = PM_MTRR_WRTHROUGH; break;
+ }
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void CYRIX_setMTRR(
+ uint reg,
+ ulong base,
+ ulong size,
+ int type)
+{
+ MTRRContext c;
+ uchar arr = CX86_ARR_BASE + reg*3;
+ uchar arr_type,arr_size;
+
+ /* Count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
+ size >>= (reg < 7 ? 12 : 18);
+ size &= 0x7FFF; /* Make sure arr_size <= 14 */
+ for (arr_size = 0; size; arr_size++, size >>= 1)
+ ;
+ if (reg < 7) {
+ switch (type) {
+ case PM_MTRR_UNCACHABLE: arr_type = 1; break;
+ case PM_MTRR_WRCOMB: arr_type = 9; break;
+ case PM_MTRR_WRTHROUGH: arr_type = 24; break;
+ default: arr_type = 8; break;
+ }
+ }
+ else {
+ switch (type) {
+ case PM_MTRR_UNCACHABLE: arr_type = 0; break;
+ case PM_MTRR_WRCOMB: arr_type = 8; break;
+ case PM_MTRR_WRTHROUGH: arr_type = 25; break;
+ default: arr_type = 9; break;
+ }
+ }
+ MTRR_beginUpdate(&c);
+ _MTRR_setCx86((uchar)arr, ((uchar*)&base)[3]);
+ _MTRR_setCx86((uchar)(arr+1), ((uchar*)&base)[2]);
+ _MTRR_setCx86((uchar)(arr+2), (uchar)((((uchar*)&base)[1]) | arr_size));
+ _MTRR_setCx86((uchar)(CX86_RCR_BASE + reg), (uchar)arr_type);
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+REMARKS:
+On Cyrix 6x86(MX) and MII the ARR3 is special: it has connection
+with the SMM (System Management Mode) mode. So we need the following:
+Check whether SMI_LOCK (CCR3 bit 0) is set
+ if it is set, ARR3 cannot be changed (it cannot be changed until the
+ next processor reset)
+ if it is reset, then we can change it, set all the needed bits:
+ - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
+ - disable access to SMM memory (CCR1 bit 2 reset)
+ - disable SMM mode (CCR1 bit 1 reset)
+ - disable write protection of ARR3 (CCR6 bit 1 reset)
+ - (maybe) disable ARR3
+Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
+****************************************************************************/
+static void CYRIX_initARR(void)
+{
+ MTRRContext c;
+ uchar ccr[7];
+ int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
+
+ /* Begin updating */
+ MTRR_beginUpdate(&c);
+
+ /* Save all CCRs locally */
+ ccr[0] = _MTRR_getCx86(CX86_CCR0);
+ ccr[1] = _MTRR_getCx86(CX86_CCR1);
+ ccr[2] = _MTRR_getCx86(CX86_CCR2);
+ ccr[3] = (uchar)c.ccr3;
+ ccr[4] = _MTRR_getCx86(CX86_CCR4);
+ ccr[5] = _MTRR_getCx86(CX86_CCR5);
+ ccr[6] = _MTRR_getCx86(CX86_CCR6);
+ if (ccr[3] & 1)
+ ccrc[3] = 1;
+ else {
+ /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
+ * access to SMM memory through ARR3 (bit 7).
+ */
+ if (ccr[6] & 0x02) {
+ ccr[6] &= 0xFD;
+ ccrc[6] = 1; /* Disable write protection of ARR3. */
+ _MTRR_setCx86(CX86_CCR6,ccr[6]);
+ }
+ }
+
+ /* If we changed CCR1 in memory, change it in the processor, too. */
+ if (ccrc[1])
+ _MTRR_setCx86(CX86_CCR1,ccr[1]);
+
+ /* Enable ARR usage by the processor */
+ if (!(ccr[5] & 0x20)) {
+ ccr[5] |= 0x20;
+ ccrc[5] = 1;
+ _MTRR_setCx86(CX86_CCR5,ccr[5]);
+ }
+
+ /* We are finished updating */
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the MTRR module, by detecting the processor type and determining
+if the processor supports the MTRR functionality.
+****************************************************************************/
+void MTRR_init(void)
+{
+ int i,cpu,ltype;
+ ulong eax,edx,lbase,lsize;
+
+ /* Check that we have a compatible CPU */
+ if (numMTRR == -1) {
+ numMTRR = 0;
+ if (!_MTRR_isRing0())
+ return;
+ cpu = CPU_getProcessorType();
+ cpuFamily = cpu & CPU_familyMask;
+ cpuType = cpu & CPU_mask;
+ cpuStepping = (cpu & CPU_steppingMask) >> CPU_steppingShift;
+ switch (cpuFamily) {
+ case CPU_Intel:
+ /* Intel Pentium Pro and later support the MTRR registers */
+ if (cpuType < CPU_PentiumPro)
+ return;
+ _MTRR_readMSR(INTEL_cap_MSR,&eax,&edx);
+ numMTRR = eax & 0xFF;
+ getMTRR = INTEL_getMTRR;
+ setMTRR = INTEL_setMTRR;
+ getFreeRegion = GENERIC_getFreeRegion;
+ INTEL_disableBankedWriteCombine();
+ break;
+ case CPU_AMD:
+ /* AMD K6-2 and later support the MTRR registers */
+ if ((cpuType < CPU_AMDK6_2) || (cpuType == CPU_AMDK6_2 && cpuStepping < 8))
+ return;
+ if (cpuType < CPU_AMDAthlon) {
+ numMTRR = 2; /* AMD CPU's have 2 MTRR's */
+ getMTRR = AMD_getMTRR;
+ setMTRR = AMD_setMTRR;
+ getFreeRegion = AMDK6_getFreeRegion;
+
+ /* For some reason some IBM systems with K6-2 processors
+ * have write combined enabled for the system BIOS
+ * region from 0xE0000 to 0xFFFFFF. We need *both* MTRR's
+ * for our own graphics drivers, so if we detect any
+ * regions below the 1Meg boundary, we remove them
+ * so we can use this MTRR register ourselves.
+ */
+ for (i = 0; i < numMTRR; i++) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lbase < 0x100000)
+ setMTRR(i,0,0,0);
+ }
+ }
+ else {
+ /* AMD Athlon uses P6 style MTRR's */
+ _MTRR_readMSR(INTEL_cap_MSR,&eax,&edx);
+ numMTRR = eax & 0xFF;
+ getMTRR = INTEL_getMTRR;
+ setMTRR = INTEL_setMTRR;
+ getFreeRegion = GENERIC_getFreeRegion;
+ INTEL_disableBankedWriteCombine();
+ }
+ break;
+ case CPU_Cyrix:
+ /* Cyrix 6x86 and later support the MTRR registers */
+ if (cpuType < CPU_Cyrix6x86 || cpuType >= CPU_CyrixMediaGX)
+ return;
+ numMTRR = 8; /* Cyrix CPU's have 8 ARR's */
+ getMTRR = CYRIX_getMTRR;
+ setMTRR = CYRIX_setMTRR;
+ getFreeRegion = CYRIX_getFreeRegion;
+ CYRIX_initARR();
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+RETURNS:
+Error code describing the result.
+
+REMARKS:
+Function to enable write combining for the specified region of memory.
+****************************************************************************/
+int MTRR_enableWriteCombine(
+ ulong base,
+ ulong size,
+ uint type)
+{
+ int i;
+ int ltype;
+ ulong lbase,lsize,last;
+
+ /* Check that we have a CPU that supports MTRR's and type is valid */
+ if (numMTRR <= 0) {
+ if (!_MTRR_isRing0())
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+ return PM_MTRR_NOT_SUPPORTED;
+ }
+ if (type >= PM_MTRR_MAX)
+ return PM_MTRR_ERR_PARAMS;
+
+ /* If the type is WC, check that this processor supports it */
+ if (!MTRR_haveWriteCombine())
+ return PM_MTRR_ERR_NOWRCOMB;
+
+ /* Adjust the boundaries depending on the CPU type */
+ switch (cpuFamily) {
+ case CPU_AMD:
+ if (cpuType < CPU_AMDAthlon) {
+ /* Apply the K6 block alignment and size rules. In order:
+ * o Uncached or gathering only
+ * o 128K or bigger block
+ * o Power of 2 block
+ * o base suitably aligned to the power
+ */
+ if (type > PM_MTRR_WRCOMB && (size < (1 << 17) || (size & ~(size-1))-size || (base & (size-1))))
+ return PM_MTRR_ERR_NOT_ALIGNED;
+ break;
+ }
+ /* Fall through for AMD Athlon which uses P6 style MTRR's */
+ case CPU_Intel:
+ case CPU_Cyrix:
+ if ((base & 0xFFF) || (size & 0xFFF)) {
+ /* Base and size must be multiples of 4Kb */
+ return PM_MTRR_ERR_NOT_4KB_ALIGNED;
+ }
+ if (base < 0x100000) {
+ /* Base must be >= 1Mb */
+ return PM_MTRR_ERR_BELOW_1MB;
+ }
+
+ /* Check upper bits of base and last are equal and lower bits
+ * are 0 for base and 1 for last
+ */
+ last = base + size - 1;
+ for (lbase = base; !(lbase & 1) && (last & 1); lbase = lbase >> 1, last = last >> 1)
+ ;
+ if (lbase != last) {
+ /* Base is not aligned on the correct boundary */
+ return PM_MTRR_ERR_NOT_ALIGNED;
+ }
+ break;
+ default:
+ return PM_MTRR_NOT_SUPPORTED;
+ }
+
+ /* Search for existing MTRR */
+ for (i = 0; i < numMTRR; ++i) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lbase == 0 && lsize == 0)
+ continue;
+ if (base > lbase + (lsize-1))
+ continue;
+ if ((base < lbase) && (base+size-1 < lbase))
+ continue;
+
+ /* Check that we don't overlap an existing region */
+ if (type != PM_MTRR_UNCACHABLE) {
+ if ((base < lbase) || (base+size-1 > lbase+lsize-1))
+ return PM_MTRR_ERR_OVERLAP;
+ }
+ else if (base == lbase && size == lsize) {
+ /* The region already exists so leave it alone */
+ return PM_MTRR_ERR_OK;
+ }
+
+ /* New region is enclosed by an existing region, so only allow
+ * a new type to be created if we are setting a region to be
+ * uncacheable (such as MMIO registers within a framebuffer).
+ */
+ if (ltype != (int)type) {
+ if (type == PM_MTRR_UNCACHABLE)
+ continue;
+ return PM_MTRR_ERR_TYPE_MISMATCH;
+ }
+ return PM_MTRR_ERR_OK;
+ }
+
+ /* Search for an empty MTRR */
+ if ((i = getFreeRegion(base,size)) < 0)
+ return PM_MTRR_ERR_NONE_FREE;
+ setMTRR(i,base,size,type);
+ return PM_MTRR_ERR_OK;
+}
+
+/****************************************************************************
+PARAMETERS:
+callback - Function to callback with write combine information
+
+REMARKS:
+Function to enumerate all write combine regions currently enabled for the
+processor.
+****************************************************************************/
+int PMAPI PM_enumWriteCombine(
+ PM_enumWriteCombine_t callback)
+{
+ int i,ltype;
+ ulong lbase,lsize;
+
+ /* Check that we have a CPU that supports MTRR's and type is valid */
+ if (numMTRR <= 0) {
+ if (!_MTRR_isRing0())
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+ return PM_MTRR_NOT_SUPPORTED;
+ }
+
+ /* Enumerate all existing MTRR's */
+ for (i = 0; i < numMTRR; ++i) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ callback(lbase,lsize,ltype);
+ }
+ return PM_MTRR_ERR_OK;
+}
+#endif
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/pcilib.c b/board/MAI/bios_emulator/scitech/src/pm/common/pcilib.c
new file mode 100644
index 0000000000..8dd6dd13e3
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/pcilib.c
@@ -0,0 +1,747 @@
+/****************************************************************************
+*
+* 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.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+*
+* Description: Module for interfacing to the PCI bus and configuration
+* space registers.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "pcilib.h"
+#if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__)
+#include <string.h>
+#endif
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+#pragma pack(1)
+
+/* Length of the memory mapping for the PCI BIOS */
+
+#define BIOS_LIMIT (128 * 1024L - 1)
+
+/* Macros for accessing the PCI BIOS functions from 32-bit protected mode */
+
+#define BIOS32_SIGNATURE (((ulong)'_' << 0) + ((ulong)'3' << 8) + ((ulong)'2' << 16) + ((ulong)'_' << 24))
+#define PCI_SIGNATURE (((ulong)'P' << 0) + ((ulong)'C' << 8) + ((ulong)'I' << 16) + ((ulong)' ' << 24))
+#define PCI_SERVICE (((ulong)'$' << 0) + ((ulong)'P' << 8) + ((ulong)'C' << 16) + ((ulong)'I' << 24))
+#define PCI_BIOS_PRESENT 0xB101
+#define FIND_PCI_DEVICE 0xB102
+#define FIND_PCI_CLASS 0xB103
+#define GENERATE_SPECIAL 0xB106
+#define READ_CONFIG_BYTE 0xB108
+#define READ_CONFIG_WORD 0xB109
+#define READ_CONFIG_DWORD 0xB10A
+#define WRITE_CONFIG_BYTE 0xB10B
+#define WRITE_CONFIG_WORD 0xB10C
+#define WRITE_CONFIG_DWORD 0xB10D
+#define GET_IRQ_ROUTING_OPT 0xB10E
+#define SET_PCI_IRQ 0xB10F
+
+/* This is the standard structure used to identify the entry point to the
+ * BIOS32 Service Directory, as documented in PCI 2.1 BIOS Specicition.
+ */
+
+typedef union {
+ struct {
+ ulong signature; /* _32_ */
+ ulong entry; /* 32 bit physical address */
+ uchar revision; /* Revision level, 0 */
+ uchar length; /* Length in paragraphs should be 01 */
+ uchar checksum; /* All bytes must add up to zero */
+ uchar reserved[5]; /* Must be zero */
+ } fields;
+ char chars[16];
+ } PCI_bios32;
+
+/* Structure for a far pointer to call the PCI BIOS services with */
+
+typedef struct {
+ ulong address;
+ ushort segment;
+ } PCIBIOS_entry;
+
+/* Macros to copy a structure that includes dwSize members */
+
+#define COPY_STRUCTURE(d,s) memcpy(d,s,MIN((s)->dwSize,(d)->dwSize))
+
+#pragma pack()
+
+/*--------------------------- Global variables ----------------------------*/
+
+static uchar *BIOSImage = NULL; /* BIOS image mapping */
+static int PCIBIOSVersion = -1;/* PCI BIOS version */
+static PCIBIOS_entry PCIEntry; /* PCI services entry point */
+static ulong PCIPhysEntry = 0; /* Physical address */
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* External assembler helper functions */
+
+uchar _ASMAPI _BIOS32_service(ulong service,ulong function,ulong *physBase,ulong *length,ulong *serviceOffset,PCIBIOS_entry entry);
+ushort _ASMAPI _PCIBIOS_isPresent(ulong i_eax,ulong *o_edx,ushort *o_ax,uchar *o_cl,PCIBIOS_entry entry);
+ulong _ASMAPI _PCIBIOS_service(ulong r_eax,ulong r_ebx,ulong r_edi,ulong r_ecx,PCIBIOS_entry entry);
+int _ASMAPI _PCIBIOS_getRouting(PCIRoutingOptionsBuffer *buf,PCIBIOS_entry entry);
+ibool _ASMAPI _PCIBIOS_setIRQ(int busDev,int intPin,int IRQ,PCIBIOS_entry entry);
+ulong _ASMAPI _PCIBIOS_specialCycle(int bus,ulong data,PCIBIOS_entry entry);
+ushort _ASMAPI _PCI_getCS(void);
+
+/****************************************************************************
+REMARKS:
+This functions returns the physical address of the PCI BIOS entry point.
+****************************************************************************/
+ulong _ASMAPI PCIBIOS_getEntry(void)
+{ return PCIPhysEntry; }
+
+/****************************************************************************
+PARAMETERS:
+hwType - Place to store the PCI hardware access mechanism flags
+lastBus - Place to store the index of the last PCI bus in the system
+
+RETURNS:
+Version number of the PCI BIOS found.
+
+REMARKS:
+This function determines if the PCI BIOS is present in the system, and if
+so returns the information returned by the PCI BIOS detect function.
+****************************************************************************/
+static int PCIBIOS_detect(
+ uchar *hwType,
+ uchar *lastBus)
+{
+ ulong signature;
+ ushort stat,version;
+
+#ifndef __16BIT__
+ PCIBIOS_entry BIOSEntry = {0};
+ uchar *BIOSEnd;
+ PCI_bios32 *BIOSDir;
+ ulong physBase,length,offset;
+
+ /* Bail if we have already detected no BIOS is present */
+ if (PCIBIOSVersion == 0)
+ return 0;
+
+ /* First scan the memory from 0xE0000 to 0xFFFFF looking for the
+ * BIOS32 service directory, so we can determine if we can call it
+ * from 32-bit protected mode.
+ */
+ if (PCIBIOSVersion == -1) {
+ PCIBIOSVersion = 0;
+ BIOSImage = PM_mapPhysicalAddr(0xE0000,BIOS_LIMIT,false);
+ if (!BIOSImage)
+ return 0;
+ BIOSEnd = BIOSImage + 0x20000;
+ for (BIOSDir = (PCI_bios32*)BIOSImage; BIOSDir < (PCI_bios32*)BIOSEnd; BIOSDir++) {
+ uchar sum;
+ int i,length;
+
+ if (BIOSDir->fields.signature != BIOS32_SIGNATURE)
+ continue;
+ length = BIOSDir->fields.length * 16;
+ if (!length)
+ continue;
+ for (sum = i = 0; i < length ; i++)
+ sum += BIOSDir->chars[i];
+ if (sum != 0)
+ continue;
+ BIOSEntry.address = (ulong)BIOSImage + (BIOSDir->fields.entry - 0xE0000);
+ BIOSEntry.segment = _PCI_getCS();
+ break;
+ }
+
+ /* If we found the BIOS32 directory, call it to get the address of the
+ * PCI services.
+ */
+ if (BIOSEntry.address == 0)
+ return 0;
+ if (_BIOS32_service(PCI_SERVICE,0,&physBase,&length,&offset,BIOSEntry) != 0)
+ return 0;
+ PCIPhysEntry = physBase + offset;
+ PCIEntry.address = (ulong)BIOSImage + (PCIPhysEntry - 0xE0000);
+ PCIEntry.segment = _PCI_getCS();
+ }
+#endif
+ /* We found the BIOS entry, so now do the version check */
+ version = _PCIBIOS_isPresent(PCI_BIOS_PRESENT,&signature,&stat,lastBus,PCIEntry);
+ if (version > 0 && ((stat >> 8) == 0) && signature == PCI_SIGNATURE) {
+ *hwType = stat & 0xFF;
+ return PCIBIOSVersion = version;
+ }
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to check against
+index - Index of the current device to check
+
+RETURNS:
+True if the device is a duplicate, false if not.
+
+REMARKS:
+This function goes through the list of all devices preceeding the newly
+found device in the info structure, and checks that the device is not a
+duplicate of a previous device. Some devices incorrectly enumerate
+themselves at different function addresses so we check here to exclude
+those cases.
+****************************************************************************/
+static ibool CheckDuplicate(
+ PCIDeviceInfo *info,
+ PCIDeviceInfo *prev)
+{
+ /* Ignore devices with a vendor ID of 0 */
+ if (info->VendorID == 0)
+ return true;
+
+ /* NOTE: We only check against the current device on
+ * the bus to ensure that we do not exclude
+ * multiple controllers of the same device ID.
+ */
+ if (info->slot.p.Bus == prev->slot.p.Bus &&
+ info->slot.p.Device == prev->slot.p.Device &&
+ info->DeviceID == prev->DeviceID)
+ return true;
+ return false;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+static int PCI_enumerateMech1(
+ PCIDeviceInfo info[])
+{
+ int bus,device,function,i,numFound = 0;
+ ulong *lp,tmp;
+ PCIslot slot = {{0,0,0,0,0,0,1}};
+ PCIDeviceInfo pci,prev = {0};
+
+ /* Try PCI access mechanism 1 */
+ PM_outpb(0xCFB,0x01);
+ tmp = PM_inpd(0xCF8);
+ PM_outpd(0xCF8,slot.i);
+ if ((PM_inpd(0xCF8) == slot.i) && (PM_inpd(0xCFC) != 0xFFFFFFFFUL)) {
+ /* PCI access mechanism 1 - the preferred mechanism */
+ for (bus = 0; bus < 8; bus++) {
+ slot.p.Bus = bus;
+ for (device = 0; device < 32; device++) {
+ slot.p.Device = device;
+ for (function = 0; function < 8; function++) {
+ slot.p.Function = function;
+ slot.p.Register = 0;
+ PM_outpd(0xCF8,slot.i);
+ if (PM_inpd(0xCFC) != 0xFFFFFFFFUL) {
+ memset(&pci,0,sizeof(pci));
+ pci.dwSize = sizeof(pci);
+ pci.mech1 = 1;
+ pci.slot = slot;
+ lp = (ulong*)&(pci.VendorID);
+ for (i = 0; i < NUM_PCI_REG; i++, lp++) {
+ slot.p.Register = i;
+ PM_outpd(0xCF8,slot.i);
+ *lp = PM_inpd(0xCFC);
+ }
+ if (!CheckDuplicate(&pci,&prev)) {
+ if (info)
+ COPY_STRUCTURE(&info[numFound],&pci);
+ ++numFound;
+ }
+ prev = pci;
+ }
+ }
+ }
+ }
+
+ /* Disable PCI config cycle on exit */
+ PM_outpd(0xCF8,0);
+ return numFound;
+ }
+ PM_outpd(0xCF8,tmp);
+
+ /* No hardware access mechanism 1 found */
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+static int PCI_enumerateMech2(
+ PCIDeviceInfo info[])
+{
+ int bus,device,function,i,numFound = 0;
+ ushort deviceIO;
+ ulong *lp;
+ PCIslot slot = {{0,0,0,0,0,0,1}};
+ PCIDeviceInfo pci,prev = {0};
+
+ /* Try PCI access mechanism 2 */
+ PM_outpb(0xCFB,0x00);
+ PM_outpb(0xCF8,0x00);
+ PM_outpb(0xCFA,0x00);
+ if (PM_inpb(0xCF8) == 0x00 && PM_inpb(0xCFB) == 0x00) {
+ /* PCI access mechanism 2 - the older mechanism for legacy busses */
+ for (bus = 0; bus < 2; bus++) {
+ slot.p.Bus = bus;
+ PM_outpb(0xCFA,(uchar)bus);
+ for (device = 0; device < 16; device++) {
+ slot.p.Device = device;
+ deviceIO = 0xC000 + (device << 8);
+ for (function = 0; function < 8; function++) {
+ slot.p.Function = function;
+ slot.p.Register = 0;
+ PM_outpb(0xCF8,(uchar)((function << 1) | 0x10));
+ if (PM_inpd(deviceIO) != 0xFFFFFFFFUL) {
+ memset(&pci,0,sizeof(pci));
+ pci.dwSize = sizeof(pci);
+ pci.mech1 = 0;
+ pci.slot = slot;
+ lp = (ulong*)&(pci.VendorID);
+ for (i = 0; i < NUM_PCI_REG; i++, lp++) {
+ slot.p.Register = i;
+ *lp = PM_inpd(deviceIO + (i << 2));
+ }
+ if (!CheckDuplicate(&pci,&prev)) {
+ if (info)
+ COPY_STRUCTURE(&info[numFound],&pci);
+ ++numFound;
+ }
+ prev = pci;
+ }
+ }
+ }
+ }
+
+ /* Disable PCI config cycle on exit */
+ PM_outpb(0xCF8,0);
+ return numFound;
+ }
+
+ /* No hardware access mechanism 2 found */
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+This functions reads a configuration dword via the PCI BIOS.
+****************************************************************************/
+static ulong PCIBIOS_readDWORD(
+ int index,
+ ulong slot)
+{
+ return (ulong)_PCIBIOS_service(READ_CONFIG_DWORD,slot >> 8,index,0,PCIEntry);
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+static int PCI_enumerateBIOS(
+ PCIDeviceInfo info[])
+{
+ uchar hwType,lastBus;
+ int bus,device,function,i,numFound = 0;
+ ulong *lp;
+ PCIslot slot = {{0,0,0,0,0,0,1}};
+ PCIDeviceInfo pci,prev = {0};
+
+ if (PCIBIOS_detect(&hwType,&lastBus)) {
+ /* PCI BIOS access - the ultimate fallback */
+ for (bus = 0; bus <= lastBus; bus++) {
+ slot.p.Bus = bus;
+ for (device = 0; device < 32; device++) {
+ slot.p.Device = device;
+ for (function = 0; function < 8; function++) {
+ slot.p.Function = function;
+ if (PCIBIOS_readDWORD(0,slot.i) != 0xFFFFFFFFUL) {
+ memset(&pci,0,sizeof(pci));
+ pci.dwSize = sizeof(pci);
+ pci.mech1 = 2;
+ pci.slot = slot;
+ lp = (ulong*)&(pci.VendorID);
+ for (i = 0; i < NUM_PCI_REG; i++, lp++)
+ *lp = PCIBIOS_readDWORD(i << 2,slot.i);
+ if (!CheckDuplicate(&pci,&prev)) {
+ if (info)
+ COPY_STRUCTURE(&info[numFound],&pci);
+ ++numFound;
+ }
+ prev = pci;
+ }
+ }
+ }
+ }
+ }
+
+ /* Return number of devices found */
+ return numFound;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+int _ASMAPI PCI_enumerate(
+ PCIDeviceInfo info[])
+{
+ int numFound;
+
+ /* First try via the direct access mechanisms which are faster if we
+ * have them (nearly always). The BIOS is used as a fallback, and for
+ * stuff we can't do directly.
+ */
+ if ((numFound = PCI_enumerateMech1(info)) == 0) {
+ if ((numFound = PCI_enumerateMech2(info)) == 0) {
+ if ((numFound = PCI_enumerateBIOS(info)) == 0)
+ return 0;
+ }
+ }
+ return numFound;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+int _ASMAPI PCI_getNumDevices(void)
+{
+ return PCI_enumerate(NULL);
+}
+
+/****************************************************************************
+PARAMETERS:
+bar - Base address to measure
+pci - PCI device to access
+
+RETURNS:
+Size of the PCI base address in bytes
+
+REMARKS:
+This function measures the size of the PCI base address register in bytes,
+by writing all F's to the register, and reading the value back. The size
+of the base address is determines by the bits that are hardwired to zero's.
+****************************************************************************/
+ulong _ASMAPI PCI_findBARSize(
+ int bar,
+ PCIDeviceInfo *pci)
+{
+ ulong base,size = 0;
+
+ base = PCI_accessReg(bar,0,PCI_READ_DWORD,pci);
+ if (base && !(base & 0x1)) {
+ /* For some strange reason some devices don't properly decode
+ * their base address registers (Intel PCI/PCI bridges!), and
+ * we read completely bogus values. We check for that here
+ * and clear out those BAR's.
+ *
+ * We check for that here because at least the low 12 bits
+ * of the address range must be zeros, since the page size
+ * on IA32 processors is always 4Kb.
+ */
+ if ((base & 0xFFF) == 0) {
+ PCI_accessReg(bar,0xFFFFFFFF,PCI_WRITE_DWORD,pci);
+ size = PCI_accessReg(bar,0,PCI_READ_DWORD,pci) & ~0xFF;
+ size = ~size+1;
+ PCI_accessReg(bar,base,PCI_WRITE_DWORD,pci);
+ }
+ }
+ pci->slot.p.Register = 0;
+ return size;
+}
+
+/****************************************************************************
+PARAMETERS:
+index - DWORD index of the register to access
+value - Value to write to the register for write access
+func - Function to implement
+
+RETURNS:
+The value read from the register for read operations
+
+REMARKS:
+The function code are defined as follows
+
+code - function
+0 - Read BYTE
+1 - Read WORD
+2 - Read DWORD
+3 - Write BYTE
+4 - Write WORD
+5 - Write DWORD
+****************************************************************************/
+ulong _ASMAPI PCI_accessReg(
+ int index,
+ ulong value,
+ int func,
+ PCIDeviceInfo *info)
+{
+ int iobase;
+
+ if (info->mech1 == 2) {
+ /* Use PCI BIOS access since we dont have direct hardware access */
+ switch (func) {
+ case PCI_READ_BYTE:
+ return (uchar)_PCIBIOS_service(READ_CONFIG_BYTE,info->slot.i >> 8,index,0,PCIEntry);
+ case PCI_READ_WORD:
+ return (ushort)_PCIBIOS_service(READ_CONFIG_WORD,info->slot.i >> 8,index,0,PCIEntry);
+ case PCI_READ_DWORD:
+ return (ulong)_PCIBIOS_service(READ_CONFIG_DWORD,info->slot.i >> 8,index,0,PCIEntry);
+ case PCI_WRITE_BYTE:
+ _PCIBIOS_service(WRITE_CONFIG_BYTE,info->slot.i >> 8,index,value,PCIEntry);
+ break;
+ case PCI_WRITE_WORD:
+ _PCIBIOS_service(WRITE_CONFIG_WORD,info->slot.i >> 8,index,value,PCIEntry);
+ break;
+ case PCI_WRITE_DWORD:
+ _PCIBIOS_service(WRITE_CONFIG_DWORD,info->slot.i >> 8,index,value,PCIEntry);
+ break;
+ }
+ }
+ else {
+ /* Use direct hardware access mechanisms */
+ if (info->mech1) {
+ /* PCI access mechanism 1 */
+ iobase = 0xCFC + (index & 3);
+ info->slot.p.Register = index >> 2;
+ PM_outpd(0xCF8,info->slot.i);
+ }
+ else {
+ /* PCI access mechanism 2 */
+ PM_outpb(0xCF8,(uchar)((info->slot.p.Function << 1) | 0x10));
+ PM_outpb(0xCFA,(uchar)info->slot.p.Bus);
+ iobase = 0xC000 + (info->slot.p.Device << 8) + index;
+ }
+ switch (func) {
+ case PCI_READ_BYTE:
+ case PCI_READ_WORD:
+ case PCI_READ_DWORD: value = PM_inpd(iobase); break;
+ case PCI_WRITE_BYTE: PM_outpb(iobase,(uchar)value); break;
+ case PCI_WRITE_WORD: PM_outpw(iobase,(ushort)value); break;
+ case PCI_WRITE_DWORD: PM_outpd(iobase,(ulong)value); break;
+ }
+ PM_outpd(0xCF8,0);
+ }
+ return value;
+}
+
+/****************************************************************************
+PARAMETERS:
+numDevices - Number of devices to query info for
+
+RETURNS:
+0 on success, -1 on error, number of devices to enumerate if numDevices = 0
+
+REMARKS:
+This function reads the PCI routing information. If you pass a value of
+0 for numDevices, this function will return with the number of devices
+needed in the routing buffer that will be filled in by the BIOS.
+****************************************************************************/
+ibool _ASMAPI PCI_getIRQRoutingOptions(
+ int numDevices,
+ PCIRouteInfo *buffer)
+{
+ PCIRoutingOptionsBuffer buf;
+ int ret;
+
+ if (PCIPhysEntry) {
+ buf.BufferSize = numDevices * sizeof(PCIRouteInfo);
+ buf.DataBuffer = buffer;
+ if ((ret = _PCIBIOS_getRouting(&buf,PCIEntry)) == 0x89)
+ return buf.BufferSize / sizeof(PCIRouteInfo);
+ if (ret != 0)
+ return -1;
+ return 0;
+ }
+
+ /* We currently only support this via the PCI BIOS functions */
+ return -1;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - PCI device information for the specified device
+intPin - Value to store in the PCI InterruptPin register
+IRQ - New ISA IRQ to map the PCI interrupt to (0-15)
+
+RETURNS:
+True on success, or false if this function failed.
+
+REMARKS:
+This function changes the PCI IRQ routing for the specified device to the
+desired PCI interrupt and the desired ISA bus compatible IRQ. This function
+may not be supported by the PCI BIOS, in which case this function will
+fail.
+****************************************************************************/
+ibool _ASMAPI PCI_setHardwareIRQ(
+ PCIDeviceInfo *info,
+ uint intPin,
+ uint IRQ)
+{
+ if (PCIPhysEntry) {
+ if (_PCIBIOS_setIRQ(info->slot.i >> 8,intPin,IRQ,PCIEntry)) {
+ info->u.type0.InterruptPin = intPin;
+ info->u.type0.InterruptLine = IRQ;
+ return true;
+ }
+ return false;
+ }
+
+ /* We currently only support this via the PCI BIOS functions */
+ return false;
+}
+
+/****************************************************************************
+PARAMETERS:
+bus - Bus number to generate the special cycle for
+specialCycleData - Data to send for the special cyle
+
+REMARKS:
+This function generates a special cycle on the specified bus using with
+the specified data.
+****************************************************************************/
+void _ASMAPI PCI_generateSpecialCyle(
+ uint bus,
+ ulong specialCycleData)
+{
+ if (PCIPhysEntry)
+ _PCIBIOS_specialCycle(bus,specialCycleData,PCIEntry);
+ /* We currently only support this via the PCI BIOS functions */
+}
+
+/****************************************************************************
+PARAMETERS:
+info - PCI device information block for device to access
+index - Index of register to start reading from
+dst - Place to store the values read from configuration space
+count - Count of bytes to read from configuration space
+
+REMARKS:
+This function is used to read a block of PCI configuration space registers
+from the configuration space into the passed in data block. This function
+will properly handle reading non-DWORD aligned data from the configuration
+space correctly.
+****************************************************************************/
+void _ASMAPI PCI_readRegBlock(
+ PCIDeviceInfo *info,
+ int index,
+ void *dst,
+ int count)
+{
+ uchar *pb;
+ ulong *pd;
+ int i;
+ int startCount = (index & 3);
+ int middleCount = (count - startCount) >> 2;
+ int endCount = count - middleCount * 4 - startCount;
+
+ for (i = 0,pb = dst; i < startCount; i++, index++) {
+ *pb++ = (uchar)PCI_accessReg(index,0,PCI_READ_BYTE,info);
+ }
+ for (i = 0,pd = (ulong*)pb; i < middleCount; i++, index += 4) {
+ *pd++ = (ulong)PCI_accessReg(index,0,PCI_READ_DWORD,info);
+ }
+ for (i = 0,pb = (uchar*)pd; i < endCount; i++, index++) {
+ *pb++ = (uchar)PCI_accessReg(index,0,PCI_READ_BYTE,info);
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+info - PCI device information block for device to access
+index - Index of register to start reading from
+dst - Place to store the values read from configuration space
+count - Count of bytes to read from configuration space
+
+REMARKS:
+This function is used to write a block of PCI configuration space registers
+to the configuration space from the passed in data block. This function
+will properly handle writing non-DWORD aligned data to the configuration
+space correctly.
+****************************************************************************/
+void _ASMAPI PCI_writeRegBlock(
+ PCIDeviceInfo *info,
+ int index,
+ void *src,
+ int count)
+{
+ uchar *pb;
+ ulong *pd;
+ int i;
+ int startCount = (index & 3);
+ int middleCount = (count - startCount) >> 2;
+ int endCount = count - middleCount * 4 - startCount;
+
+ for (i = 0,pb = src; i < startCount; i++, index++) {
+ PCI_accessReg(index,*pb++,PCI_WRITE_BYTE,info);
+ }
+ for (i = 0,pd = (ulong*)pb; i < middleCount; i++, index += 4) {
+ PCI_accessReg(index,*pd++,PCI_WRITE_DWORD,info);
+ }
+ for (i = 0,pb = (uchar*)pd; i < endCount; i++, index++) {
+ PCI_accessReg(index,*pb++,PCI_WRITE_BYTE,info);
+ }
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/unixio.c b/board/MAI/bios_emulator/scitech/src/pm/common/unixio.c
new file mode 100644
index 0000000000..04aa47002b
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/unixio.c
@@ -0,0 +1,306 @@
+/****************************************************************************
+*
+* 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.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+*
+* Description: Module containing Unix I/O functions.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* {secret} */
+typedef struct {
+ DIR *d;
+ char path[PM_MAX_PATH];
+ char mask[PM_MAX_PATH];
+ } PM_findHandle;
+
+/****************************************************************************
+REMARKS:
+Internal function to convert the find data to the generic interface.
+****************************************************************************/
+static void convertFindData(
+ PM_findData *findData,
+ struct dirent *blk,
+ const char *path)
+{
+ ulong dwSize = findData->dwSize;
+ struct stat st;
+ char filename[PM_MAX_PATH];
+
+ memset(findData,0,findData->dwSize);
+ findData->dwSize = dwSize;
+ strcpy(filename,path);
+ PM_backslash(filename);
+ strcat(filename,blk->d_name);
+ stat(filename,&st);
+ if (!(st.st_mode & S_IWRITE))
+ findData->attrib |= PM_FILE_READONLY;
+ if (st.st_mode & S_IFDIR)
+ findData->attrib |= PM_FILE_DIRECTORY;
+ findData->sizeLo = st.st_size;
+ findData->sizeHi = 0;
+ strncpy(findData->name,blk->d_name,PM_MAX_PATH);
+ findData->name[PM_MAX_PATH-1] = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Determines if a file name matches the passed in pattern.
+****************************************************************************/
+static ibool filematch(
+ char *pattern,
+ char *dirpath,
+ struct dirent *dire)
+{
+ struct stat st;
+ int i = 0,j = 0,lastchar = '\0';
+ char fullpath[PM_MAX_PATH];
+
+ strcpy(fullpath,dirpath);
+ PM_backslash(fullpath);
+ strcat(fullpath, dire->d_name);
+ if (stat(fullpath, &st) != 0)
+ return false;
+ for (; i < (int)strlen(dire->d_name) && j < (int)strlen(pattern); i++, j++) {
+ if (pattern[j] == '*' && lastchar != '\\') {
+ if (pattern[j+1] == '\0')
+ return true;
+ while (dire->d_name[i++] != pattern[j+1]) {
+ if (dire->d_name[i] == '\0')
+ return false;
+ }
+ i -= 2;
+ }
+ else if (dire->d_name[i] != pattern[j] &&
+ !(pattern[j] == '?' && lastchar != '\\'))
+ return false;
+ lastchar = pattern[i];
+ }
+ if (j == (int)strlen(pattern) && i == (int)strlen(dire->d_name))
+ return true;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void * PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ PM_findHandle *d;
+ struct dirent *dire;
+ char name[PM_MAX_PATH];
+ char ext[PM_MAX_PATH];
+
+ if ((d = PM_malloc(sizeof(*d))) == NULL)
+ return PM_FILE_INVALID;
+ PM_splitpath(filename,NULL,d->path,name,ext);
+ strcpy(d->mask,name);
+ strcat(d->mask,ext);
+ if (strlen(d->path) == 0)
+ strcpy(d->path, ".");
+ if (d->path[strlen(d->path)-1] == '/')
+ d->path[strlen(d->path)-1] = 0;
+ if ((d->d = opendir(d->path)) != NULL) {
+ while ((dire = readdir(d->d)) != NULL) {
+ if (filematch(d->mask,d->path,dire)) {
+ convertFindData(findData,dire,d->path);
+ return d;
+ }
+ }
+ closedir(d->d);
+ }
+ PM_free(d);
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ PM_findHandle *d = handle;
+ struct dirent *dire;
+
+ while ((dire = readdir(d->d)) != NULL) {
+ if (filematch(d->mask,d->path,dire)) {
+ convertFindData(findData,dire,d->path);
+ return true;
+ }
+ }
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ PM_findHandle *d = handle;
+
+ closedir(d->d);
+ free(d);
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ if (drive == 3)
+ return true;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ (void)drive;
+ getcwd(dir,len);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ struct stat st;
+ mode_t mode;
+
+ stat(filename,&st);
+ mode = st.st_mode;
+ if (attrib & PM_FILE_READONLY)
+ mode &= ~S_IWRITE;
+ else
+ mode |= S_IWRITE;
+ chmod(filename,mode);
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file attributes for a specific file.
+****************************************************************************/
+uint PMAPI PM_getFileAttr(
+ const char *filename)
+{
+ struct stat st;
+
+ stat(filename,&st);
+ if (st.st_mode & S_IWRITE)
+ return 0;
+ return PM_FILE_READONLY;
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+ return mkdir(filename,0x1FF) == 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ return rmdir(filename) == 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_getFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ PM_fatalError("PM_getFileTime not implemented yet!");
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_setFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ PM_fatalError("PM_setFileTime not implemented yet!");
+ return false;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/vgastate.c b/board/MAI/bios_emulator/scitech/src/pm/common/vgastate.c
new file mode 100644
index 0000000000..3be14e81eb
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/vgastate.c
@@ -0,0 +1,377 @@
+/****************************************************************************
+*
+* 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.
+*
+* ========================================================================
+*
+* Portions copyright (C) Josh Vanderhoof
+*
+* Language: ANSI C
+* Environment: Any
+*
+* Description: Functions to save and restore the VGA hardware state.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#if defined(__WIN32_VXD__) || defined(__NT_DRIVER__)
+#include "sdd/sddhelp.h"
+#else
+#include <string.h>
+#endif
+
+/*--------------------------- Global variables ----------------------------*/
+
+/* VGA index register ports */
+#define CRT_I 0x3D4 /* CRT Controller Index */
+#define ATT_IW 0x3C0 /* Attribute Controller Index & Data */
+#define GRA_I 0x3CE /* Graphics Controller Index */
+#define SEQ_I 0x3C4 /* Sequencer Index */
+
+/* VGA data register ports */
+#define CRT_D 0x3D5 /* CRT Controller Data Register */
+#define ATT_R 0x3C1 /* Attribute Controller Data Read Register */
+#define GRA_D 0x3CF /* Graphics Controller Data Register */
+#define SEQ_D 0x3C5 /* Sequencer Data Register */
+#define MIS_R 0x3CC /* Misc Output Read Register */
+#define MIS_W 0x3C2 /* Misc Output Write Register */
+#define IS1_R 0x3DA /* Input Status Register 1 */
+#define PEL_IW 0x3C8 /* PEL Write Index */
+#define PEL_IR 0x3C7 /* PEL Read Index */
+#define PEL_D 0x3C9 /* PEL Data Register */
+
+/* standard VGA indexes max counts */
+#define CRT_C 24 /* 24 CRT Controller Registers */
+#define ATT_C 21 /* 21 Attribute Controller Registers */
+#define GRA_C 9 /* 9 Graphics Controller Registers */
+#define SEQ_C 5 /* 5 Sequencer Registers */
+#define MIS_C 1 /* 1 Misc Output Register */
+#define PAL_C 768 /* 768 Palette Registers */
+#define FONT_C 8192 /* Total size of character generator RAM */
+
+/* VGA registers saving indexes */
+#define CRT 0 /* CRT Controller Registers start */
+#define ATT (CRT+CRT_C) /* Attribute Controller Registers start */
+#define GRA (ATT+ATT_C) /* Graphics Controller Registers start */
+#define SEQ (GRA+GRA_C) /* Sequencer Registers */
+#define MIS (SEQ+SEQ_C) /* General Registers */
+#define PAL (MIS+MIS_C) /* VGA Palette Registers */
+#define FONT (PAL+PAL_C) /* VGA font data */
+
+/* Macros for port I/O with arguments reversed */
+
+#define _port_out(v,p) PM_outpb(p,(uchar)(v))
+#define _port_in(p) PM_inpb(p)
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Returns the size of the VGA state buffer.
+****************************************************************************/
+int PMAPI PM_getVGAStateSize(void)
+{
+ return CRT_C + ATT_C + GRA_C + SEQ_C + MIS_C + PAL_C + FONT_C;
+}
+
+/****************************************************************************
+REMARKS:
+Delay for a short period of time.
+****************************************************************************/
+static void vga_delay(void)
+{
+ int i;
+
+ /* For the loop here we program the POST register. The length of this
+ * delay is dependant only on ISA bus speed, but it is enough for
+ * what we need.
+ */
+ for (i = 0; i <= 10; i++)
+ PM_outpb(0x80, 0);
+}
+
+/****************************************************************************
+PARAMETERS:
+port - I/O port to read value from
+index - Port index to read
+
+RETURNS:
+Byte read from 'port' register 'index'.
+****************************************************************************/
+static ushort vga_rdinx(
+ ushort port,
+ ushort index)
+{
+ PM_outpb(port,(uchar)index);
+ return PM_inpb(port+1);
+}
+
+/****************************************************************************
+PARAMETERS:
+port - I/O port to write to
+index - Port index to write
+value - Byte to write to port
+
+REMARKS:
+Writes a byte value to the 'port' register 'index'.
+****************************************************************************/
+static void vga_wrinx(
+ ushort port,
+ ushort index,
+ ushort value)
+{
+ PM_outpb(port,(uchar)index);
+ PM_outpb(port+1,(uchar)value);
+}
+
+/****************************************************************************
+REMARKS:
+Save the color palette values
+****************************************************************************/
+static void vga_savepalette(
+ uchar *pal)
+{
+ int i;
+
+ _port_out(0, PEL_IR);
+ for (i = 0; i < 768; i++) {
+ vga_delay();
+ *pal++ = _port_in(PEL_D);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Restore the color palette values
+****************************************************************************/
+static void vga_restorepalette(
+ const uchar *pal)
+{
+ int i;
+
+ /* restore saved palette */
+ _port_out(0, PEL_IW);
+ for (i = 0; i < 768; i++) {
+ vga_delay();
+ _port_out(*pal++, PEL_D);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Read the font data from the VGA character generator RAM
+****************************************************************************/
+static void vga_saveFont(
+ uchar *data)
+{
+ uchar *A0000Ptr = PM_getA0000Pointer();
+ uchar save[7];
+
+ /* Enable access to character generator RAM */
+ save[0] = (uchar)vga_rdinx(SEQ_I,0x00);
+ save[1] = (uchar)vga_rdinx(SEQ_I,0x02);
+ save[2] = (uchar)vga_rdinx(SEQ_I,0x04);
+ save[3] = (uchar)vga_rdinx(SEQ_I,0x00);
+ save[4] = (uchar)vga_rdinx(GRA_I,0x04);
+ save[5] = (uchar)vga_rdinx(GRA_I,0x05);
+ save[6] = (uchar)vga_rdinx(GRA_I,0x06);
+ vga_wrinx(SEQ_I,0x00,0x01);
+ vga_wrinx(SEQ_I,0x02,0x04);
+ vga_wrinx(SEQ_I,0x04,0x07);
+ vga_wrinx(SEQ_I,0x00,0x03);
+ vga_wrinx(GRA_I,0x04,0x02);
+ vga_wrinx(GRA_I,0x05,0x00);
+ vga_wrinx(GRA_I,0x06,0x00);
+
+ /* Copy character generator RAM */
+ memcpy(data,A0000Ptr,FONT_C);
+
+ /* Restore VGA state */
+ vga_wrinx(SEQ_I,0x00,save[0]);
+ vga_wrinx(SEQ_I,0x02,save[1]);
+ vga_wrinx(SEQ_I,0x04,save[2]);
+ vga_wrinx(SEQ_I,0x00,save[3]);
+ vga_wrinx(GRA_I,0x04,save[4]);
+ vga_wrinx(GRA_I,0x05,save[5]);
+ vga_wrinx(GRA_I,0x06,save[6]);
+}
+
+/****************************************************************************
+REMARKS:
+Downloads the font data to the VGA character generator RAM
+****************************************************************************/
+static void vga_restoreFont(
+ const uchar *data)
+{
+ uchar *A0000Ptr = PM_getA0000Pointer();
+
+ /* Enable access to character generator RAM */
+ vga_wrinx(SEQ_I,0x00,0x01);
+ vga_wrinx(SEQ_I,0x02,0x04);
+ vga_wrinx(SEQ_I,0x04,0x07);
+ vga_wrinx(SEQ_I,0x00,0x03);
+ vga_wrinx(GRA_I,0x04,0x02);
+ vga_wrinx(GRA_I,0x05,0x00);
+ vga_wrinx(GRA_I,0x06,0x00);
+
+ /* Copy font back to character generator RAM */
+ memcpy(A0000Ptr,data,FONT_C);
+}
+
+/****************************************************************************
+REMARKS:
+Save the state of all VGA compatible registers
+****************************************************************************/
+void PMAPI PM_saveVGAState(
+ void *stateBuf)
+{
+ uchar *regs = stateBuf;
+ int i;
+
+ /* Save state of VGA registers */
+ for (i = 0; i < CRT_C; i++) {
+ _port_out(i, CRT_I);
+ regs[CRT + i] = _port_in(CRT_D);
+ }
+ for (i = 0; i < ATT_C; i++) {
+ _port_in(IS1_R);
+ vga_delay();
+ _port_out(i, ATT_IW);
+ vga_delay();
+ regs[ATT + i] = _port_in(ATT_R);
+ vga_delay();
+ }
+ for (i = 0; i < GRA_C; i++) {
+ _port_out(i, GRA_I);
+ regs[GRA + i] = _port_in(GRA_D);
+ }
+ for (i = 0; i < SEQ_C; i++) {
+ _port_out(i, SEQ_I);
+ regs[SEQ + i] = _port_in(SEQ_D);
+ }
+ regs[MIS] = _port_in(MIS_R);
+
+ /* Save the VGA palette values */
+ vga_savepalette(&regs[PAL]);
+
+ /* Save the VGA character generator RAM */
+ vga_saveFont(&regs[FONT]);
+
+ /* Turn the VGA display back on */
+ PM_vgaUnblankDisplay();
+}
+
+/****************************************************************************
+REMARKS:
+Retore the state of all VGA compatible registers
+****************************************************************************/
+void PMAPI PM_restoreVGAState(
+ const void *stateBuf)
+{
+ const uchar *regs = stateBuf;
+ int i;
+
+ /* Blank the display before we start the restore */
+ PM_vgaBlankDisplay();
+
+ /* Restore the VGA character generator RAM */
+ vga_restoreFont(&regs[FONT]);
+
+ /* Restore the VGA palette values */
+ vga_restorepalette(&regs[PAL]);
+
+ /* Restore the state of the VGA compatible registers */
+ _port_out(regs[MIS], MIS_W);
+
+ /* Delay to allow clock change to settle */
+ for (i = 0; i < 10; i++)
+ vga_delay();
+
+ /* Synchronous reset on */
+ _port_out(0x00,SEQ_I);
+ _port_out(0x01,SEQ_D);
+
+ /* Write seqeuencer registers */
+ _port_out(1, SEQ_I);
+ _port_out(regs[SEQ + 1] | 0x20, SEQ_D);
+ for (i = 2; i < SEQ_C; i++) {
+ _port_out(i, SEQ_I);
+ _port_out(regs[SEQ + i], SEQ_D);
+ }
+
+ /* Synchronous reset off */
+ _port_out(0x00,SEQ_I);
+ _port_out(0x03,SEQ_D);
+
+ /* Deprotect CRT registers 0-7 and write CRTC */
+ _port_out(0x11, CRT_I);
+ _port_out(_port_in(CRT_D) & 0x7F, CRT_D);
+ for (i = 0; i < CRT_C; i++) {
+ _port_out(i, CRT_I);
+ _port_out(regs[CRT + i], CRT_D);
+ }
+ for (i = 0; i < GRA_C; i++) {
+ _port_out(i, GRA_I);
+ _port_out(regs[GRA + i], GRA_D);
+ }
+ for (i = 0; i < ATT_C; i++) {
+ _port_in(IS1_R); /* reset flip-flop */
+ vga_delay();
+ _port_out(i, ATT_IW);
+ vga_delay();
+ _port_out(regs[ATT + i], ATT_IW);
+ vga_delay();
+ }
+
+ /* Ensure the VGA screen is turned on */
+ PM_vgaUnblankDisplay();
+}
+
+/****************************************************************************
+REMARKS:
+Disables the VGA display for screen output making it blank.
+****************************************************************************/
+void PMAPI PM_vgaBlankDisplay(void)
+{
+ /* Turn screen off */
+ _port_out(0x01, SEQ_I);
+ _port_out(_port_in(SEQ_D) | 0x20, SEQ_D);
+
+ /* Disable video output */
+ _port_in(IS1_R);
+ vga_delay();
+ _port_out(0x00, ATT_IW);
+}
+
+/****************************************************************************
+REMARKS:
+Enables the VGA display for screen output.
+****************************************************************************/
+void PMAPI PM_vgaUnblankDisplay(void)
+{
+ /* Turn screen back on */
+ _port_out(0x01, SEQ_I);
+ _port_out(_port_in(SEQ_D) & 0xDF, SEQ_D);
+
+ /* Enable video output */
+ _port_in(IS1_R);
+ vga_delay();
+ _port_out(0x20, ATT_IW);
+}
OpenPOWER on IntegriCloud