diff --git a/repos/base-sel4/patches/arm_cache.patch b/repos/base-sel4/patches/arm_cache.patch index 3ea96e9eb1..3fa8b2379e 100644 --- a/repos/base-sel4/patches/arm_cache.patch +++ b/repos/base-sel4/patches/arm_cache.patch @@ -1,6 +1,6 @@ --- src/kernel/sel4/libsel4/arch_include/arm/sel4/arch/types.h +++ src/kernel/sel4/libsel4/arch_include/arm/sel4/arch/types.h -@@ -24,6 +24,7 @@ +@@ -26,10 +26,12 @@ typedef seL4_CPtr seL4_ARM_IOPageTable; typedef enum { @@ -8,3 +8,8 @@ seL4_ARM_PageCacheable = 0x01, seL4_ARM_ParityEnabled = 0x02, seL4_ARM_Default_VMAttributes = 0x03, + seL4_ARM_ExecuteNever = 0x04, ++ seL4_ARM_Default_VMAttributes_NoExecute = 0x07, + /* seL4_ARM_PageCacheable | seL4_ARM_ParityEnabled */ + SEL4_FORCE_LONG_ENUM(seL4_ARM_VMAttributes), + } seL4_ARM_VMAttributes; diff --git a/repos/base-sel4/ports/sel4.hash b/repos/base-sel4/ports/sel4.hash index 8fae257642..3bbeb1e8b2 100644 --- a/repos/base-sel4/ports/sel4.hash +++ b/repos/base-sel4/ports/sel4.hash @@ -1 +1 @@ -b00bc949a62cc71b45191b19c966f3a542b25c20 +fac219549e9515349e61deae22a199ae3196e67a diff --git a/repos/base-sel4/src/core/include/ipc_pager.h b/repos/base-sel4/src/core/include/ipc_pager.h index b3939b0078..e332c3a3a5 100644 --- a/repos/base-sel4/src/core/include/ipc_pager.h +++ b/repos/base-sel4/src/core/include/ipc_pager.h @@ -18,135 +18,139 @@ #include #include -namespace Genode { class Ipc_pager; } - namespace Genode { - - class Mapping - { - friend class Ipc_pager; - - private: - - addr_t _from_phys_addr; - addr_t _to_virt_addr; - Cache_attribute _attr; - size_t _num_pages; - bool _writeable; - addr_t _fault_type = { 0 }; - - enum { PAGE_SIZE_LOG2 = 12 }; - - public: - - /** - * Constructor - */ - Mapping(addr_t dst_addr, addr_t src_addr, - Cache_attribute const cacheability, bool io_mem, - unsigned l2size, bool rw, bool executable) - : - _from_phys_addr(src_addr), - _to_virt_addr(dst_addr), - _attr(cacheability), - _num_pages(1 << (l2size - PAGE_SIZE_LOG2)), - _writeable(rw) - { } - - /** - * Construct invalid mapping - */ - Mapping() : _num_pages(0) { } - - /** - * Prepare map operation - * - * No preparations are needed on seL4 because all mapping - * originate from the physical address space. - */ - void prepare_map_operation() { } - - addr_t from_phys() const { return _from_phys_addr; } - addr_t to_virt() const { return _to_virt_addr; } - size_t num_pages() const { return _num_pages; } - bool writeable() const { return _writeable; } - Cache_attribute cacheability() const { return _attr; } - addr_t fault_type() const { return _fault_type; } - }; - - - /** - * Special paging server class - */ - class Ipc_pager : public Native_capability - { - private: - - addr_t _badge; /* faulted badge of thread */ - addr_t _reply_sel; /* selector to save reply cap */ - addr_t _pf_addr; /* page-fault address */ - addr_t _pf_ip; /* instruction pointer of faulter */ - bool _pf_write; /* true on write fault */ - addr_t _fault_type; /* type of fault */ - - Mapping _reply_mapping; - - public: - - /** - * Constructor - */ - Ipc_pager(); - - /** - * Wait for a new page fault received as short message IPC - */ - void wait_for_fault(); - - /** - * Reply current page-fault and wait for a new one - */ - void reply_and_wait_for_fault(); - - /** - * Request instruction pointer of current page fault - */ - addr_t fault_ip() { return _pf_ip; } - - /** - * Request fault address of current page fault - */ - addr_t fault_addr() { return _pf_addr; } - - /** - * Set parameters for next reply - */ - void set_reply_mapping(Mapping m) - { - _reply_mapping = m; - _reply_mapping._fault_type = _fault_type; - } - - /** - * Set destination for next reply - */ - void reply_save_caller(addr_t sel) { _reply_sel = sel; } - - /** - * Return badge for faulting thread - */ - unsigned long badge() const { return _badge; } - - /** - * Return true if page fault was a write fault - */ - bool write_fault() const { return _pf_write; } - - /** - * Return true if page fault was on non-executable memory - */ - bool exec_fault() const { return false; } - }; + class Mapping; + class Ipc_pager; } + +class Genode::Mapping +{ + friend class Ipc_pager; + + private: + + addr_t _from_phys_addr; + addr_t _to_virt_addr; + Cache_attribute _attr; + size_t _num_pages; + addr_t _fault_type = { 0 }; + bool _writeable = { false }; + bool _executable = { false }; + + enum { PAGE_SIZE_LOG2 = 12 }; + + public: + + /** + * Constructor + */ + Mapping(addr_t dst_addr, addr_t src_addr, + Cache_attribute const cacheability, bool io_mem, + unsigned l2size, bool rw, bool executable) + : + _from_phys_addr(src_addr), + _to_virt_addr(dst_addr), + _attr(cacheability), + _num_pages(1 << (l2size - PAGE_SIZE_LOG2)), + _writeable(rw), _executable(executable) + { } + + /** + * Construct invalid mapping + */ + Mapping() : _num_pages(0) { } + + /** + * Prepare map operation + * + * No preparations are needed on seL4 because all mapping + * originate from the physical address space. + */ + void prepare_map_operation() { } + + addr_t from_phys() const { return _from_phys_addr; } + addr_t to_virt() const { return _to_virt_addr; } + size_t num_pages() const { return _num_pages; } + bool writeable() const { return _writeable; } + bool executable() const { return _executable; } + Cache_attribute cacheability() const { return _attr; } + addr_t fault_type() const { return _fault_type; } +}; + + +/** + * Special paging server class + */ +class Genode::Ipc_pager : public Native_capability +{ + private: + + addr_t _badge; /* faulted badge of thread */ + addr_t _reply_sel; /* selector to save reply cap */ + addr_t _pf_addr; /* page-fault address */ + addr_t _pf_ip; /* instruction pointer of faulter */ + addr_t _fault_type; /* type of fault */ + bool _pf_write; /* true on write fault */ + bool _pf_exec; /* true on exec fault */ + + Mapping _reply_mapping; + + public: + + /** + * Constructor + */ + Ipc_pager(); + + /** + * Wait for a new page fault received as short message IPC + */ + void wait_for_fault(); + + /** + * Reply current page-fault and wait for a new one + */ + void reply_and_wait_for_fault(); + + /** + * Request instruction pointer of current page fault + */ + addr_t fault_ip() { return _pf_ip; } + + /** + * Request fault address of current page fault + */ + addr_t fault_addr() { return _pf_addr; } + + /** + * Set parameters for next reply + */ + void set_reply_mapping(Mapping m) + { + _reply_mapping = m; + _reply_mapping._fault_type = _fault_type; + } + + /** + * Set destination for next reply + */ + void reply_save_caller(addr_t sel) { _reply_sel = sel; } + + /** + * Return badge for faulting thread + */ + unsigned long badge() const { return _badge; } + + /** + * Return true if page fault was a write fault + */ + bool write_fault() const { return _pf_write; } + + /** + * Return true if page fault was on non-executable memory + */ + bool exec_fault() const { return _pf_exec; } +}; + #endif /* _CORE__INCLUDE__IPC_PAGER_H_ */ diff --git a/repos/base-sel4/src/core/include/map_local.h b/repos/base-sel4/src/core/include/map_local.h index 8a59e58e59..5c328f89bf 100644 --- a/repos/base-sel4/src/core/include/map_local.h +++ b/repos/base-sel4/src/core/include/map_local.h @@ -36,12 +36,13 @@ namespace Genode { inline bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, Platform * platform = nullptr) { - enum { DONT_FLUSH = false, WRITEABLE = true }; + enum { DONT_FLUSH = false, WRITEABLE = true, NON_EXECUTABLE = false }; try { platform = platform ? platform : platform_specific(); platform->core_vm_space().map(from_phys, to_virt, num_pages, Cache_attribute::CACHED, - WRITEABLE, DONT_FLUSH); + WRITEABLE, NON_EXECUTABLE, + DONT_FLUSH); } catch (Page_table_registry::Mapping_cache_full) { return false; } diff --git a/repos/base-sel4/src/core/include/vm_space.h b/repos/base-sel4/src/core/include/vm_space.h index 2849d98c69..a84735cca6 100644 --- a/repos/base-sel4/src/core/include/vm_space.h +++ b/repos/base-sel4/src/core/include/vm_space.h @@ -157,7 +157,8 @@ class Genode::Vm_space bool _map_frame(addr_t const from_phys, addr_t const to_virt, Cache_attribute const cacheability, - bool const writable, bool const flush_support) + bool const writable, bool const executable, + bool const flush_support) { if (_page_table_registry.page_frame_at(to_virt)) { /* @@ -228,7 +229,7 @@ class Genode::Vm_space * Insert copy of page-frame selector into page table */ long ret = _map_page(Cap_sel(pte_idx), to_virt, cacheability, - writable); + writable, executable); if (ret != seL4_NoError) { error("seL4_*_Page_Map ", Hex(from_phys), "->", Hex(to_virt), " returned ", ret); @@ -241,7 +242,8 @@ class Genode::Vm_space * Platform specific map/unmap of a page frame */ long _map_page(Genode::Cap_sel const &idx, Genode::addr_t const virt, - Cache_attribute const cacheability, bool const write); + Cache_attribute const cacheability, bool const write, + bool const writable); long _unmap_page(Genode::Cap_sel const &idx); class Alloc_page_table_failed : Exception { }; @@ -374,7 +376,7 @@ class Genode::Vm_space void map(addr_t const from_phys, addr_t const to_virt, size_t const num_pages, Cache_attribute const cacheability, - bool const writable, bool flush_support) + bool const writable, bool const executable, bool flush_support) { Lock::Guard guard(_lock); @@ -382,7 +384,8 @@ class Genode::Vm_space off_t const offset = i << get_page_size_log2(); if (!_map_frame(from_phys + offset, to_virt + offset, - cacheability, writable, flush_support)) + cacheability, writable, executable, + flush_support)) error("mapping failed ", Hex(from_phys + offset), " -> ", Hex(to_virt + offset)); } diff --git a/repos/base-sel4/src/core/pager.cc b/repos/base-sel4/src/core/pager.cc index fd0f07c840..8ae86614a3 100644 --- a/repos/base-sel4/src/core/pager.cc +++ b/repos/base-sel4/src/core/pager.cc @@ -74,6 +74,7 @@ void Ipc_pager::reply_and_wait_for_fault() _pf_ip = fault_info.ip; _pf_addr = fault_info.pf; _pf_write = fault_info.write; + _pf_exec = fault_info.exec_fault(); _fault_type = seL4_MessageInfo_get_label(page_fault_msg_info); _badge = badge; diff --git a/repos/base-sel4/src/core/platform_pd.cc b/repos/base-sel4/src/core/platform_pd.cc index 5d354b97bf..b06074e3c7 100644 --- a/repos/base-sel4/src/core/platform_pd.cc +++ b/repos/base-sel4/src/core/platform_pd.cc @@ -89,10 +89,10 @@ bool Platform_pd::bind_thread(Platform_thread *thread) */ addr_t const utcb = (thread->_utcb) ? thread->_utcb : thread->INITIAL_IPC_BUFFER_VIRT; - enum { WRITABLE = true, ONE_PAGE = 1, FLUSHABLE = true }; + enum { WRITABLE = true, ONE_PAGE = 1, FLUSHABLE = true, NON_EXECUTABLE = false }; _vm_space.alloc_page_tables(utcb, get_page_size()); _vm_space.map(thread->_info.ipc_buffer_phys, utcb, ONE_PAGE, - Cache_attribute::CACHED, WRITABLE, FLUSHABLE); + Cache_attribute::CACHED, WRITABLE, NON_EXECUTABLE, FLUSHABLE); return true; } @@ -161,7 +161,7 @@ bool Platform_pd::install_mapping(Mapping const &mapping, _vm_space.map(mapping.from_phys(), mapping.to_virt(), mapping.num_pages(), mapping.cacheability(), - mapping.writeable(), FLUSHABLE); + mapping.writeable(), mapping.executable(), FLUSHABLE); return true; } catch (...) { char const * fault_name = "unknown"; 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 22f65438d3..5f598ea756 100644 --- a/repos/base-sel4/src/core/spec/arm/fault_info.h +++ b/repos/base-sel4/src/core/spec/arm/fault_info.h @@ -18,12 +18,23 @@ struct Fault_info bool data_abort = 0; bool write = 0; + enum { + IFSR_FAULT = 1, + IFSR_FAULT_PERMISSION = 0xf, + DFSR_WRITE_FAULT = 1UL << 11 + }; + Fault_info(seL4_MessageInfo_t msg_info) : ip(seL4_GetMR(0)), pf(seL4_GetMR(1)), - data_abort(seL4_GetMR(2) != 1), + data_abort(seL4_GetMR(2) != IFSR_FAULT), /* Instruction Fault Status Register (IFSR) resp. Data FSR (DFSR) */ - write(data_abort && (seL4_GetMR(3) & (1 << 11))) - { } + write(data_abort && (seL4_GetMR(3) & DFSR_WRITE_FAULT)) + { + if (!data_abort && seL4_GetMR(3) != IFSR_FAULT_PERMISSION) + data_abort = true; + } + + bool exec_fault() const { return !data_abort; } }; diff --git a/repos/base-sel4/src/core/spec/arm/vm_space.cc b/repos/base-sel4/src/core/spec/arm/vm_space.cc index 1b9d2e35f9..22b213b56f 100644 --- a/repos/base-sel4/src/core/spec/arm/vm_space.cc +++ b/repos/base-sel4/src/core/spec/arm/vm_space.cc @@ -27,12 +27,13 @@ static long map_page_table(Genode::Cap_sel const pagetable, long Genode::Vm_space::_map_page(Genode::Cap_sel const &idx, Genode::addr_t const virt, Cache_attribute const cacheability, - bool const writable) + bool const writable, + bool const executable) { seL4_ARM_Page const service = _idx_to_sel(idx.value()); seL4_ARM_PageDirectory const pd = _pd_sel.value(); seL4_CapRights_t const rights = writable ? seL4_ReadWrite : seL4_CanRead; - seL4_ARM_VMAttributes attr = seL4_ARM_Default_VMAttributes; + seL4_ARM_VMAttributes attr = executable ? seL4_ARM_Default_VMAttributes : seL4_ARM_Default_VMAttributes_NoExecute; if (cacheability == UNCACHED) attr = seL4_ARM_Uncacheable; 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 fae42e868e..6527678d6c 100644 --- a/repos/base-sel4/src/core/spec/x86/fault_info.h +++ b/repos/base-sel4/src/core/spec/x86/fault_info.h @@ -35,4 +35,6 @@ struct Fault_info pf(seL4_GetMR(1)), write(seL4_GetMR(3) & ERR_W) { } + + bool exec_fault() const { return false; } }; diff --git a/repos/base-sel4/src/core/spec/x86/vm_space.cc b/repos/base-sel4/src/core/spec/x86/vm_space.cc index 34f6d89e09..2c04c14071 100644 --- a/repos/base-sel4/src/core/spec/x86/vm_space.cc +++ b/repos/base-sel4/src/core/spec/x86/vm_space.cc @@ -17,7 +17,8 @@ long Genode::Vm_space::_map_page(Genode::Cap_sel const &idx, Genode::addr_t const virt, Cache_attribute const cacheability, - bool const writable) + bool const writable, + bool const executable) { seL4_X86_Page const service = _idx_to_sel(idx.value()); seL4_X86_PageDirectory const pd = _pd_sel.value(); diff --git a/repos/base/run/rm_fault.run b/repos/base/run/rm_fault.run index 932a2d0b00..e318addff9 100644 --- a/repos/base/run/rm_fault.run +++ b/repos/base/run/rm_fault.run @@ -12,6 +12,7 @@ proc non_executable_supported { } { if {[have_spec nova] && [have_spec x86_64]} { return true } if {[have_spec foc] && [have_spec x86_64]} { return true } if {[have_spec foc] && [have_spec arm]} { return true } + if {[have_spec sel4] && [have_spec arm]} { return true } return false }