Kernel/aarch64: Flush the D-cache before reading back RPi mailbox data

Since we currently can't use MM to allocate a DMA buffer for the RPi
mailbox (as it needs to be below 1G), we can't map it as Non-cacheable,
and instead need to rely on manual cache maintenance operations.
We previously forgot to flush the cache again before reading back data,
which is required on ARM systems, as explained in the comment.
(See also https://events.static.linuxfound.org/sites/events/files/slides/slides_17.pdf
and the DMA examples at https://support.arm.com/documentation/ddi0487/mc/-Part-K-Appendixes/-Appendix-K11-Barrier-Litmus-Tests/-K11-5-Cache-and-TLB-maintenance-instructions-and-barriers/-K11-5-1-Data-cache-maintenance-instructions.)

This appears to have fixed the "Failed to get the RPi CPU temperature"
messages that occur every so often.

In the future, we should instead make MM somehow be able to return
DMA buffers below a given address threshold for legacy bus masters, such
as the mailbox peripheral in Raspberry Pis. MM should also somehow try
to make sure that some low memory stays available for legacy DMA
peripherals and otherwise potentially fall back to bounce pages.
This commit is contained in:
Sönke Holz authored and Sönke Holz committed 2026-09-18 17:23:32 +02:00
1 parent f414ac22bd
commit 6a04d4a37b
1 file changed
+11
+11
View File
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Arch/MemoryFences.h>
#include <Kernel/Arch/aarch64/ASM_wrapper.h>
#include <Kernel/Arch/aarch64/RPi/Mailbox.h>
#include <Kernel/Memory/MemoryManager.h>
@@ -137,6 +138,16 @@ bool Mailbox::send_queue(void* queue, u32 queue_size)
u32 response = m_registers->read_data;
// We keep at most one message in flight and do synchronous communication, so response will always be == request for us.
if (response == request) {
// Ensure that the data cache flush and memcpy() are done after the response == request check.
full_memory_fence();
// Ensure that stale cache lines are discarded before reading from the buffer.
// Cacheable memory regions can be allocated into cache lines at any time, e.g. because they were prefetched or speculatively read.
// We could use an invalidate-only cache operation here (flush_data_cache() both cleans and invalidates),
// but then we'd need to ensure that the buffer is aligned to the cache line size
// (which can vary from processor to processor) to not accidentally delete unrelated data from the caches.
Processor::flush_data_cache(VirtualAddress { &transfer_buffer }, queue_size);
memcpy(queue, transfer_buffer, queue_size);
return message_header->success();
}