2025-04-27 07:49:33 -04:00

500 lines
10 KiB
NASM

;*******************************************************************************
;
; Copyright (c) 1996-1998, Cirrus Logic, Inc.
; All Rights Reserved.
;
; FILE: $Workfile: CfgLgMem.asm $
;
; REVISION HISTORY: $Log: //uinac/Log/Log/Laguna/NT35/Miniport/CL546x/i386/CfgLgMem.asm $
;
; Rev 1.0 Jan 22 1998 16:26:58 frido
; Initial revision.
;
;*******************************************************************************
.586p
.MODEL FLAT, STDCALL
.NOLIST
include i386\CfgLgMem.inc
if 0 ; this is for the buggy build.exe
#include "i386\CfgLgMem.inc"
endif
.LIST
.CODE
GetuPVersionInfo PROTO STDCALL
PreMTRRChange PROTO STDCALL
PostMTRRChange PROTO STDCALL,
dwCR4 :DWORD
SetMemType PROTO STDCALL,
dwPhysAddr :DWORD,
dwSize :DWORD,
dwMemType :DWORD,
pMTRRReg :DWORD
ConfigureLagunaMemory PROTO STDCALL,
dwPhysFB :DWORD,
dwFBSize :DWORD
ReleaseMTRRs PROTO STDCALL,
dwFBMTRRReg :DWORD
;****************************************************************************
;*
;* FUNCTION: GetuPVersionInfo
;*
;* DESCRIPTION: Determines cpu, returns family identification in edx:eax
;* where possible.
;*
;* Based on sample code from Intel App Note AP-485
;* "Intel Processor Identification with the CPUID Instruction"
;*
;****************************************************************************
GetuPVersionInfo PROC
LOCAL highestVal :DWORD,
VersionInfo :QWORD
pushfd
pushad
pushfd ;transfer eflags to eax
pop eax
mov ecx, eax ;save copy of eflags
; Test for 386.
xor eax, FLAGS_AC_BIT ;toggle AC bit
push eax ;transfer eax back to eflags
popfd
pushfd ;transfer eflags back to eax
pop eax
; If AC bit did not stay put, then its a 386.
xor eax, ecx
jnz check_486
mov DWORD PTR [VersionInfo][0], FAMILY_386
mov DWORD PTR [VersionInfo][4], 0
jmp GVIdone
check_486:
mov eax, ecx ;get another copy of eflags
xor eax, FLAGS_ID_BIT ;toggle ID bit
push eax ;transfer eax back to eflags
popfd
pushfd ;transfer eflags back to eax
pop eax
; If ID bit did not stay put, the CPUID instruction is not supported.
; If CPUID is not supported, it must be a 486 if we got to here.
xor eax, ecx
jnz has_cpuid
mov DWORD PTR [VersionInfo][0], FAMILY_486
mov DWORD PTR [VersionInfo][4], 0
jmp GVIdone
has_cpuid:
xor eax, eax ;call cpuid with 0 in eax to get
cpuid ; vendor id string and highest
; value of eax recognized
mov [highestVal], eax ;save highest value
cmp ebx, 'uneG' ;ebx,edx,ecx should have
jne notIntel ; 'GenuineIntel'
cmp edx, 'Ieni'
jne notIntel
cmp ecx, 'letn'
je isIntel
notIntel:
mov DWORD PTR [VersionInfo][0], 0
mov DWORD PTR [VersionInfo][4], 0
jmp GVIdone
isIntel:
mov eax, 1
cmp eax, [highestVal]
jle hasSig
mov DWORD PTR [VersionInfo][0], 0
mov DWORD PTR [VersionInfo][4], 0
jmp GVIdone
hasSig:
cpuid
mov DWORD PTR [VersionInfo][0], eax
mov DWORD PTR [VersionInfo][4], edx
GVIdone:
popad
popfd
mov eax, DWORD PTR [VersionInfo][0]
mov edx, DWORD PTR [VersionInfo][4]
ret
GetuPVersionInfo ENDP
;****************************************************************************
;*
;* FUNCTION: SetMemType
;*
;* DESCRIPTION: Sets a MTRR for the physical address range specified to the
;* memory type specified. Only supports variable range MTRR's.
;*
;* Based on the MEMTYPESET pseudo code from chapter 11 of the
;* "Pentium Pro Family Developer's Manual Volume 3: Operating
;* System Writer's Guide".
;*
;****************************************************************************
SetMemType PROC \
USES ebx esi edi,
dwPhysAddr :DWORD,
dwSize :DWORD,
dwMemType :DWORD,
pMTRRReg :DWORD
LOCAL dwMTRRRegCnt :DWORD,
dwMaxPhysAddr :DWORD,
dwCR4 :DWORD
; Check for valid memory type.
mov ebx, [dwMemType]
cmp ebx, WRITE_COMBINING
jbe SMTTypeOk
cmp ebx, WRITE_PROTECTED
ja SMTErrorInvalidParam
cmp ebx, WRITE_THROUGH
jb SMTErrorInvalidParam
SMTTypeOk:
; Check if cpu supports MTRR's.
INVOKE GetuPVersionInfo
test edx, FEATURE_MTRR
jz SMTErrorNotSupported
mov ecx, MSR_MTRRcapsReg
rdmsr
; If memory type is WC, check if CPU supports WC.
cmp ebx, WRITE_COMBINING
jne SMTNotWC
test eax, MTRRcap_WC_BIT
jz SMTErrorNotSupported
SMTNotWC:
; Cave count of variable MTRR's available.
and eax, MTRRcap_VCNT_MASK
mov [dwMTRRRegCnt], eax
; If count is zero then fail.
or eax, eax
jz SMTErrorNotSupported
; Check size is not zero and is multiple of 4kB.
mov ecx, [dwSize]
or ecx, ecx
jz SMTErrorInvalidParam
test ecx, 00000FFFh
jnz SMTErrorInvalidParam
; Check physAddr is on page (4kB) boundary.
mov eax, [dwPhysAddr]
test eax, 00000FFFh
jnz SMTErrorInvalidParam
; Check physAddr + size <= 4GB
add eax, ecx
jb SMTErrorInvalidParam
mov [dwMaxPhysAddr], eax ;save this for later
; Check power of 2 requirement. This cheats, since I know the size will
; be 2, 4, 6 or 8 MB.
dec ecx
and ecx, [dwPhysAddr]
jnz SMTErrorInvalidParam
; Loop over MTRR's to see if this memory range overlaps with a memory
; range already specified by another MTRR.
mov ebx, [dwMTRRRegCnt]
mov ecx, [MSR_MTRRphysBase0Reg]
SMTMTRRLoop1:
; Read the physBase reg.
rdmsr
inc ecx
mov edi, edx ;physBase is in edi:esi
mov esi, eax
; Read the physMask reg.
rdmsr ;physMask is in edx:eax
test eax, MTRRphysMask_V_BIT
jz SMTMTRRNextPair
; This MTRR is being used so check for overlap between it's memory range\
; and the mem range we want to set.
; Get base physical addr of this MTRR.
and esi, MTRRphysBase_PHYS_BASE_MASK_LO
cmp esi, [dwMaxPhysAddr]
ja SMTMTRRNextPair
; Convert mask to a size. This probably doesn't always work.
and eax, MTRRphysMask_PHYS_MASK_MASK_LO
not eax
inc eax
; Find end phys addr of this MTRR.
add esi, eax
cmp esi, [dwPhysAddr]
jb SMTMTRRNextPair
; Hell, there's an overlap, so fail for now.
jmp SMTErrorAlreadyAssigned
SMTMTRRNextPair:
inc ecx
dec ebx
jnz SMTMTRRLoop1
; Look for first available MTRR.
mov ebx, [dwMTRRRegCnt]
mov ecx, MSR_MTRRphysMask0Reg
SMTMTRRLoop2:
; Read physMask reg & check V bit.
rdmsr
test eax, MTRRphysMask_V_BIT
jz SMTFoundAvailMTRR
add ecx, 2
dec ebx
jnz SMTMTRRLoop2
; If we get here then all the MTRR's are already in use so we must fail
; the call.
jmp SMTErrorAccessDenied
SMTFoundAvailMTRR:
dec ecx ;ecx contains physBase MSR reg number
mov eax, [pMTRRReg]
mov [eax], ecx ;save MTRR reg we're going to use
; Disable
INVOKE PreMTRRChange
mov [dwCR4], eax
; Update the MTRR. Set the physBase reg.
mov eax, [dwPhysAddr]
mov ecx, [dwMemType]
and eax, MTRRphysBase_PHYS_BASE_MASK_LO
and ecx, MTRRphysBase_TYPE_MASK
or eax, ecx
xor edx, edx
mov ecx, [pMTRRReg]
mov ecx, [ecx]
wrmsr
; Set the physMask reg.
mov eax, [dwSize]
dec eax
not eax
and eax, MTRRphysMask_PHYS_MASK_MASK_LO
or eax, MTRRphysMask_V_BIT
inc ecx
xor edx, edx
or edx, MTRRphysMask_PHYS_MASK_MASK_HI
wrmsr
; Enable.
INVOKE PostMTRRChange, [dwCR4]
SMTDone:
mov eax, mVDD_SUCCESS
SMTRet:
ret
SMTErrorInvalidParam:
mov eax, mVDDERR_INVALID_PARAMETER
jmp SMTRet
SMTErrorNotSupported:
mov eax, mVDDERR_NOT_SUPPORTED
jmp SMTRet
SMTErrorAlreadyAssigned:
mov eax, mVDDERR_ALREADY_ASSIGNED
jmp SMTRet
SMTErrorAccessDenied:
mov eax, mVDDERR_ACCESS_DENIED
jmp SMTRet
SetMemType ENDP
;****************************************************************************
;*
;* FUNCTION: PreMTRRChange
;*
;* DESCRIPTION:
;*
;****************************************************************************
PreMTRRChange PROC
LOCAL dwCR4 :DWORD
; Disable interrupts.
cli
; Save CR4.
mov eax, cr4
mov [dwCR4], eax
; Disable caching.
mov eax, cr0
or eax, CR0_CD_BIT ;set CD bit in CR0
and eax, NOT CR0_NW_BIT ;clear NW bit in CR0
mov cr0, eax
; Flush the caches.
wbinvd
; Flush the TLB's.
mov eax, cr3
mov cr3, eax
; Disable MTRR's.
mov ecx, MSR_MTRRdefTypeReg
rdmsr
and eax, NOT MSR_MTRREnable
wrmsr
; Return the saved CR4 value.
mov eax, [dwCR4]
ret
PreMTRRChange ENDP
;****************************************************************************
;*
;* FUNCTION: PostMTRRChange
;*
;* DESCRIPTION:
;*
;****************************************************************************
PostMTRRChange PROC,
dwCR4 :DWORD
; Flush caches.
wbinvd
; Flush TLB's.
mov eax, cr3
mov cr3, eax
; Enable MTRR's
mov ecx, MSR_MTRRdefTypeReg
rdmsr
or eax, MSR_MTRREnable
wrmsr
; Enable caches.
mov eax, cr0
and eax, NOT (CR0_CD_BIT OR CR0_NW_BIT)
mov cr0, eax
; Restore cr4.
mov eax, [dwCR4]
mov cr4, eax
; Enable interrupts.
sti
ret
PostMTRRChange ENDP
;****************************************************************************
;*
;* FUNCTION: ConfigureLagunaMemory
;*
;* DESCRIPTION: Set physical address of frame buffer to write combined caching.
;* Only supports CPU's with MTRR's.
;*
;****************************************************************************
ConfigureLagunaMemory PROC,
dwPhysFB :DWORD,
dwFBSize :DWORD
LOCAL dwFBMTRRReg :DWORD
; Initialize dwFBMTRRReg.
mov [dwFBMTRRReg], 0
; Set frame buffer to write-combining memory type assigned to a dwFBSize
; block of memory starting at the physical address of the frame buffer.
mov eax, [dwPhysFB]
mov ecx, [dwFBSize]
lea edx, [dwFBMTRRReg]
INVOKE SetMemType, eax, ecx, WRITE_COMBINING, edx
mov eax, [dwFBMTRRReg]
ret
ConfigureLagunaMemory ENDP
;****************************************************************************
;*
;* FUNCTION: ReleaseFBMTRR
;*
;* DESCRIPTION: Clears the MTRR used for the frame buffer on system
;* exit
;*
;****************************************************************************
ReleaseMTRRs PROC,
dwFBMTRRReg :DWORD
LOCAL dwCR4 :DWORD
; See if we have a valid MTRR register.
mov eax, [dwFBMTRRReg]
cmp eax, MSR_MTRRphysBase0Reg
jb RMFBDone
cmp eax, MSR_MTRRphysBase7Reg
ja RMFBDone
; Disable.
INVOKE PreMTRRChange
mov [dwCR4], eax
; Update the MTRR. Set the physBase reg.
xor eax, eax
xor edx, edx
mov ecx, [dwFBMTRRReg]
wrmsr
; Set the physMask reg.
inc ecx
wrmsr
; Enable.
INVOKE PostMTRRChange, [dwCR4]
RMFBDone:
ret
ReleaseMTRRs ENDP
END