From a8ed11e75bd47aecd6707a4dd9cd4531c2feb577 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Fri, 21 Sep 2018 08:44:23 +0200 Subject: [PATCH] sel4/arm: make alignment faults visible Fixes #2993 --- repos/base-sel4/src/core/include/ipc_pager.h | 11 ++++++++ repos/base-sel4/src/core/include/vm_space.h | 22 +++++++++++----- repos/base-sel4/src/core/pager.cc | 26 ++++++++++++++++--- repos/base-sel4/src/core/platform_pd.cc | 17 +++++++----- .../base-sel4/src/core/spec/arm/fault_info.h | 14 ++++++---- .../base-sel4/src/core/spec/x86/fault_info.h | 1 + 6 files changed, 70 insertions(+), 21 deletions(-) diff --git a/repos/base-sel4/src/core/include/ipc_pager.h b/repos/base-sel4/src/core/include/ipc_pager.h index bc3603103f..ddfa5ffc5f 100644 --- a/repos/base-sel4/src/core/include/ipc_pager.h +++ b/repos/base-sel4/src/core/include/ipc_pager.h @@ -93,6 +93,7 @@ class Genode::Ipc_pager : public Native_capability addr_t _fault_type = 0; /* type of fault */ bool _pf_write = false; /* true on write fault */ bool _pf_exec = false; /* true on exec fault */ + bool _pf_align = false; /* true on unaligned fault */ Mapping _reply_mapping { }; @@ -151,6 +152,16 @@ class Genode::Ipc_pager : public Native_capability * Return true if page fault was on non-executable memory */ bool exec_fault() const { return _pf_exec; } + + /** + * Return true if page fault was due to unaligned memory access + */ + bool align_fault() const { return _pf_align; } + + /** + * Install memory mapping after pager code executed. + */ + bool install_mapping(); }; #endif /* _CORE__INCLUDE__IPC_PAGER_H_ */ diff --git a/repos/base-sel4/src/core/include/vm_space.h b/repos/base-sel4/src/core/include/vm_space.h index 02be221a9a..342bc08f4f 100644 --- a/repos/base-sel4/src/core/include/vm_space.h +++ b/repos/base-sel4/src/core/include/vm_space.h @@ -389,22 +389,30 @@ class Genode::Vm_space _cap_sel_alloc.free(_vm_pad_cnode.sel()); } - void map(addr_t const from_phys, addr_t const to_virt, + bool map(addr_t const from_phys, addr_t const to_virt, size_t const num_pages, Cache_attribute const cacheability, bool const writable, bool const executable, bool flush_support) { Lock::Guard guard(_lock); + bool ok = true; + for (size_t i = 0; i < num_pages; i++) { off_t const offset = i << get_page_size_log2(); - if (!_map_frame(from_phys + offset, to_virt + offset, - cacheability, writable, executable, - flush_support)) - warning("mapping failed ", Hex(from_phys + offset), - " -> ", Hex(to_virt + offset), " ", - !flush_support ? "core" : ""); + if (_map_frame(from_phys + offset, to_virt + offset, + cacheability, writable, executable, + flush_support)) + continue; + + ok = false; + + warning("mapping failed ", Hex(from_phys + offset), + " -> ", Hex(to_virt + offset), " ", + !flush_support ? "core" : ""); } + + return ok; } bool unmap(addr_t const virt, size_t const num_pages, diff --git a/repos/base-sel4/src/core/pager.cc b/repos/base-sel4/src/core/pager.cc index 8ce7d58f61..0ae9a1f150 100644 --- a/repos/base-sel4/src/core/pager.cc +++ b/repos/base-sel4/src/core/pager.cc @@ -47,12 +47,14 @@ void Ipc_pager::wait_for_fault() reply_and_wait_for_fault(); } +bool Ipc_pager::install_mapping() +{ + _badge = Genode::install_mapping(_reply_mapping, _badge); + return _badge; +} void Ipc_pager::reply_and_wait_for_fault() { - if (_badge) - _badge = install_mapping(_reply_mapping, _badge); - seL4_Word badge = Rpc_obj_key::INVALID; seL4_MessageInfo_t page_fault_msg_info; @@ -76,6 +78,7 @@ void Ipc_pager::reply_and_wait_for_fault() _pf_write = fault_info.write; _pf_exec = fault_info.exec_fault(); _fault_type = seL4_MessageInfo_get_label(page_fault_msg_info); + _pf_align = fault_info.align_fault(); _badge = badge; } @@ -187,6 +190,23 @@ void Pager_entrypoint::entry() " ip=", Hex(_pager.fault_ip()), " pf-addr=", Hex(_pager.fault_addr())); _pager.reply_save_caller(obj->reply_cap_sel()); + return; + } + + try { + /* install memory mappings */ + if (_pager.install_mapping()) + return; + + /* on alignment fault don't reply and submit signal */ + if (_pager.align_fault()) { + warning("alignment fault, addr=", Hex(_pager.fault_addr()), + " ip=", Hex(_pager.fault_ip())); + throw 1; + } + } catch (...) { + reply_pending = false; + obj->submit_exception_signal(); } }); } diff --git a/repos/base-sel4/src/core/platform_pd.cc b/repos/base-sel4/src/core/platform_pd.cc index 26e49d479b..5b35b1d9e2 100644 --- a/repos/base-sel4/src/core/platform_pd.cc +++ b/repos/base-sel4/src/core/platform_pd.cc @@ -160,10 +160,14 @@ bool Platform_pd::install_mapping(Mapping const &mapping, _vm_space.alloc_page_tables(mapping.to_virt(), mapping.num_pages() * get_page_size()); - _vm_space.map(mapping.from_phys(), mapping.to_virt(), - mapping.num_pages(), mapping.cacheability(), - mapping.writeable(), mapping.executable(), FLUSHABLE); - return true; + if (_vm_space.map(mapping.from_phys(), mapping.to_virt(), + mapping.num_pages(), mapping.cacheability(), + mapping.writeable(), mapping.executable(), FLUSHABLE)) + return true; + + Genode::warning("mapping failure for thread '", thread_name, + "' in pd '", _vm_space.pd_label(), "'"); + return false; } catch (...) { char const * fault_name = "unknown"; @@ -185,11 +189,12 @@ bool Platform_pd::install_mapping(Mapping const &mapping, break; } - /* pager ep would die when we re-throw - let core survive */ Genode::error("unexpected exception during fault '", fault_name, "'", " - thread '", thread_name, "' in pd '", _vm_space.pd_label(),"' stopped"); - return false; + + /* catched by Pager_entrypoint::entry() in base-sel4/pager.cc */ + throw; } } diff --git a/repos/base-sel4/src/core/spec/arm/fault_info.h b/repos/base-sel4/src/core/spec/arm/fault_info.h index ce9011b7ea..4a6ceebaa0 100644 --- a/repos/base-sel4/src/core/spec/arm/fault_info.h +++ b/repos/base-sel4/src/core/spec/arm/fault_info.h @@ -13,14 +13,16 @@ struct Fault_info { - Genode::addr_t ip = 0; - Genode::addr_t pf = 0; - bool data_abort = 0; - bool write = 0; + Genode::addr_t const ip; + Genode::addr_t const pf; + bool data_abort; + bool const write; + bool const align; enum { IFSR_FAULT = 1, IFSR_FAULT_PERMISSION = 0xf, + DFSR_ALIGN_FAULT = 1UL << 0, DFSR_WRITE_FAULT = 1UL << 11 }; @@ -30,11 +32,13 @@ struct Fault_info pf(seL4_GetMR(1)), data_abort(seL4_GetMR(2) != IFSR_FAULT), /* Instruction Fault Status Register (IFSR) resp. Data FSR (DFSR) */ - write(data_abort && (seL4_GetMR(3) & DFSR_WRITE_FAULT)) + write(data_abort && (seL4_GetMR(3) & DFSR_WRITE_FAULT)), + align(data_abort && (seL4_GetMR(3) == DFSR_ALIGN_FAULT)) { if (!data_abort && seL4_GetMR(3) != IFSR_FAULT_PERMISSION) data_abort = true; } bool exec_fault() const { return !data_abort; } + bool align_fault() const { return align; } }; diff --git a/repos/base-sel4/src/core/spec/x86/fault_info.h b/repos/base-sel4/src/core/spec/x86/fault_info.h index d765fe34c5..00e7be1822 100644 --- a/repos/base-sel4/src/core/spec/x86/fault_info.h +++ b/repos/base-sel4/src/core/spec/x86/fault_info.h @@ -37,4 +37,5 @@ struct Fault_info { } bool exec_fault() const { return false; } + bool align_fault() const { return false; } };