分类: LINUX
2016-03-18 16:09:19
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 操作接口:
()
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 操作。