- 論壇徽章:
- 0
|
cache alias:
http://www.72891.cn/forum.php?mod=viewthread&tid=1972593
cache一般有幾種類型:
pipt
vivt
vipt noalias
vipt alias
實(shí)際上armv7 的dcache是vipt noalias的。icache是vipt alias的。
為什么會(huì)有cache alias問題呢,為什么amv7 dcache又沒有呢,這是armv7 硬件能夠自動(dòng)處理dcache alias問題。
一個(gè)cache由 cache line size * num set * way 組成。
一般是 32 * 256 * 4 = 32KB.
如果line size * num set = 8KB大于page size的話那么就有可能有alias問題。
假設(shè)0xf000 0000和0xf000 1000兩段地址都是映射同一個(gè)page的話,那么訪問0xf000 0000和0xf000 1000時(shí),他們?cè)赾ache中的num是不同的,就是有各自的cache line,但是映射的物理地址是一樣的。如果硬件不能自動(dòng)處理的話,軟件一定要處理好。
現(xiàn)在假設(shè)dcache是vipt alias的話,文件系統(tǒng)寫一個(gè)page cache時(shí),由于用戶態(tài)可能映射了該page,所以會(huì)調(diào)用flush_dcache_page()來解決這個(gè)alias問題。
最終會(huì)調(diào)用到flush_pfn_alias(),不過這個(gè)代碼看不懂,請(qǐng)高人幫忙分析下。
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
//這個(gè)函數(shù)這個(gè)地址不知道什么意思?
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");
} |
|