轉載下文:
CPU Cache原理
CPU緩存(Cache Memory)是位於CPU與內存之間的臨時存儲器,它的容量比內存小的多但是交換速度卻比內存要快得多。緩存的出現主要是爲了解決CPU運算速度與內存讀寫速度不匹配的矛盾,因爲CPU運算速度要比內存讀寫速度快很多,這樣會使CPU花費很長時間等待數據到來或把數據寫入內存。在緩存中的數據是內存中的一小部分,但這一小部分是短時間內CPU即將訪問的,當CPU調用大量數據時,就可避開內存直接從緩存中調用,從而加快讀取速度。
cache 一致性問題
由於緩存存在於cpu與內存中間,所以任何外設對內存的修改並不能保證cache中也得到同樣的更新,同樣處理器對緩存中內容的修改也不能保證內存中的數據得到更新。這種緩存中數據與內存中數據的不同步和不一致現象將可能導致 使用DMA 傳輸數據時 或 處理器運行自修改代碼時產生錯誤。
DMA 與 Cache
在進行DMA 操作時,如果沒有對Cache 進行適當的操作,將可能產生以下兩種錯誤:
1. DMA 從外設讀取數據到供處理器使用。DMA 將外部數據直接傳到內存中,但cache 中仍然保留的是舊數據,這樣處理器在訪問數據時直接訪問緩存將得到錯誤的數據。
2. DMA 向外設寫入由處理器提供的數據。處理器在處理數據時數據會先存放到cache 中,此時cache 中的數據有可能還沒來得及寫回到內存中的數據。如果這時DMA 直接從內存中取出數據傳送到外設,外設將可能得到錯誤的數據。
爲了正確進行DMA 傳輸,必須進行必要的cache 操作。 cache 操作主要分爲 invalidate (作廢) 和 writeback (寫回) ,有時也將兩着放在一起使用。
以linux 下對DMA 操作的函數爲例:
參考:kernel/arch/arm/mm/dma-mapping.c
/*
* Make an area consistent for devices.
* Note: Drivers should NOT use this function directly, as it will break
* platforms with CONFIG_DMABOUNCE.
* Use the driver DMA support - see dma-mapping.h (dma_sync_*)
*/
void dma_cache_maint(const void *start, size_t size, int direction)
{
void (*inner_op)(const void *, const void *);
void (*outer_op)(unsigned long, unsigned long);
BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(start + size - 1));
switch (direction) {
case DMA_FROM_DEVICE: /* invalidate only */
inner_op = dmac_inv_range;
outer_op = outer_inv_range;
break;
case DMA_TO_DEVICE: /* writeback only */
inner_op = dmac_clean_range;
outer_op = outer_clean_range;
break;
case DMA_BIDIRECTIONAL: /* writeback and invalidate */
inner_op = dmac_flush_range;
outer_op = outer_flush_range;
break;
default:
BUG();
}
inner_op(start, start + size);
outer_op(__pa(start), __pa(start) + size);
}
EXPORT_SYMBOL(dma_cache_maint);
1. DMA 從外設讀取數據到供處理器使用時,可先進性invalidate 操作。這樣將迫使處理器在讀取cache中的數據時,先從內存中讀取數據到緩存,保證緩存和內存中數據的一致性。
2. DMA 向外設寫入由處理器提供的數據時,可先進性writeback 操作。這樣可以DMA傳輸數據之前先將緩存中的數據寫回到內存中。
如果不清楚DMA 操作的方向,也可先同時進行invalidate 和writeback 操作。操作的結果等同於invalidate 和 writeback 操作效果的和。
wince 操作系統也有一套cache 操作接口:
(http://msdn.microsoft.com/en-us/library/ms904878.aspx)
void OEMCacheRangeFlush( LPVOID pAddr, DWORD dwLength, DWORD dwFlags );dwFlags 的定義如下表
Value | Description |
---|---|
CACHE_SYNC_WRITEBACK | Write back cached data. |
CACHE_SYNC_DISCARD | Write back and discard cached data. |
CACHE_SYNC_INSTRUCTIONS | Discard all cached instructions. |
自修改代碼 與 Cache
當處理器要執行自修改代碼時,處理器首先生成新的代碼存放到cache中,最後從cache 中裝入再將指令送入處理器。如果處理器的cache 分爲 D-Cache (數據緩存)和 I-Cache (指令緩存),則生成代碼時會存入D-Cache ,而取代碼時從 I-Cache 中讀出,這樣當D-Cache 和 I-Cache 中的數據(也就是新要生成的指令碼)不相同時,會導致無法執行正確的指令。
爲了使指令正確執行,需要對兩個Cache中的數據及時進行同步:對D-Cache 進行writeback 操作,對I-Cashe 進行invalidate 操作。