📄 memory.c
字号:
//------------------------------------------------------------------------------
static BOOL MTRRSetMemoryAttributes (
LPVOID pVirtAddr, // Virtual address of region
LPVOID pPhysAddrShifted,// PhysicalAddress >> 8 (to support up to 40 bit address)
DWORD cbSize, // Size of the region
DWORD dwAttributes // attributes to be set
)
{
// try MTRR if we physical address is know and MTRR is available
if (g_nMtrrCnt && (PHYSICAL_ADDRESS_UNKNOWN != pPhysAddrShifted)) {
// MTRR supproted
LARGE_INTEGER liPhysMask;
LARGE_INTEGER liPhysBase;
DWORD cbOrigSize = cbSize; // save the original size since we need to do it in 2-passes
DWORD cbAlignedSize, dwAlignedBase;
int nRegNeeded = 0, n;
liPhysBase.QuadPart = ((ULONGLONG) pPhysAddrShifted) << 8; // real physical address
// first: calculate number of register pair needed
// count MTRR registers needed
for ( ; cbSize; cbSize -= cbAlignedSize, liPhysBase.QuadPart += cbAlignedSize) {
cbAlignedSize = MSB(cbSize); // maximun alignment that can be satisfied
if (liPhysBase.LowPart) {
dwAlignedBase = LSB (liPhysBase.LowPart); // least alignment required for base
if (cbAlignedSize > dwAlignedBase) {
cbAlignedSize = dwAlignedBase;
}
}
n = CheckExistingMTRR (&liPhysBase, cbAlignedSize);
if (MTRR_OVERLAPPED == n) {
// do not support overpped with existing ranges
DEBUGMSG (1, (L"OEMSetMemoryAttributes: MTRR existing Range overallped with the new request\r\n"));
return FALSE;
}
nRegNeeded += n; // note: MTRR_ALREADY_EXIST == 0 and MTRR_NOT_EXIST == 1, so we can use this math
}
DEBUGMSG (1, (L"OEMSetMemoryAttributes: nRegNeeded = %d\r\n", nRegNeeded));
// do we have enough registers left?
if (g_nMtrrInuse + nRegNeeded > g_nMtrrCnt) {
// running out of MTRR registers
DEBUGMSG (1, (L"OEMSetMemoryAttributes: Run out of MTRR registers\r\n"));
return FALSE;
}
if (!nRegNeeded) {
// no register needed, the range already exist with Write-Combine
return TRUE;
}
// registers available, start allocating
liPhysBase.QuadPart = ((ULONGLONG) pPhysAddrShifted) << 8; // real physical address
liPhysMask.HighPart = 0xF; // size can never be > 4G, thus the high part of mask shold always be 0xf
// update MTRR registers
for (n = 0, cbSize = cbOrigSize; cbSize; cbSize -= cbAlignedSize, liPhysBase.QuadPart += cbAlignedSize) {
cbAlignedSize = MSB(cbSize); // maximun alignment that can be satisfied
if (liPhysBase.LowPart) {
dwAlignedBase = LSB (liPhysBase.LowPart); // least alignment required for base
if (cbAlignedSize > dwAlignedBase) {
cbAlignedSize = dwAlignedBase;
}
}
if (MTRR_ALREADY_EXIST != CheckExistingMTRR (&liPhysBase, cbAlignedSize)) {
// find a free MTRR register
do {
DWORD dummy, dwPhysMask;
NKrdmsr (MSRAddr_MTRRphysMask0 + 2*n, &dummy, &dwPhysMask);
if (!(MTRRphysMask_ValidMask & dwPhysMask)) {
// found
break;
}
n ++;
} while (n < g_nMtrrCnt);
DEBUGCHK (n < g_nMtrrCnt);
liPhysMask.LowPart = (0-cbAlignedSize) | MTRRphysMask_ValidMask;
WriteMtrrRegPair (n ++, &liPhysBase, &liPhysMask);
}
}
g_nMtrrInuse += nRegNeeded;
return TRUE;
}
return FALSE;
}
//------------------------------------------------------------------------------
//
// OEMSetMemoryAttributes
//
// OEM function to change memory attributes that isn't supported by kernel.
// Current implementaion only supports PAGE_WRITECOMBINE.
//
// This function first try to use PAT, and then try MTRR if PAT isn't available.
//
//------------------------------------------------------------------------------
static BOOL OEMSetMemoryAttributes (
LPVOID pVirtAddr, // Virtual address of region
LPVOID pPhysAddrShifted,// PhysicalAddress >> 8 (to support up to 40 bit address)
DWORD cbSize, // Size of the region
DWORD dwAttributes // attributes to be set
)
{
if (PAGE_WRITECOMBINE ^ dwAttributes) {
DEBUGMSG (1, (L"OEMSetMemoryAttributes: Only PAGE_WRITECOMBINE is supported\r\n"));
return FALSE;
}
// I decided to try MTRR first since MTRR show better perf improvement on my CEPC (64M vs. 48M).
// Depending on platform, you might want to reverse the order if PAT has a better perf improvement.
return MTRRSetMemoryAttributes (pVirtAddr, pPhysAddrShifted, cbSize, dwAttributes)
|| PATSetMemoryAttributes (pVirtAddr, pPhysAddrShifted, cbSize, dwAttributes);
}
//------------------------------------------------------------------------------
//
// InitializePATAndMTRR
//
// Initialize memory type settings in the PAT (page attribute table). The PAT
// is a single 64-bit register which is a table of memory types. Page table
// entries index into the PAT via three bits: PCD, PWT, and PATi. Each page
// uses the memory type stored in the PAT in that location. By default the
// first four entries in the PAT (PATi=0) are initialized by the CPU on reboot
// to the legacy values that are implied by PCD and PWT for backward-
// compatibility. The remaining four PAT entries (PATi=1) may be programmed
// to any type desired.
//
// In the i486 OAL we program the first upper PAT entry (PATi=1, PCD=0, PWT=0)
// to be write-combined. The remaining three upper PAT entries are currently
// left as their default values and unused in the page table.
//
// The PAT index is set on page table entries by OEMVirtualProtect, based on
// the PAGE_NOCACHE, PAGE_x86_WRITETHRU, and PAGE_WRITECOMBINE flags passed
// down by VirtualProtect.
//
//------------------------------------------------------------------------------
static void InitializePATAndMTRR (void)
{
DWORD dwHighPart, dwLowPart;
DEBUGMSG (1, (L"g_dwCPUFeatures = %8.8lx\r\n", g_dwCPUFeatures));
// can't do anything if MSR is not support
if (!(g_dwCPUFeatures & CPUID_MSR)) {
return;
}
// Is PAT supported?
if (g_dwCPUFeatures & CPUID_PAT) {
// PAT is supported
// Read the current PAT values
NKrdmsr(MSRAddr_PAT, &dwHighPart, &dwLowPart);
// MUST leave dwLowPart as-is for backward compatibility!
// Set the first entry in the high part to be write-combining
dwHighPart = (dwHighPart & ~PAT_Entry0Mask) | PAT_TypeWriteCombining;
// Write the new PAT values
NKwrmsr(MSRAddr_PAT, dwHighPart, dwLowPart);
}
if (g_dwCPUFeatures & CPUID_MTRR) {
// MTRR is supported
DWORD dummy, dwMTRR;
// read the MTRRcap register and check if WC is supproted
NKrdmsr(MSRAddr_MTRRcap, &dummy, &dwMTRR);
if (dwMTRR & MTRRcap_WriteCombineMask) {
int i;
// WC is supported, continue to initialize the MTRR registers/globals
g_nMtrrCnt = (int) (dwMTRR & MTRRcap_VarRangeRegisterCountMask);
DEBUGMSG (1, (L"g_nMtrrCnt = %d\r\n", g_nMtrrCnt));
DEBUGCHK (g_nMtrrCnt);
#ifdef DEBUG
DumpMTRR ();
#endif
// figure out the vairable entries that are already in use
for (i = 0; i < g_nMtrrCnt; i ++) {
NKrdmsr (MSRAddr_MTRRphysMask0 + 2*g_nMtrrInuse, &dummy, &dwMTRR);
DEBUGMSG (1, (L"PhysMask%d: %8.8lx%8.8lx\r\n", i, dummy, dwMTRR));
if (dwMTRR & MTRRphysMask_ValidMask)
g_nMtrrInuse ++;
}
DEBUGMSG (1, (L"g_nMtrrInuse = %d\r\n", g_nMtrrInuse));
// enable MTRR if it's not already enabled
NKrdmsr (MSRAddr_MTRRdefType, &dummy, &dwMTRR);
if (!(dwMTRR & MTRRdefType_EnableMask)) {
NKwrmsr (MSRAddr_MTRRdefType, 0, dwMTRR | MTRRdefType_EnableMask);
}
}
}
// initialize the pfnNKSetMemoryAttributes function pointer
pfnOEMSetMemoryAttributes = OEMSetMemoryAttributes;
}
void x86InitMemory (void)
{
extern DWORD MainMemoryEndAddress;
// Use the PAT/MTRR to add write-combining support to VirtualProtect
g_dwCPUFeatures = IdentifyCpu();
InitializePATAndMTRR ();
//
// Detect extra RAM.
//
g_dwRAMAutoDetectSize = 0x0E400000; // Side effect???
DEBUGMSG(1, (TEXT("g_dwRAMAutoDetectStart = 0x%x, g_dwRAMAutoDetectSize = 0x%x\r\n"), g_dwRAMAutoDetectStart, g_dwRAMAutoDetectSize));
//if (MainMemoryEndAddress == g_dwRAMAutoDetectStart) {
MainMemoryEndAddress += IsDRAM (MainMemoryEndAddress, g_dwRAMAutoDetectSize);
//}
RETAILMSG(1, (TEXT("MainMemoryEndAddress = 0x%x\r\n"), MainMemoryEndAddress));
}
void OEMCacheRangeFlush (LPVOID pAddr, DWORD dwLength, DWORD dwFlags)
{
// cache flush?
if (dwFlags & (CACHE_SYNC_WRITEBACK | CACHE_SYNC_DISCARD)) {
// just perform an uncached access
_asm { mov eax, dword ptr ds:0xa0000000 }
}
if (dwFlags & CACHE_SYNC_FLUSH_TLB) {
// flush TLB
_asm {
mov eax, cr3
mov cr3, eax
}
}
}
VOID* OALPAtoVA(UINT32 pa, BOOL cached)
{
return (VOID *) (pa | (cached? 0x80000000 : 0xa0000000));
}
UINT32 OALVAtoPA(VOID *va)
{
return (DWORD) va & ~ 0xa0000000;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -