void OEMCacheRangeFlush(LPVOID pAddr, DWORD dwLength, DWORD dwFlags) { // cache maintenance constants const DWORD PAGE_SIZE = 4096; // 4KB pages used by winCE on XScale // these are defined in assembly language extern void OALFlushICache(void); extern void XScaleFlushICacheLines(LPVOID, DWORD, DWORD); extern void XScaleFlushDCache(DWORD, DWORD, DWORD); extern void XScaleFlushDCacheLines(PVOID, DWORD, DWORD); extern void XScaleCleanDCacheLines(LPVOID, DWORD, DWORD); extern void OALClearITLB(void); extern void OALClearITLBEntry(LPVOID); extern void OALClearDTLB(void); extern void OALClearDTLBEntry(LPVOID); extern void OALClearUTLB(void); extern const PVOID gpvCacheFlushBaseMemoryAddress; /////////////////////////////////////////////////////////////////////////// // Flush DCACHE /////////////////////////////////////////////////////////////////////////// if(dwFlags & CACHE_SYNC_DISCARD) { // Write-back and invalidate either all or a range // if (!(dwLength || (DWORD)pAddr)) // If length and address are both zero, flush all. { XScaleFlushDCache(DCACHE_LINES, ARMCacheInfo.dwL1DCacheLineSize, (DWORD) gpvCacheFlushBaseMemoryAddress); } else if (dwLength >= (DWORD) ARMCacheInfo.dwL1DCacheSize) { XScaleFlushDCache(DCACHE_LINES, ARMCacheInfo.dwL1DCacheLineSize, (DWORD) gpvCacheFlushBaseMemoryAddress); } else { // normalize address and length DWORD dwNormalizedAddress, dwNormalizedLength; dwNormalizedAddress = (DWORD) pAddr & ~(ARMCacheInfo.dwL1DCacheLineSize - 1); dwNormalizedLength = dwLength + ((DWORD) pAddr - dwNormalizedAddress); // invalidate all the indicated cache entries XScaleFlushDCacheLines((LPVOID) dwNormalizedAddress, dwNormalizedLength, ARMCacheInfo.dwL1DCacheLineSize); } } else if(dwFlags & CACHE_SYNC_WRITEBACK) { // write back the address range // if (!(dwLength || (DWORD)pAddr)) // If length and address are both zero, flush all. { XScaleFlushDCache(DCACHE_LINES, ARMCacheInfo.dwL1DCacheLineSize, (DWORD) gpvCacheFlushBaseMemoryAddress); } else if (dwLength >= (DWORD) ARMCacheInfo.dwL1DCacheSize) { XScaleFlushDCache(DCACHE_LINES, ARMCacheInfo.dwL1DCacheLineSize, (DWORD) gpvCacheFlushBaseMemoryAddress); } else { // normalize address to cache line alignment and adjust the length accordingly DWORD dwNormalizedAddress = (DWORD) pAddr & ~(ARMCacheInfo.dwL1DCacheLineSize - 1); DWORD dwNormalizedLength = dwLength + ((DWORD) pAddr - dwNormalizedAddress); // write back all the indicated cache entries XScaleCleanDCacheLines((LPVOID) dwNormalizedAddress, dwNormalizedLength, ARMCacheInfo.dwL1DCacheLineSize); } } /////////////////////////////////////////////////////////////////////////// // Flush ICACHE /////////////////////////////////////////////////////////////////////////// if(dwFlags & CACHE_SYNC_INSTRUCTIONS) { if (!(dwLength || (DWORD)pAddr)) // If length and address are both zero, flush all. { OALFlushICache(); } else if (dwLength >= (DWORD) ARMCacheInfo.dwL1ICacheSize) { OALFlushICache(); } else { // normalize address and length DWORD dwNormalizedAddress, dwNormalizedLength; dwNormalizedAddress = (DWORD) pAddr & ~(ARMCacheInfo.dwL1ICacheLineSize - 1); dwNormalizedLength = dwLength + ((DWORD) pAddr - dwNormalizedAddress); // invalidate all the indicated cache entries XScaleFlushICacheLines((LPVOID) dwNormalizedAddress, dwNormalizedLength, ARMCacheInfo.dwL1ICacheLineSize); } } /////////////////////////////////////////////////////////////////////////// // Flush I-TLB /////////////////////////////////////////////////////////////////////////// if(dwFlags & CACHE_SYNC_FLUSH_I_TLB) { if(dwLength == PAGE_SIZE) { // flush a single entry from the I-TLB // OALClearITLBEntry(pAddr); } else { // flush the entire TLB // OALClearITLB(); } } /////////////////////////////////////////////////////////////////////////// // Flush D-TLB /////////////////////////////////////////////////////////////////////////// if(dwFlags & CACHE_SYNC_FLUSH_D_TLB) { if(dwLength == PAGE_SIZE) { // flush a single entry from the I-TLB // OALClearDTLBEntry(pAddr); } else { // flush the entire TLB // OALClearDTLB(); } } }
void OEMCacheRangeFlush(VOID *pAddress, DWORD length, DWORD flags) { OALMSG(OAL_CACHE&&OAL_VERBOSE, ( L"+OEMCacheRangeFlush(0x%08x, %d, 0x%08x)\r\n", pAddress, length, flags )); if ((flags & CACHE_SYNC_DISCARD) != 0) { // Write back and invalidate the selected portions of the data cache if (length == 0) { if (pAddress == NULL) OALFlushDCache(); } else { // Normalize address to cache line alignment UINT32 mask = g_oalCacheInfo.L1DLineSize - 1; UINT32 address = (UINT32)pAddress & ~mask; // Adjust size to reflect cache line alignment length += (UINT32)pAddress - address; // If range is bigger than cache size flush all if (length >= g_oalCacheInfo.L1DSize) { OALFlushDCache(); } else { // Flush all the indicated cache entries OALFlushDCacheLines((VOID*)address, length); } } } else if ((flags & CACHE_SYNC_WRITEBACK) != 0) { // Write back the selected portion of the data cache if (length == 0) { if (pAddress == NULL) OALCleanDCache(); } else { // Normalize address to cache line alignment UINT32 mask = g_oalCacheInfo.L1DLineSize - 1; UINT32 address = (UINT32)pAddress & ~mask; // Adjust size to reflect cache line alignment length += (UINT32)pAddress - address; // If range is bigger than cache size clean all if (length >= g_oalCacheInfo.L1DSize) { OALCleanDCache(); } else { // Flush all the indicated cache entrie OALCleanDCacheLines((VOID*)address, length); } } } if ((flags & CACHE_SYNC_INSTRUCTIONS) != 0) { if (length == 0) { if (pAddress == NULL) OALFlushICache(); } else { // Normalize address to cache line alignment UINT32 mask = g_oalCacheInfo.L1ILineSize - 1; UINT32 address = (UINT32)pAddress & ~mask; length += (UINT32)pAddress - address; if (length >= g_oalCacheInfo.L1ISize) { OALFlushICache(); } else { OALFlushICacheLines((VOID*)address, length); } } } if ((flags & CACHE_SYNC_FLUSH_I_TLB) != 0) { if (length == PAGE_SIZE) { // flush one TLB entry OALClearITLBEntry(pAddress); } else { // flush the whole TLB OALClearITLB(); } } if ((flags & CACHE_SYNC_FLUSH_D_TLB) != 0) { // check first for TLB updates forced by paging if (length == PAGE_SIZE) { // flush one TLB entry OALClearDTLBEntry(pAddress); } else { // flush the whole TLB OALClearDTLB(); } } OALMSG(OAL_CACHE&&OAL_VERBOSE, (L"-OEMCacheRangeFlush\r\n")); }