sel4: flush page table allocator if full

Issue #2044
This commit is contained in:
Alexander Boettcher
2016-07-08 13:44:52 +02:00
committed by Christian Helmuth
parent 90390fe053
commit 998dfa6c5e
4 changed files with 54 additions and 10 deletions

View File

@ -35,7 +35,13 @@ namespace Genode {
*/ */
inline bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages) inline bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages)
{ {
platform_specific()->core_vm_space().map(from_phys, to_virt, num_pages); enum { DONT_FLUSH = false };
try {
platform_specific()->core_vm_space().map(from_phys, to_virt,
num_pages, DONT_FLUSH);
} catch (Page_table_registry::Mapping_cache_full) {
return false;
}
return true; return true;
} }

View File

@ -17,6 +17,7 @@
/* Genode includes */ /* Genode includes */
#include <util/list.h> #include <util/list.h>
#include <base/exception.h> #include <base/exception.h>
#include <base/log.h>
/* core includes */ /* core includes */
#include <util.h> #include <util.h>
@ -30,6 +31,7 @@ class Genode::Page_table_registry
public: public:
class Lookup_failed : Exception { }; class Lookup_failed : Exception { };
class Mapping_cache_full : Exception { };
private: private:
@ -93,7 +95,11 @@ class Genode::Page_table_registry
return; return;
} }
try {
_entries.insert(new (entry_alloc) Entry(addr, sel)); _entries.insert(new (entry_alloc) Entry(addr, sel));
} catch (Genode::Allocator::Out_of_memory) {
throw Mapping_cache_full();
}
} }
void remove_entry(Allocator &entry_alloc, addr_t addr) void remove_entry(Allocator &entry_alloc, addr_t addr)
@ -107,6 +113,14 @@ class Genode::Page_table_registry
PWRN("trying to remove non-existing page frame for 0x%lx", addr); PWRN("trying to remove non-existing page frame for 0x%lx", addr);
} }
} }
void flush_all(Allocator &entry_alloc)
{
for (; Entry *entry = _entries.first();) {
_entries.remove(entry);
destroy(entry_alloc, entry);
}
}
}; };
/** /**
@ -257,6 +271,13 @@ class Genode::Page_table_registry
} }
} }
void flush_cache()
{
for (Page_table *pt = _page_tables.first(); pt; pt = pt->next())
pt->flush_all(_page_table_entry_alloc);
}
/** /**
* Apply functor 'fn' to selector of specified virtual address * Apply functor 'fn' to selector of specified virtual address
* *

View File

@ -148,7 +148,7 @@ class Genode::Vm_space
*/ */
unsigned _idx_to_sel(unsigned idx) const { return (_id << 20) | idx; } unsigned _idx_to_sel(unsigned idx) const { return (_id << 20) | idx; }
void _map_page(addr_t from_phys, addr_t to_virt) void _map_page(addr_t from_phys, addr_t to_virt, bool flush_support)
{ {
/* allocate page-table entry selector */ /* allocate page-table entry selector */
unsigned pte_idx = _sel_alloc.alloc(); unsigned pte_idx = _sel_alloc.alloc();
@ -164,7 +164,19 @@ class Genode::Vm_space
Cnode_index(_leaf_cnode_entry(pte_idx))); Cnode_index(_leaf_cnode_entry(pte_idx)));
/* remember relationship between pte_sel and the virtual address */ /* remember relationship between pte_sel and the virtual address */
try {
_page_table_registry.insert_page_table_entry(to_virt, pte_idx); _page_table_registry.insert_page_table_entry(to_virt, pte_idx);
} catch (Page_table_registry::Mapping_cache_full) {
if (!flush_support)
throw;
warning("flush page table entries - mapping cache full");
_page_table_registry.flush_cache();
/* re-try once */
_page_table_registry.insert_page_table_entry(to_virt, pte_idx);
}
/* /*
* Insert copy of page-frame selector into page table * Insert copy of page-frame selector into page table
@ -300,7 +312,8 @@ class Genode::Vm_space
_vm_cnodes[i].destruct(_cap_sel_alloc); _vm_cnodes[i].destruct(_cap_sel_alloc);
} }
void map(addr_t from_phys, addr_t to_virt, size_t num_pages) void map(addr_t from_phys, addr_t to_virt, size_t num_pages,
bool flush_support = true)
{ {
Lock::Guard guard(_lock); Lock::Guard guard(_lock);
@ -310,7 +323,7 @@ class Genode::Vm_space
for (size_t i = 0; i < num_pages; i++) { for (size_t i = 0; i < num_pages; i++) {
off_t const offset = i << get_page_size_log2(); off_t const offset = i << get_page_size_log2();
_map_page(from_phys + offset, to_virt + offset); _map_page(from_phys + offset, to_virt + offset, flush_support);
} }
} }

View File

@ -12,7 +12,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <base/printf.h> #include <base/log.h>
/* core includes */ /* core includes */
#include <ram_session_component.h> #include <ram_session_component.h>
@ -43,14 +43,18 @@ void Ram_session_component::_clear_ds (Dataspace_component *ds)
/* allocate range in core's virtual address space */ /* allocate range in core's virtual address space */
void *virt_addr; void *virt_addr;
if (!platform()->region_alloc()->alloc(page_rounded_size, &virt_addr)) { if (!platform()->region_alloc()->alloc(page_rounded_size, &virt_addr)) {
PERR("could not allocate virtual address range in core of size %zd\n", error("could not allocate virtual address range in core of size ",
page_rounded_size); page_rounded_size);
return; return;
} }
/* map the dataspace's physical pages to core-local virtual addresses */ /* map the dataspace's physical pages to core-local virtual addresses */
size_t num_pages = page_rounded_size >> get_page_size_log2(); size_t num_pages = page_rounded_size >> get_page_size_log2();
map_local(ds->phys_addr(), (addr_t)virt_addr, num_pages); if (!map_local(ds->phys_addr(), (addr_t)virt_addr, num_pages)) {
error("could not map virtual address range in core of size ",
page_rounded_size);
return;
}
/* clear dataspace */ /* clear dataspace */
size_t num_longwords = page_rounded_size/sizeof(long); size_t num_longwords = page_rounded_size/sizeof(long);