⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memory.c

📁 威盛 wince5.0 bsp 包 for x86 系统, 支持 VT8601 等北桥
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// 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 + -