hw: clear RAM dataspaces in chunks

Clearing very large RAM dataspaces could fill up core's page table,
because the dataspaces are locally mapped to clear them.
This would manifest in a loop where exhausting the local page table
leads to its flushing (which does not work for core) and a retry that
again fills up the page table and so on.

To prevent this, flush RAM dataspaces in chunks of at most 128MiB.

Fixes #5086
This commit is contained in:
Benjamin Lamowski 2024-01-05 11:40:17 +01:00 committed by Christian Helmuth
parent 41731a2439
commit 25c7204b2a

View File

@ -16,6 +16,7 @@
#include <ram_dataspace_factory.h>
#include <platform.h>
#include <map_local.h>
#include <util/misc_math.h>
using namespace Core;
@ -51,19 +52,35 @@ void Ram_dataspace_factory::_clear_ds (Dataspace_component &ds)
if (!guard.virt_ptr)
return;
/* map the dataspace's physical pages to corresponding virtual addresses */
size_t num_pages = page_rounded_size >> get_page_size_log2();
if (!map_local(ds.phys_addr(), (addr_t)guard.virt_ptr, num_pages)) {
error("core-local memory mapping failed");
return;
/*
* Map and clear dataspaces in chucks of 128MiB max to prevent large
* mappings from filling up core's page table.
*/
static size_t constexpr max_chunk_size = 128 * 1024 * 1024;
size_t size_remaining = page_rounded_size;
addr_t chunk_phys_addr = ds.phys_addr();
while (size_remaining) {
size_t chunk_size = min(size_remaining, max_chunk_size);
size_t num_pages = chunk_size >> get_page_size_log2();
/* map the dataspace's physical pages to corresponding virtual addresses */
if (!map_local(chunk_phys_addr, (addr_t)guard.virt_ptr, num_pages)) {
error("core-local memory mapping failed");
return;
}
/* dependent on the architecture, cache maintainance might be necessary */
Cpu::clear_memory_region((addr_t)guard.virt_ptr, chunk_size,
ds.cacheability() != CACHED);
/* unmap dataspace from core */
if (!unmap_local((addr_t)guard.virt_ptr, num_pages))
error("could not unmap core-local address range at ", guard.virt_ptr);
size_remaining -= chunk_size;
chunk_phys_addr += chunk_size;
}
/* dependent on the architecture, cache maintainance might be necessary */
Cpu::clear_memory_region((addr_t)guard.virt_ptr, page_rounded_size,
ds.cacheability() != CACHED);
/* unmap dataspace from core */
if (!unmap_local((addr_t)guard.virt_ptr, num_pages))
error("could not unmap core-local address range at ", guard.virt_ptr);
}