📄 memory.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name: memory.c
Abstract:
This file implements x86 memory related functions.
exported function:
void x86InitMemory (void);
globals defined:
x86CacheInfo
globals affected:
MainMemoryAddress
pfnOEMSetMemoryAttributes
Notes:
--*/
#include <windows.h>
#include <pc.h>
#include <msr.h>
extern BOOL (* pfnOEMSetMemoryAttributes) (LPVOID pVirtualAddr, LPVOID pPhysAddr, DWORD cbSize, DWORD dwAttributes);
static DWORD g_dwCPUFeatures;
static int g_nMtrrCnt;
static int g_nMtrrInuse;
#define PAGE_SIZE 4096
extern const DWORD g_dwRAMAutoDetectStart;
//extern const DWORD g_dwRAMAutoDetectSize;
extern DWORD g_dwRAMAutoDetectSize;
// Cache Information. Platform specific
//
CacheInfo g_oalCacheInfo =
{
0, // flags for L1 cache
0, // L1 IC total size in bytes
0, // L1 IC line size in bytes
0, // L1 IC number of ways, 1 for direct mapped
0, // L1 DC total size in bytes
0, // L1 DC line size in bytes
0, // L1 DC number of ways, 1 for direct mapped
0, // flags for L2 cache
0, // L2 IC total size in bytes, 0 means no L2 ICache
0, // L2 IC line size in bytes
0, // L2 IC number of ways, 1 for direct mapped
0, // L2 DC total size in bytes, 0 means no L2 DCache
0, // L2 DC line size in bytes
0 // L2 DC number of ways, 1 for direct mapped
};
// -----------------------------------------------------------------------------
//
// IsDRAM
//
// Is there DRAM available at the specified location? This test must be non-
// destructive... can't alter the contents except temporarily.
//
// -----------------------------------------------------------------------------
static DWORD
IsDRAM(
DWORD dwMemStartAddr,
DWORD dwMaxMemLength
)
{
#define EXTENSION_CHECK_SIZE 4
#define DRAM_TEST_INTERVAL 0x100000
DWORD testvect [EXTENSION_CHECK_SIZE] ={0x55aaaa55,0xaa5555aa,12345678,0xf00f4466 };
DWORD backup [EXTENSION_CHECK_SIZE];
DWORD *target;
BOOL bMismatch= FALSE;
DWORD length;
//
// Make sure we aren't caching this data. That wouldn't be too useful...
//
dwMemStartAddr |= 0x20000000;
//
// Probe each page until we find one that fails
//
for (length = 0; (length < dwMaxMemLength) && !bMismatch ; )
{
target = (PDWORD) (length + dwMemStartAddr);
//
// Save the original data in backup buffer
//
memcpy( backup, target, sizeof(testvect) );
//
// Now fill memory from the test vector
//
memcpy( target, testvect, sizeof(testvect) );
//
// Now compare memory to the test vector
//
if ( memcmp( target, testvect, sizeof(testvect) ) )
bMismatch = TRUE;
else
length += DRAM_TEST_INTERVAL; // OK, advance our probe pointer
//
// Don't forget to restore the saved data.
//
memcpy( target, backup, sizeof(backup) );
}
//
// Check every 1MB but report 4MB aligned only. All 4MB must be good to pass.
//
length &= ~(0x00400000 - 1);
DEBUGMSG(length, (TEXT("OEM Extra DRAM Detected @ base = x%X, size=%d MB \r\n"),
dwMemStartAddr, (length >> 20)));
return (length);
}
static void WriteMtrrRegPair (int ixReg, const LARGE_INTEGER *pliPhysBase, const LARGE_INTEGER *pliPhysMask)
{
DEBUGMSG (1, (L"Setting MTRR reg-pair:%d with 0x%8.8lx%8.8lx, 0x%8.8lx%8.8lx\r\n", ixReg,
pliPhysBase->HighPart, pliPhysBase->LowPart| MTRR_TypeWriteCombining,
pliPhysMask->HighPart, pliPhysMask->LowPart));
// Per Intel MTRR document, we need to disable/enable interrupt, flush cache and TLB, and disable MTRR before/after
// changing MTRR registers. However, since we use this only for non-memory area (video frame buffer) during
// initialization, both cache and TLB shouldn't have any refernece to them. We'll need to revisit this function
// if the assumption is no longer true.
//
// pre_mtrr_change();
NKwrmsr(MSRAddr_MTRRphysBase0 + (2 * ixReg), pliPhysBase->HighPart, pliPhysBase->LowPart | MTRR_TypeWriteCombining);
NKwrmsr(MSRAddr_MTRRphysMask0 + (2 * ixReg), pliPhysMask->HighPart, pliPhysMask->LowPart);
// post_mtrr_change();
}
#ifdef DEBUG
static void DumpMTRR (void)
{
int i;
DWORD dwHi, dwLo;
for (i = 0; i < g_nMtrrCnt; i ++) {
NKrdmsr (MSRAddr_MTRRphysMask0 + 2*i, &dwHi, &dwLo);
NKDbgPrintfW (L"MTRR PhysMask%d: %8.8lx%8.8lx\r\n", i, dwHi, dwLo);
NKrdmsr (MSRAddr_MTRRphysBase0 + 2*i, &dwHi, &dwLo);
NKDbgPrintfW (L"MTRR PhysBase%d: %8.8lx%8.8lx\r\n", i, dwHi, dwLo);
}
}
#endif
// return the least significant non-zero bit
__inline DWORD LSB (DWORD x)
{
return x & (0-x);
}
// return the most significant non-zero bit
static DWORD MSB (DWORD x)
{
DWORD msb = x;
while (x &= (x-1)) {
msb = x;
}
return msb;
}
//
// CheckExistingMTRR: check if the requested range overlap with existing ranges
//
// returns: 0 - if already exist and is of type PAGE_WRITECOMBINE
// 1 - if not exist and no overlapping with any existing ranges
// -1 - if overlapped with existing ranges (FAIL)
//
#define MTRR_ALREADY_EXIST 0
#define MTRR_NOT_EXIST 1
#define MTRR_OVERLAPPED -1
static int CheckExistingMTRR (const LARGE_INTEGER *pliPhysBase, DWORD dwPhysSize)
{
int i;
LARGE_INTEGER liReg;
DEBUGCHK (LSB (dwPhysSize) == dwPhysSize); // dwPhysSize must be power of 2
// loop through the MTTR register pairs
for (i = 0; i < g_nMtrrCnt; i ++) {
NKrdmsr (MSRAddr_MTRRphysMask0 + 2*i, &liReg.HighPart, &liReg.LowPart);
if (liReg.LowPart & MTRRphysMask_ValidMask) {
// register is in use, check to see if it covers our request
// NOTE: we're assuming all MTRR ranges are of size 2^^n
// and physbase is also 2^^n aligned
DWORD dwRegSize = LSB (liReg.LowPart & -PAGE_SIZE);
DWORD dwRegType;
NKrdmsr (MSRAddr_MTRRphysBase0 + 2*i, &liReg.HighPart, &liReg.LowPart);
dwRegType = liReg.LowPart & MTRRphysBase_TypeMask;
liReg.LowPart -= dwRegType;
if ((pliPhysBase->QuadPart < liReg.QuadPart + dwRegSize)
&& (pliPhysBase->QuadPart + dwPhysSize >= liReg.QuadPart)) {
// range overlapped - return MTRR_ALREADY_EXIST if fully contained and of the same type.
// - otherwise return MTRR_OVERLAPPED
return ((MTRR_TypeWriteCombining == dwRegType)
&&(pliPhysBase->QuadPart >= liReg.QuadPart)
&& (pliPhysBase->QuadPart + dwPhysSize <= liReg.QuadPart + dwRegSize))
? MTRR_ALREADY_EXIST
: MTRR_OVERLAPPED;
}
}
}
return MTRR_NOT_EXIST;
}
//------------------------------------------------------------------------------
//
// PATSetMemoryAttributes
//
// PAT version of OEMSetMemoryAttributes
//
//------------------------------------------------------------------------------
static BOOL PATSetMemoryAttributes (
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
)
{
return (g_dwCPUFeatures & CPUID_PAT)
? NKVirtualSetAttributes (pVirtAddr, cbSize,
x86_PAT_INDEX0, // Index of first upper PAT entry
x86_PAT_INDEX_MASK, // Mask of all PAT index bits
&dwAttributes)
: FALSE;
}
//------------------------------------------------------------------------------
//
// MTRRSetMemoryAttributes
//
// MTRR version of OEMSetMemoryAttributes
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -