On Wed, Nov 25, 2009 at 03:01:05PM +0100, Florian Lohoff wrote:
> > | static inline void flush_icache_range(unsigned long start, unsigned long
> > stop)
> > | {
> > | cacheflush ((void *)start, stop-start, ICACHE);
> > | }
>
> Would this only evict stuff from the ICACHE? When trying to execute
> a just written buffer and with a writeback DCACHE you would need to
> explicitly writeback the DCACHE to memory and invalidate the ICACHE.
No; ICACHE really means the kernel will do whatever it takes to make the
I-cache coherent with the D-cache. For most processors this requires
writing back the D-cache to S-cache or if no S-cache present, memory
then invalidating the I-cache.
> > It seems this is not enough, as sometimes, some executed code does not
> > correspond to the assembly dump of this memory region. This seems to be
> > especially the case of memory regions that are written twice, due to
> > relocations:
> > 1) a branch instruction is written with an offset of 0
> > 2) the offset is patched
> > 3) cacheflush is called
> >
> > Sometimes the executed code correspond to the code written in 1), which
> > means the branch is skipped.
>
> Which proves my theory - as long as you have cache pressure you will happily
> writeback the contents to memory before trying to execute (you invalidate
> the ICACHE above) - In case you DCACHE does not suffer from pressure
> the contents will not been written back and you'll execute stale code.
You could - on a uni-processor system - do something like this to invalidate
the cache:
int array[32768 / sizeof(int)]; /* size of D-cache on SB1250 */
blow_away_d(void)
{
memset(array, 0, sizeof(array) / sizeof(int) - 2);
array[sizeof(int) - 2] = 0x03E00008; /* jr $ra */
array[sizeof(int) - 1] = 0x00000000; /* nop */
}
blow_away_i(void)
{
void (*fn)(void) = (void *) array;
blow_away_d();
fn();
}
blow_away_setup(void)
{
blow_away_d();
cacheflush(array, sizeof(array), BCACHE);
}
The memset and array assignment operations result in victim writebacks
that is basically an D-cache writeback. Later on executing the code in
the array will result in the entire I-cache getting refilled so anything
of your qemu code array that might happen to live in the I-cache will be
discarded out of the cache.
Ralf
|