📄 cfw.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.
//
#include <windows.h>
/*
OEMCacheRangeFlush()
Single OAL entry point for all cache flush operations.
Parameters:
pAddr - starting VA on which the cache operation is to be performed
dwLength - length of flush
dwFlags - specifies the cache operation to be performed:
CACHE_SYNC_WRITEBACK: write back DATA cache
CACHE_SYNC_DISCARD: write back and discard DATA cache
CACHE_SYNC_INSTRUCTIONS: discard I-Cache
CACHE_SYNC_FLUSH_I_TLB: flush instruction TLB
CACHE_SYNC_FLUSH_D_TLB: flush data TLB
CACHE_SYNC_FLUSH_TLB: flush both I/D TLB
CACHE_SYNC_L2_WRITEBACK: write back L2 cache
CACHE_SYNC_L2_DISCARD: write back and discard L2 cache
CACHE_SYNC_ALL: perform all the above operations.
Return Value
None.
Remarks
If both pAddr and dwLength are 0, the entire cache (or TLB, as directed by dwFlags) will be flushed.
Only the kernel can set the TLB flush flags when it calls this routine, and when a TLB flush is performed
with dwLength == PAGE_SIZE, pAddr is guaranteed to be on a page boundary.
*/
void OEMCacheRangeFlush(LPVOID pAddr, DWORD dwLength, DWORD dwFlags)
{
// cache maintenance constants
const DWORD DCACHE_LINES_PER_SET_BITS = 6; // 64 lines per set
const DWORD DCACHE_LINE_SIZE_BITS = 5; // 32 bytes per line
const DWORD DCACHE_SETS = 8; // 8 sets
const DWORD DCACHE_LINES_PER_SET = (1 << DCACHE_LINES_PER_SET_BITS);
const DWORD DCACHE_LINE_SIZE = (1 << DCACHE_LINE_SIZE_BITS);
const DWORD ICACHE_LINE_SIZE = 32; // bytes
const DWORD MMU_PAGE_SIZE = 4096;
// these are defined in assembly language
extern void ARMFlushDCache(DWORD, DWORD, DWORD, DWORD);
extern void ARMFlushDCacheLines(LPVOID, DWORD, DWORD);
extern void ARMCleanDCache(DWORD, DWORD, DWORD, DWORD);
extern void ARMCleanDCacheLines(LPVOID, DWORD, DWORD);
extern void ARMFlushICache(void);
extern void ARMFlushICacheLines(LPVOID, DWORD, DWORD);
extern void ARMClearITLB(void);
extern void ARMClearITLBEntry(LPVOID);
extern void ARMClearDTLB(void);
extern void ARMClearDTLBEntry(LPVOID);
if (dwFlags & CACHE_SYNC_DISCARD)
{
// write back and invalidate the selected portions of the data cache
if(dwLength == 0) {
if(pAddr == 0) {
// yes, invalidate it also
ARMFlushDCache(DCACHE_LINES_PER_SET - 1, DCACHE_SETS - 1, (32 - DCACHE_LINES_PER_SET_BITS), DCACHE_LINE_SIZE);
}
} else if(dwLength > MMU_PAGE_SIZE) {
// too much work, invalidate the whole cache
ARMFlushDCache(DCACHE_LINES_PER_SET - 1, DCACHE_SETS - 1, (32 - DCACHE_LINES_PER_SET_BITS), DCACHE_LINE_SIZE);
} else {
// normalize address to cache line alignment and adjust the length accordingly
DWORD dwNormalizedAddress = (DWORD) pAddr & ~(DCACHE_LINE_SIZE - 1);
DWORD dwNormalizedLength = dwLength + ((DWORD) pAddr - dwNormalizedAddress);
// flush all the indicated cache entries
ARMFlushDCacheLines((LPVOID) dwNormalizedAddress, dwNormalizedLength, DCACHE_LINE_SIZE);
}
}
else if (dwFlags & CACHE_SYNC_WRITEBACK) {
// write back the address range -- is it the whole cache?
if(dwLength == 0) {
if(pAddr == 0) {
// yes, invalidate it also
ARMCleanDCache(DCACHE_LINES_PER_SET - 1, DCACHE_SETS - 1, (32 - DCACHE_LINES_PER_SET_BITS), DCACHE_LINE_SIZE);
}
} else if(dwLength > MMU_PAGE_SIZE) {
// too much work, invalidate the whole cache
ARMCleanDCache(DCACHE_LINES_PER_SET - 1, DCACHE_SETS - 1, (32 - DCACHE_LINES_PER_SET_BITS), DCACHE_LINE_SIZE);
} else {
// normalize address to cache line alignment and adjust the length accordingly
DWORD dwNormalizedAddress = (DWORD) pAddr & ~(DCACHE_LINE_SIZE - 1);
DWORD dwNormalizedLength = dwLength + ((DWORD) pAddr - dwNormalizedAddress);
// write back all the indicated cache entries
ARMCleanDCacheLines((LPVOID) dwNormalizedAddress, dwNormalizedLength, DCACHE_LINE_SIZE);
}
}
if (dwFlags & CACHE_SYNC_INSTRUCTIONS)
{
if(dwLength == 0) {
if(pAddr == 0) {
// yes, invalidate it also
ARMFlushICache();
}
} else if(dwLength > MMU_PAGE_SIZE) {
// too much work, invalidate the whole cache
ARMFlushICache();
} else {
// normalize address to cache line alignment and adjust the length accordingly
DWORD dwNormalizedAddress = (DWORD) pAddr & ~(ICACHE_LINE_SIZE - 1);
DWORD dwNormalizedLength = dwLength + ((DWORD) pAddr - dwNormalizedAddress);
// write back all the indicated cache entries
ARMFlushICacheLines((LPVOID) dwNormalizedAddress, dwNormalizedLength, ICACHE_LINE_SIZE);
}
}
// We can flush individual entries in the instruction TLB
if (dwFlags & CACHE_SYNC_FLUSH_I_TLB)
{
if(dwLength == MMU_PAGE_SIZE) {
// flush one TLB entry
ARMClearITLBEntry(pAddr);
} else {
// flush the whole TLB
ARMClearITLB();
}
}
// We can flush individual entries in the data TLB
if (dwFlags & CACHE_SYNC_FLUSH_D_TLB)
{
// check first for TLB updates forced by paging
if(dwLength == MMU_PAGE_SIZE) {
// flush one TLB entry
ARMClearDTLBEntry(pAddr);
} else {
// flush the whole TLB
ARMClearDTLB();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -