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 */
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_ */

View File

@ -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,

View File

@ -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();
}
});
}

View File

@ -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;
}
}

View File

@ -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; }
};

View File

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