blake326 发表于 2014-06-30 13:32

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");
}

blake326 发表于 2014-07-01 09:17

ding
ding
ding

blake326 发表于 2014-07-02 09:12

在ding一下看看。。。

blake326 发表于 2014-07-02 18:58

看起来没人知道。还是论坛档次太低了 :(

塑料袋 发表于 2014-07-03 13:22

blake326 发表于 2014-07-02 18:58 static/image/common/back.gif
看起来没人知道。还是论坛档次太低了

这个只能怪你不是女的

你要是个美女的话,早有人告诉你了。而且最好是去你家言传身教啊

amarant 发表于 2014-07-03 14:11

本帖最后由 amarant 于 2014-07-03 14:33 编辑

不是没人知道,很多人知道。
一来,人不愿看你的帖子,这么长,都是代码
二来,大家都很忙,整天解bug,看看论坛也希望看看轻松愉快的


ALIAS_FLUSH_START 这个地址随便填,因为以他作为开始地址往上刷cache size大小后,就可以全刷。而填一个偏移,就能刷指定行的cache

wth0722 发表于 2014-07-03 16:36

回复 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]
查看完整版本: flush_pfn_alias(), cache alias问题。