Page 1 of 1

how to disable the cache

Posted: Sun May 18, 2008 9:57 am
by DLBuunk
I am trying to write an floppydisk-driver for my small realmode OS, everything worked fine until I read new data in a memory location I already used, because I used DMA the cache wasn't updated. Now I have the data in memory, but because the cache still holds the old data, i can't use it.
Is there any way to flush/disable the cache in realmode? (everything I found about this problem required pmode)

Posted: Sun May 18, 2008 5:12 pm
by Combuster
I suggest you read the Intel manuals - it shows all options of cache control (including all mechanisms that work in real mode)

Specifically, try looking up WBINVD and MTRR

Re: how to disable the cache

Posted: Mon May 19, 2008 12:09 am
by Brendan
Hi,
some_nerd wrote:I am trying to write an floppydisk-driver for my small realmode OS, everything worked fine until I read new data in a memory location I already used, because I used DMA the cache wasn't updated. Now I have the data in memory, but because the cache still holds the old data, i can't use it.
If this actually is what's happening, then your motherboard is broken. The caches are meant to be updated when DMA occurs - there's a "cache coherency protocol" used by CPUs to keep their caches synchronized, that ensures that all caches are coherent for both SMP and DMA.

My guess is that you're starting the DMA transfer but not waiting for it to complete, so that you read one value before DMA overwrites it and another value after DMA overwrites it.

Another guess is that you're using DMA to replace page table entries, etc. In this case the CPU's TLB is not updated (even though the cache is), and you'd need to do TLB invalidation yourself (use "INVLPG", or reload CR3 if you're not using "global" pages).

The only other thing I can think of is if you're executing code while DMA overwrites the code you're executing. In this case you can't really determine how many instructions are in the CPU's pipeline at the time and can end up executing instructions after they've been replaced, but I doubt any sane person would attempt this (due to timing variations you'd never be able to predict when the code is overwritten anyway) .
some_nerd wrote:Is there any way to flush/disable the cache in realmode? (everything I found about this problem required pmode)
For flushing you can use "WBINVD" (80486 or later) or "CLFLUSH" (P6 or later?). In this case you'd need to flush the cache beforehand (otherwise the new data may be overwritten by old data from the CPU's cache), and make sure you don't touch the area being modified until after it's modified (which includes speculative reads).

For disabling, you can use the CD flag in CR0, MTRRs, or the flags in page table entries. Note: "disabling" the cache normally only disables cache updates and doesn't flush data already in the cache - you'd need to disable cache updates then flush the cache to make sure all cache lines are marked as "invalid".

Note: There's only 2 sane reasons for flushing/disabling caches for normal RAM: testing for faulty RAM and measuring RAM speed.Testing if RAM is present is the only other reason (but I won't call that a sane reason ;)).


Cheers,

Brendan

Posted: Mon May 19, 2008 1:10 am
by bewing
Brendan wrote: ... or the flags in page table entries.
That was extremely interesting, and I hadn't understood that properly, before.

Theoretically, the cache coherency stuff takes cycles ... so, theoretically, is it a good idea to turn off caching for pages that you are expecting to DMA to (and re-enable it afterward) -- or is it better to just let the cache coherency hardware do its job?

Or, I suppose, the cache coherency hardware is probably going to end up simply invalidating cached memory pages either way, right? Just marking those blobs of cache as invalid shouldn't take much time .... Hmmm....

Posted: Mon May 19, 2008 5:56 am
by DLBuunk
Thanks for all possibele solutions, I suppose these will help me.

No, I am not overwriting the code I was executing, I am reading some text I stored at the disk, but when I try to read another sector into the same buffer and print it on screen it doesn't seem to be updated.