flush_pfn_alias(), cache alias问题。
cache alias:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=1972593
cache一般有几种类型:
pipt
vivt
vipt noalias
vipt alias
实际上armv7 的dcache是vipt noalias的。icache是vipt alias的。
为什么会有cache alias问题呢,为什么amv7 dcache又没有呢,这是armv7 硬件能够自动处理dcache alias问题。
一个cache由 cache line size * num set * way 组成。
一般是 32 * 256 * 4 = 32KB.
如果line size * num set = 8KB大于page size的话那么就有可能有alias问题。
假设0xf000 0000和0xf000 1000两段地址都是映射同一个page的话,那么访问0xf000 0000和0xf000 1000时,他们在cache中的num是不同的,就是有各自的cache line,但是映射的物理地址是一样的。如果硬件不能自动处理的话,软件一定要处理好。
现在假设dcache是vipt alias的话,文件系统写一个page cache时,由于用户态可能映射了该page,所以会调用flush_dcache_page()来解决这个alias问题。
最终会调用到flush_pfn_alias(),不过这个代码看不懂,请高人帮忙分析下。
void flush_dcache_page(struct page *page)
{
struct address_space *mapping;
/*
* The zero page is never written to, so never has any dirty
* cache lines, and therefore never needs to be flushed.
*/
if (page == ZERO_PAGE(0))
return;
mapping = page_mapping(page);
if (!cache_ops_need_broadcast() &&
mapping && !mapping_mapped(mapping))
clear_bit(PG_dcache_clean, &page->flags);
else {
__flush_dcache_page(mapping, page);
if (mapping && cache_is_vivt())
__flush_dcache_aliases(mapping, page);
else if (mapping)
__flush_icache_all();
set_bit(PG_dcache_clean, &page->flags);
}
}
void __flush_dcache_page(struct address_space *mapping, struct page *page)
{
/*
* Writeback any data associated with the kernel mapping of this
* page.This ensures that data in the physical page is mutually
* coherent with the kernels mapping.
*/
if (!PageHighMem(page)) {
__cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
} else {
void *addr = kmap_high_get(page);
if (addr) {
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
kunmap_high(page);
} else if (cache_is_vipt()) {
/* unmapped pages might still be cached */
addr = kmap_atomic(page);
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
kunmap_atomic(addr);
}
}
/*
* If this is a page cache page, and we have an aliasing VIPT cache,
* we only need to do one flush - which would be at the relevant
* userspace colour, which is congruent with page->index.
*/
if (mapping && cache_is_vipt_aliasing())
flush_pfn_alias(page_to_pfn(page),
page->index << PAGE_CACHE_SHIFT);
}
#define ALIAS_FLUSH_START 0xffff4000
//这个函数这个地址不知道什么意思?
static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
{
unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
const int zero = 0;
set_pte_ext(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL), 0);
flush_tlb_kernel_page(to);
asm( "mcrr p15, 0, %1, %0, c14\n"
" mcr p15, 0, %2, c7, c10, 4"
:
: "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero)
: "cc");
} ding
ding
ding 在ding一下看看。。。 看起来没人知道。还是论坛档次太低了 :( blake326 发表于 2014-07-02 18:58 static/image/common/back.gif
看起来没人知道。还是论坛档次太低了
这个只能怪你不是女的
你要是个美女的话,早有人告诉你了。而且最好是去你家言传身教啊 本帖最后由 amarant 于 2014-07-03 14:33 编辑
不是没人知道,很多人知道。
一来,人不愿看你的帖子,这么长,都是代码
二来,大家都很忙,整天解bug,看看论坛也希望看看轻松愉快的
ALIAS_FLUSH_START 这个地址随便填,因为以他作为开始地址往上刷cache size大小后,就可以全刷。而填一个偏移,就能刷指定行的cache
回复 6# amarant
講的不錯
其實flush_pfn_alias()就是一個關鍵
樓主你可以試者去兜起來
1. to 就是解決alias的新VA
2. 13,14bit 就是靠這兩個去把那同一個color放在一起<-- CACHE_COLOUR(vaddr)
3. mcrr p15,,,,c14 目的就是flush to這個VA
4. mcr p15, 0,c7, c10, 4 就是做 DSB
页:
[1]