sel4/arm: make alignment faults visible

Fixes #2993
This commit is contained in:
Alexander Boettcher 2018-09-21 08:44:23 +02:00 committed by Christian Helmuth
parent 24a2b15eec
commit a8ed11e75b
6 changed files with 70 additions and 21 deletions

View File

@ -93,6 +93,7 @@ class Genode::Ipc_pager : public Native_capability
addr_t _fault_type = 0; /* type of fault */ addr_t _fault_type = 0; /* type of fault */
bool _pf_write = false; /* true on write fault */ bool _pf_write = false; /* true on write fault */
bool _pf_exec = false; /* true on exec fault */ bool _pf_exec = false; /* true on exec fault */
bool _pf_align = false; /* true on unaligned fault */
Mapping _reply_mapping { }; Mapping _reply_mapping { };
@ -151,6 +152,16 @@ class Genode::Ipc_pager : public Native_capability
* Return true if page fault was on non-executable memory * Return true if page fault was on non-executable memory
*/ */
bool exec_fault() const { return _pf_exec; } 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_ */ #endif /* _CORE__INCLUDE__IPC_PAGER_H_ */

View File

@ -389,22 +389,30 @@ class Genode::Vm_space
_cap_sel_alloc.free(_vm_pad_cnode.sel()); _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, size_t const num_pages, Cache_attribute const cacheability,
bool const writable, bool const executable, bool flush_support) bool const writable, bool const executable, bool flush_support)
{ {
Lock::Guard guard(_lock); Lock::Guard guard(_lock);
bool ok = true;
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();
if (!_map_frame(from_phys + offset, to_virt + offset, if (_map_frame(from_phys + offset, to_virt + offset,
cacheability, writable, executable, cacheability, writable, executable,
flush_support)) flush_support))
continue;
ok = false;
warning("mapping failed ", Hex(from_phys + offset), warning("mapping failed ", Hex(from_phys + offset),
" -> ", Hex(to_virt + offset), " ", " -> ", Hex(to_virt + offset), " ",
!flush_support ? "core" : ""); !flush_support ? "core" : "");
} }
return ok;
} }
bool unmap(addr_t const virt, size_t const num_pages, bool unmap(addr_t const virt, size_t const num_pages,

View File

@ -47,12 +47,14 @@ void Ipc_pager::wait_for_fault()
reply_and_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() void Ipc_pager::reply_and_wait_for_fault()
{ {
if (_badge)
_badge = install_mapping(_reply_mapping, _badge);
seL4_Word badge = Rpc_obj_key::INVALID; seL4_Word badge = Rpc_obj_key::INVALID;
seL4_MessageInfo_t page_fault_msg_info; 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_write = fault_info.write;
_pf_exec = fault_info.exec_fault(); _pf_exec = fault_info.exec_fault();
_fault_type = seL4_MessageInfo_get_label(page_fault_msg_info); _fault_type = seL4_MessageInfo_get_label(page_fault_msg_info);
_pf_align = fault_info.align_fault();
_badge = badge; _badge = badge;
} }
@ -187,6 +190,23 @@ void Pager_entrypoint::entry()
" ip=", Hex(_pager.fault_ip()), " ip=", Hex(_pager.fault_ip()),
" pf-addr=", Hex(_pager.fault_addr())); " pf-addr=", Hex(_pager.fault_addr()));
_pager.reply_save_caller(obj->reply_cap_sel()); _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();
} }
}); });
} }

View File

@ -160,10 +160,14 @@ bool Platform_pd::install_mapping(Mapping const &mapping,
_vm_space.alloc_page_tables(mapping.to_virt(), _vm_space.alloc_page_tables(mapping.to_virt(),
mapping.num_pages() * get_page_size()); mapping.num_pages() * get_page_size());
_vm_space.map(mapping.from_phys(), mapping.to_virt(), if (_vm_space.map(mapping.from_phys(), mapping.to_virt(),
mapping.num_pages(), mapping.cacheability(), mapping.num_pages(), mapping.cacheability(),
mapping.writeable(), mapping.executable(), FLUSHABLE); mapping.writeable(), mapping.executable(), FLUSHABLE))
return true; return true;
Genode::warning("mapping failure for thread '", thread_name,
"' in pd '", _vm_space.pd_label(), "'");
return false;
} catch (...) { } catch (...) {
char const * fault_name = "unknown"; char const * fault_name = "unknown";
@ -185,11 +189,12 @@ bool Platform_pd::install_mapping(Mapping const &mapping,
break; break;
} }
/* pager ep would die when we re-throw - let core survive */
Genode::error("unexpected exception during fault '", fault_name, "'", Genode::error("unexpected exception during fault '", fault_name, "'",
" - thread '", thread_name, "' in pd '", " - thread '", thread_name, "' in pd '",
_vm_space.pd_label(),"' stopped"); _vm_space.pd_label(),"' stopped");
return false;
/* catched by Pager_entrypoint::entry() in base-sel4/pager.cc */
throw;
} }
} }

View File

@ -13,14 +13,16 @@
struct Fault_info struct Fault_info
{ {
Genode::addr_t ip = 0; Genode::addr_t const ip;
Genode::addr_t pf = 0; Genode::addr_t const pf;
bool data_abort = 0; bool data_abort;
bool write = 0; bool const write;
bool const align;
enum { enum {
IFSR_FAULT = 1, IFSR_FAULT = 1,
IFSR_FAULT_PERMISSION = 0xf, IFSR_FAULT_PERMISSION = 0xf,
DFSR_ALIGN_FAULT = 1UL << 0,
DFSR_WRITE_FAULT = 1UL << 11 DFSR_WRITE_FAULT = 1UL << 11
}; };
@ -30,11 +32,13 @@ struct Fault_info
pf(seL4_GetMR(1)), pf(seL4_GetMR(1)),
data_abort(seL4_GetMR(2) != IFSR_FAULT), data_abort(seL4_GetMR(2) != IFSR_FAULT),
/* Instruction Fault Status Register (IFSR) resp. Data FSR (DFSR) */ /* 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) if (!data_abort && seL4_GetMR(3) != IFSR_FAULT_PERMISSION)
data_abort = true; data_abort = true;
} }
bool exec_fault() const { return !data_abort; } bool exec_fault() const { return !data_abort; }
bool align_fault() const { return align; }
}; };

View File

@ -37,4 +37,5 @@ struct Fault_info
{ } { }
bool exec_fault() const { return false; } bool exec_fault() const { return false; }
bool align_fault() const { return false; }
}; };