Index: ker/kerext_cache.c =================================================================== --- ker/kerext_cache.c (revision 207404) +++ ker/kerext_cache.c (working copy) @@ -25,6 +25,52 @@ int full; }; +/* 3 Times the cache size seems to be a good starting point of the limit of cost vs. time + * based on some metrics taken + */ +#define DCACHE_FLUSH_LINE_LIMIT(_cacheptr) ((_cacheptr)->num_lines*3) +static +int poison_data_cache(struct cacheattr_entry *cache) { + volatile register unsigned v; + static void* poison_baseaddr = NULL; + static size_t poison_size = 0; + int rv; + unsigned nlines, linesz, n; + unsigned *dcache_line; + + nlines = cache->num_lines; + linesz = cache->line_size; + + if(poison_size < (nlines*linesz)) { + if(poison_baseaddr) { + /*TODO: Mmm, we might be flushing a different size cache? Multi-level? */ + (void)memmgr.munmap(NULL, (uintptr_t)poison_baseaddr, poison_size, 0, + mempart_getid(procmgr_prp, sys_memclass_id)); + } + + /* TODO: This is awful, but we need a mapping we can exploit to poison the cache. + * Ideally, we would make a mapping of (nlines*linesz) which maps to 1 page only (syspage?) + * only but for a proof of concept this will have to do. + * + * Other candidates: + * - grab some ram area from asinfo/ram inside CPU_PADDR_START/END + * and do a MAP_PHYS to it + * - make the kernel stack the size of the cache and use it? + */ + if((rv=memmgr.mmap(0, 0, (nlines * linesz), + PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, + 0, 0, __PAGESIZE, 0, NOFD, &poison_baseaddr, &poison_size, + mempart_getid(NULL, sys_memclass_id))) != EOK) { + return rv; + } + } + + /* poison the dcache which effectively flushing it all */ + for(n=0,dcache_line = poison_baseaddr; n < nlines ; n++,dcache_line+=(linesz/sizeof(unsigned))) { + v = *dcache_line; /* push out our cache line */ + } +} + // // This can take a while, so we do it with the kernel unlocked and // everything in a passed-in structure so that we can continue from @@ -70,6 +116,13 @@ if(valid_len > cache_len) valid_len = cache_len; } lines = (valid_len + cache->line_size - 1) / cache->line_size; + + if((flags & CACHE_FLAG_DATA) && (lines > DCACHE_FLUSH_LINE_LIMIT(cache))) { + if(poison_data_cache(cache) == EOK) { + lines=0; /* we're flushed */ + } + } + while(lines != 0) { unsigned done_lines; size_t done_size;