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

📄 memory.c

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