CPU Cache原理 &避免dma cache 出錯

CPU Cache 原理及操作 & dma_cache_maint
    轉載下文:

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 操作。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章