From 998dfa6c5ee237b7cfdc4d716abbf96bb21b4c83 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Fri, 8 Jul 2016 13:44:52 +0200 Subject: [PATCH] sel4: flush page table allocator if full Issue #2044 --- repos/base-sel4/src/core/include/map_local.h | 8 ++++++- .../src/core/include/page_table_registry.h | 23 ++++++++++++++++++- repos/base-sel4/src/core/include/vm_space.h | 21 +++++++++++++---- .../base-sel4/src/core/ram_session_support.cc | 12 ++++++---- 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/repos/base-sel4/src/core/include/map_local.h b/repos/base-sel4/src/core/include/map_local.h index 3a2a80920f..912ec2dab6 100644 --- a/repos/base-sel4/src/core/include/map_local.h +++ b/repos/base-sel4/src/core/include/map_local.h @@ -35,7 +35,13 @@ namespace Genode { */ 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; } diff --git a/repos/base-sel4/src/core/include/page_table_registry.h b/repos/base-sel4/src/core/include/page_table_registry.h index 60c0625250..51c83f822e 100644 --- a/repos/base-sel4/src/core/include/page_table_registry.h +++ b/repos/base-sel4/src/core/include/page_table_registry.h @@ -17,6 +17,7 @@ /* Genode includes */ #include #include +#include /* core includes */ #include @@ -30,6 +31,7 @@ class Genode::Page_table_registry public: class Lookup_failed : Exception { }; + class Mapping_cache_full : Exception { }; private: @@ -93,7 +95,11 @@ class Genode::Page_table_registry return; } - _entries.insert(new (entry_alloc) Entry(addr, sel)); + try { + _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) @@ -107,6 +113,14 @@ class Genode::Page_table_registry 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 * diff --git a/repos/base-sel4/src/core/include/vm_space.h b/repos/base-sel4/src/core/include/vm_space.h index 784a0f40b2..ad9487fec5 100644 --- a/repos/base-sel4/src/core/include/vm_space.h +++ b/repos/base-sel4/src/core/include/vm_space.h @@ -148,7 +148,7 @@ class Genode::Vm_space */ 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 */ unsigned pte_idx = _sel_alloc.alloc(); @@ -164,7 +164,19 @@ class Genode::Vm_space Cnode_index(_leaf_cnode_entry(pte_idx))); /* remember relationship between pte_sel and the virtual address */ - _page_table_registry.insert_page_table_entry(to_virt, pte_idx); + try { + _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 @@ -300,7 +312,8 @@ class Genode::Vm_space _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); @@ -310,7 +323,7 @@ class Genode::Vm_space for (size_t i = 0; i < num_pages; i++) { 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); } } diff --git a/repos/base-sel4/src/core/ram_session_support.cc b/repos/base-sel4/src/core/ram_session_support.cc index 961b8f4f52..e21e53b910 100644 --- a/repos/base-sel4/src/core/ram_session_support.cc +++ b/repos/base-sel4/src/core/ram_session_support.cc @@ -12,7 +12,7 @@ */ /* Genode includes */ -#include +#include /* core includes */ #include @@ -43,14 +43,18 @@ void Ram_session_component::_clear_ds (Dataspace_component *ds) /* allocate range in core's virtual address space */ void *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", - page_rounded_size); + error("could not allocate virtual address range in core of size ", + page_rounded_size); return; } /* map the dataspace's physical pages to core-local virtual addresses */ 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 */ size_t num_longwords = page_rounded_size/sizeof(long);