mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-21 00:23:16 +00:00
core: rework page-fault resolution
The change "core: allow offset-attached managed dataspaces" addressed a corner case of the use of nested region maps. Apparently, this change negatively affects other scenarios (tool_chain_auto). In order to confidently cover all the differnt situations, this patch reworks the page-fault resolution code for improved clarity and safety, by introducing dedicated result types, reducing the use of basic types, choosing expressive names, and fostering constness. It also introduces a number of 'print' hooks that greatly ease manual instrumentation and streamlines the error messages printed by core. Those messages no longer appear when a user-level page-fault handler is reistered for the faulted-at region map. So the monitor component produces less noise on the attempt to dump non-existing memory. Issue #4917 Fixes #4920
This commit is contained in:
@ -112,7 +112,8 @@ class Core::Platform : public Platform_generic
|
|||||||
*/
|
*/
|
||||||
Sigma0();
|
Sigma0();
|
||||||
|
|
||||||
int pager(Ipc_pager &) override { /* never called */ return -1; }
|
/* never called */
|
||||||
|
Pager_result pager(Ipc_pager &) override { return Pager_result::STOP; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,7 +131,8 @@ class Core::Platform : public Platform_generic
|
|||||||
*/
|
*/
|
||||||
Core_pager(Platform_pd &core_pd);
|
Core_pager(Platform_pd &core_pd);
|
||||||
|
|
||||||
int pager(Ipc_pager &) override { /* never called */ return -1; }
|
/* never called */
|
||||||
|
Pager_result pager(Ipc_pager &) override { return Pager_result::STOP; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,7 +98,7 @@ namespace Core {
|
|||||||
inline addr_t map_src_addr(addr_t core_local_addr, addr_t) {
|
inline addr_t map_src_addr(addr_t core_local_addr, addr_t) {
|
||||||
return core_local_addr; }
|
return core_local_addr; }
|
||||||
|
|
||||||
inline size_t constrain_map_size_log2(size_t size_log2) { return size_log2; }
|
inline Log2 kernel_constrained_map_size(Log2 size) { return size; }
|
||||||
|
|
||||||
inline unsigned long convert_native_thread_id_to_badge(Fiasco::l4_threadid_t tid)
|
inline unsigned long convert_native_thread_id_to_badge(Fiasco::l4_threadid_t tid)
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,8 @@ class Core::Platform : public Platform_generic
|
|||||||
*/
|
*/
|
||||||
Sigma0(Cap_index*);
|
Sigma0(Cap_index*);
|
||||||
|
|
||||||
int pager(Ipc_pager &) override { /* never called */ return -1; }
|
/* never called */
|
||||||
|
Pager_result pager(Ipc_pager &) override { return Pager_result::STOP; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -132,7 +133,8 @@ class Core::Platform : public Platform_generic
|
|||||||
*/
|
*/
|
||||||
Core_pager(Platform_pd &core_pd, Sigma0 &);
|
Core_pager(Platform_pd &core_pd, Sigma0 &);
|
||||||
|
|
||||||
int pager(Ipc_pager &) override { /* never called */ return -1; }
|
/* never called */
|
||||||
|
Pager_result pager(Ipc_pager &) override { return Pager_result::STOP; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,7 +73,7 @@ namespace Core {
|
|||||||
inline addr_t map_src_addr(addr_t core_local_addr, addr_t) {
|
inline addr_t map_src_addr(addr_t core_local_addr, addr_t) {
|
||||||
return core_local_addr; }
|
return core_local_addr; }
|
||||||
|
|
||||||
inline size_t constrain_map_size_log2(size_t size_log2) { return size_log2; }
|
inline Log2 kernel_constrained_map_size(Log2 size) { return size; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__UTIL_H_ */
|
#endif /* _CORE__INCLUDE__UTIL_H_ */
|
||||||
|
@ -60,12 +60,7 @@ void Pager_entrypoint::entry()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* handle request */
|
/* handle request */
|
||||||
if (obj->pager(_pager)) {
|
if (obj->pager(_pager) == Pager_object::Pager_result::CONTINUE) {
|
||||||
/* could not resolv - leave thread in pagefault */
|
|
||||||
warning("page-fault, ", *obj,
|
|
||||||
" ip=", Hex(_pager.fault_ip()),
|
|
||||||
" pf-addr=", Hex(_pager.fault_addr()));
|
|
||||||
} else {
|
|
||||||
_pager.set_reply_dst(Native_thread(obj->badge()));
|
_pager.set_reply_dst(Native_thread(obj->badge()));
|
||||||
reply_pending = true;
|
reply_pending = true;
|
||||||
return;
|
return;
|
||||||
|
@ -64,13 +64,7 @@ void Pager_object::start_paging(Kernel_object<Kernel::Signal_receiver> & receive
|
|||||||
void Pager_object::exception_handler(Signal_context_capability) { }
|
void Pager_object::exception_handler(Signal_context_capability) { }
|
||||||
|
|
||||||
|
|
||||||
void Pager_object::unresolved_page_fault_occurred()
|
void Pager_object::unresolved_page_fault_occurred() { }
|
||||||
{
|
|
||||||
Platform_thread * const pt = (Platform_thread *)badge();
|
|
||||||
if (pt && pt->pd())
|
|
||||||
warning("page fault, pager_object: pd='", pt->pd()->label(),
|
|
||||||
"' thread='", pt->label(), "' ", pt->fault_info());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Pager_object::print(Output &out) const
|
void Pager_object::print(Output &out) const
|
||||||
|
@ -151,6 +151,8 @@ class Core::Pager_object : private Object_pool<Pager_object>::Entry,
|
|||||||
** Pure virtual **
|
** Pure virtual **
|
||||||
******************/
|
******************/
|
||||||
|
|
||||||
|
enum class Pager_result { STOP, CONTINUE };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request a mapping that resolves a fault directly
|
* Request a mapping that resolves a fault directly
|
||||||
*
|
*
|
||||||
@ -159,7 +161,7 @@ class Core::Pager_object : private Object_pool<Pager_object>::Entry,
|
|||||||
* \retval 0 succeeded
|
* \retval 0 succeeded
|
||||||
* \retval !=0 fault can't be received directly
|
* \retval !=0 fault can't be received directly
|
||||||
*/
|
*/
|
||||||
virtual int pager(Ipc_pager & p) = 0;
|
virtual Pager_result pager(Ipc_pager & p) = 0;
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
|
@ -46,7 +46,8 @@ void Pager_entrypoint::entry()
|
|||||||
_fault = pt->fault_info();
|
_fault = pt->fault_info();
|
||||||
|
|
||||||
/* try to resolve fault directly via local region managers */
|
/* try to resolve fault directly via local region managers */
|
||||||
if (po->pager(*this)) continue;
|
if (po->pager(*this) == Pager_object::Pager_result::STOP)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* apply mapping that was determined by the local region managers */
|
/* apply mapping that was determined by the local region managers */
|
||||||
{
|
{
|
||||||
|
@ -43,8 +43,10 @@ namespace Core {
|
|||||||
* as 4K and 4M, this function should select one of those smaller or
|
* as 4K and 4M, this function should select one of those smaller or
|
||||||
* equal to the argument.
|
* equal to the argument.
|
||||||
*/
|
*/
|
||||||
constexpr size_t constrain_map_size_log2(size_t size_log2) {
|
static constexpr Log2 kernel_constrained_map_size(Log2 size)
|
||||||
return (size_log2 < 20) ? 12 : 20; }
|
{
|
||||||
|
return { (size.log2 < 20) ? uint8_t(12) : uint8_t(20) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _CORE__UTIL_H_ */
|
#endif /* _CORE__UTIL_H_ */
|
||||||
|
@ -185,7 +185,9 @@ class Core::Pager_object : public Object_pool<Pager_object>::Entry
|
|||||||
const char * client_thread() const;
|
const char * client_thread() const;
|
||||||
const char * client_pd() const;
|
const char * client_pd() const;
|
||||||
|
|
||||||
virtual int pager(Ipc_pager &ps) = 0;
|
enum class Pager_result { STOP, CONTINUE };
|
||||||
|
|
||||||
|
virtual Pager_result pager(Ipc_pager &ps) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign user-level exception handler for the pager object
|
* Assign user-level exception handler for the pager object
|
||||||
|
@ -27,19 +27,17 @@ namespace Core {
|
|||||||
constexpr size_t get_super_page_size() { return 1 << get_super_page_size_log2(); }
|
constexpr size_t get_super_page_size() { return 1 << get_super_page_size_log2(); }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T trunc_page(T addr) { return addr & _align_mask(get_page_size_log2()); }
|
inline T trunc_page(T addr) { return addr & _align_mask(size_t(get_page_size_log2())); }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T round_page(T addr) { return trunc_page(addr + get_page_size() - 1); }
|
inline T round_page(T addr) { return trunc_page(addr + get_page_size() - 1); }
|
||||||
|
|
||||||
inline addr_t map_src_addr(addr_t /* core_local */, addr_t phys) { return phys; }
|
inline addr_t map_src_addr(addr_t /* core_local */, addr_t phys) { return phys; }
|
||||||
|
|
||||||
|
inline Log2 kernel_constrained_map_size(Log2 size)
|
||||||
inline size_t constrain_map_size_log2(size_t size_log2)
|
|
||||||
{
|
{
|
||||||
/* Nova::Mem_crd order has 5 bits available and is in 4K page units */
|
/* Nova::Mem_crd order has 5 bits available and is in 4K page units */
|
||||||
enum { MAX_MAP_LOG2 = (1U << 5) - 1 + 12 };
|
return { min(size.log2, uint8_t((1 << 5) - 1 + 12)) };
|
||||||
return size_log2 > MAX_MAP_LOG2 ? (size_t)MAX_MAP_LOG2 : size_log2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline unsigned scale_priority(unsigned const prio, char const * name)
|
inline unsigned scale_priority(unsigned const prio, char const * name)
|
||||||
|
@ -150,7 +150,7 @@ void Pager_object::_page_fault_handler(Pager_object &obj)
|
|||||||
obj._state.block_pause_sm();
|
obj._state.block_pause_sm();
|
||||||
|
|
||||||
/* lookup fault address and decide what to do */
|
/* lookup fault address and decide what to do */
|
||||||
int error = obj.pager(ipc_pager);
|
unsigned error = (obj.pager(ipc_pager) == Pager_object::Pager_result::STOP);
|
||||||
|
|
||||||
/* don't open receive window for pager threads */
|
/* don't open receive window for pager threads */
|
||||||
if (utcb.crd_rcv.value())
|
if (utcb.crd_rcv.value())
|
||||||
@ -194,10 +194,6 @@ void Pager_object::_page_fault_handler(Pager_object &obj)
|
|||||||
ipc_pager.fault_addr(),
|
ipc_pager.fault_addr(),
|
||||||
ipc_pager.sp(),
|
ipc_pager.sp(),
|
||||||
(uint8_t)ipc_pager.fault_type());
|
(uint8_t)ipc_pager.fault_type());
|
||||||
|
|
||||||
/* region manager fault - to be handled */
|
|
||||||
log("page fault, ", fault_info, " reason=", error);
|
|
||||||
|
|
||||||
obj._state_lock.release();
|
obj._state_lock.release();
|
||||||
|
|
||||||
/* block the faulting thread until region manager is done */
|
/* block the faulting thread until region manager is done */
|
||||||
|
@ -35,33 +35,13 @@ bool Pd_session_component::assign_pci(addr_t pci_config_memory, uint16_t bdf)
|
|||||||
|
|
||||||
void Pd_session_component::map(addr_t virt, addr_t size)
|
void Pd_session_component::map(addr_t virt, addr_t size)
|
||||||
{
|
{
|
||||||
Genode::addr_t const pd_core = platform_specific().core_pd_sel();
|
|
||||||
Platform_pd &target_pd = *_pd;
|
Platform_pd &target_pd = *_pd;
|
||||||
Genode::addr_t const pd_dst = target_pd.pd_sel();
|
|
||||||
Nova::Utcb &utcb = *reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb());
|
Nova::Utcb &utcb = *reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb());
|
||||||
|
addr_t const pd_core = platform_specific().core_pd_sel();
|
||||||
|
addr_t const pd_dst = target_pd.pd_sel();
|
||||||
|
|
||||||
auto lambda = [&] (Region_map_component *region_map,
|
auto map_memory = [&] (Mapping const &mapping)
|
||||||
Rm_region *region,
|
|
||||||
addr_t const ds_offset,
|
|
||||||
addr_t const region_offset,
|
|
||||||
addr_t const dst_region_size) -> addr_t
|
|
||||||
{
|
{
|
||||||
Dataspace_component * dsc = region ? ®ion->dataspace() : nullptr;
|
|
||||||
if (!dsc) {
|
|
||||||
struct No_dataspace{};
|
|
||||||
throw No_dataspace();
|
|
||||||
}
|
|
||||||
if (!region_map) {
|
|
||||||
ASSERT_NEVER_CALLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mapping mapping = Region_map_component::create_map_item(region_map,
|
|
||||||
*region,
|
|
||||||
ds_offset,
|
|
||||||
region_offset,
|
|
||||||
*dsc, virt,
|
|
||||||
dst_region_size);
|
|
||||||
|
|
||||||
/* asynchronously map memory */
|
/* asynchronously map memory */
|
||||||
uint8_t err = Nova::NOVA_PD_OOM;
|
uint8_t err = Nova::NOVA_PD_OOM;
|
||||||
do {
|
do {
|
||||||
@ -79,27 +59,39 @@ void Pd_session_component::map(addr_t virt, addr_t size)
|
|||||||
|
|
||||||
} while (err == Nova::NOVA_PD_OOM &&
|
} while (err == Nova::NOVA_PD_OOM &&
|
||||||
Nova::NOVA_OK == Pager_object::handle_oom(Pager_object::SRC_CORE_PD,
|
Nova::NOVA_OK == Pager_object::handle_oom(Pager_object::SRC_CORE_PD,
|
||||||
_pd->pd_sel(),
|
target_pd.pd_sel(),
|
||||||
"core", "ep",
|
"core", "ep",
|
||||||
Pager_object::Policy::UPGRADE_CORE_TO_DST));
|
Pager_object::Policy::UPGRADE_CORE_TO_DST));
|
||||||
|
|
||||||
addr_t const map_size = 1UL << mapping.size_log2;
|
|
||||||
addr_t const mapped = mapping.dst_addr + map_size - virt;
|
|
||||||
|
|
||||||
if (err != Nova::NOVA_OK) {
|
if (err != Nova::NOVA_OK) {
|
||||||
error("could not map memory ",
|
error("could not eagerly map memory ",
|
||||||
Hex_range<addr_t>(mapping.dst_addr, map_size) , " "
|
Hex_range<addr_t>(mapping.dst_addr, 1UL << mapping.size_log2) , " "
|
||||||
"eagerly error=", err);
|
"error=", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapped;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (size) {
|
while (size) {
|
||||||
addr_t mapped = _address_space.apply_to_dataspace(virt, lambda);
|
|
||||||
virt += mapped;
|
Fault const artificial_fault {
|
||||||
size = size < mapped ? 0 : size - mapped;
|
.hotspot = { virt },
|
||||||
|
.access = Access::READ,
|
||||||
|
.rwx = Rwx::rwx(),
|
||||||
|
.bounds = { .start = 0, .end = ~0UL },
|
||||||
|
};
|
||||||
|
|
||||||
|
_address_space.with_mapping_for_fault(artificial_fault,
|
||||||
|
[&] (Mapping const &mapping)
|
||||||
|
{
|
||||||
|
map_memory(mapping);
|
||||||
|
|
||||||
|
size_t const mapped_bytes = 1 << mapping.size_log2;
|
||||||
|
|
||||||
|
virt += mapped_bytes;
|
||||||
|
size = size < mapped_bytes ? 0 : size - mapped_bytes;
|
||||||
|
},
|
||||||
|
|
||||||
|
[&] (Region_map_component &, Fault const &) { /* don't reflect */ }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
error(__func__, " failed ", Hex(virt), "+", Hex(size));
|
error(__func__, " failed ", Hex(virt), "+", Hex(size));
|
||||||
|
@ -111,7 +111,7 @@ namespace Core {
|
|||||||
|
|
||||||
inline addr_t map_src_addr(addr_t, addr_t phys) { return phys; }
|
inline addr_t map_src_addr(addr_t, addr_t phys) { return phys; }
|
||||||
|
|
||||||
inline size_t constrain_map_size_log2(size_t size_log2) { return size_log2; }
|
inline Log2 kernel_constrained_map_size(Log2 size) { return size; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__UTIL_H_ */
|
#endif /* _CORE__INCLUDE__UTIL_H_ */
|
||||||
|
@ -101,7 +101,8 @@ class Core::Platform : public Platform_generic
|
|||||||
*/
|
*/
|
||||||
Sigma0();
|
Sigma0();
|
||||||
|
|
||||||
int pager(Ipc_pager &) override { /* never called */ return -1; }
|
/* never called */
|
||||||
|
Pager_result pager(Ipc_pager &) override { return Pager_result::STOP; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -119,7 +120,8 @@ class Core::Platform : public Platform_generic
|
|||||||
*/
|
*/
|
||||||
Core_pager(Platform_pd &core_pd);
|
Core_pager(Platform_pd &core_pd);
|
||||||
|
|
||||||
int pager(Ipc_pager &) override { /* never called */ return -1; }
|
/* never called */
|
||||||
|
Pager_result pager(Ipc_pager &) override { return Pager_result::STOP; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -105,8 +105,7 @@ namespace Core {
|
|||||||
inline addr_t map_src_addr(addr_t core_local_addr, addr_t) {
|
inline addr_t map_src_addr(addr_t core_local_addr, addr_t) {
|
||||||
return core_local_addr; }
|
return core_local_addr; }
|
||||||
|
|
||||||
inline size_t constrain_map_size_log2(size_t size_log2) {
|
inline Log2 kernel_constrained_map_size(Log2 size) { return size; }
|
||||||
return size_log2; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__UTIL_H_ */
|
#endif /* _CORE__INCLUDE__UTIL_H_ */
|
||||||
|
@ -94,6 +94,8 @@ class Core::Pager_object : public Object_pool<Pager_object>::Entry
|
|||||||
|
|
||||||
unsigned long reply_cap_sel() const { return _reply_cap.value(); }
|
unsigned long reply_cap_sel() const { return _reply_cap.value(); }
|
||||||
|
|
||||||
|
enum class Pager_result { STOP, CONTINUE };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to be implemented by a derived class
|
* Interface to be implemented by a derived class
|
||||||
*
|
*
|
||||||
@ -101,7 +103,7 @@ class Core::Pager_object : public Object_pool<Pager_object>::Entry
|
|||||||
*
|
*
|
||||||
* Returns !0 on error and pagefault will not be answered.
|
* Returns !0 on error and pagefault will not be answered.
|
||||||
*/
|
*/
|
||||||
virtual int pager(Ipc_pager &ps) = 0;
|
virtual Pager_result pager(Ipc_pager &ps) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wake up the faulter
|
* Wake up the faulter
|
||||||
|
@ -27,7 +27,7 @@ namespace Core {
|
|||||||
inline addr_t round_page(addr_t addr) { return trunc_page(addr + get_page_size() - 1); }
|
inline addr_t round_page(addr_t addr) { return trunc_page(addr + get_page_size() - 1); }
|
||||||
|
|
||||||
inline addr_t map_src_addr(addr_t, addr_t phys) { return phys; }
|
inline addr_t map_src_addr(addr_t, addr_t phys) { return phys; }
|
||||||
inline size_t constrain_map_size_log2(size_t) { return get_page_size_log2(); }
|
inline Log2 kernel_constrained_map_size(Log2) { return { get_page_size_log2() }; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__UTIL_H_ */
|
#endif /* _CORE__INCLUDE__UTIL_H_ */
|
||||||
|
@ -222,20 +222,12 @@ void Pager_entrypoint::entry()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send reply if page-fault handling succeeded */
|
reply_pending = obj->pager(_pager) == Pager_object::Pager_result::CONTINUE;
|
||||||
reply_pending = !obj->pager(_pager);
|
|
||||||
if (!reply_pending) {
|
|
||||||
warning("page-fault, ", *obj,
|
|
||||||
" ip=", Hex(_pager.fault_ip()),
|
|
||||||
" pf-addr=", Hex(_pager.fault_addr()));
|
|
||||||
_pager.reply_save_caller(obj->reply_cap_sel());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* install memory mappings */
|
if (reply_pending)
|
||||||
if (_pager.install_mapping()) {
|
(void)_pager.install_mapping();
|
||||||
return;
|
else
|
||||||
}
|
_pager.reply_save_caller(obj->reply_cap_sel());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,12 +112,12 @@ compare_output_to $good_string
|
|||||||
puts "Affinity test: passed"
|
puts "Affinity test: passed"
|
||||||
|
|
||||||
set output $original_output
|
set output $original_output
|
||||||
grep_output {no RM attachment }
|
grep_output {Error:}
|
||||||
unify_output {pf_addr=0x[a-f0-9]+} "ADDR"
|
unify_output {address 0x[a-f0-9]+} "address ADDR"
|
||||||
unify_output {pf_ip=0x[a-f0-9]+} "IP"
|
unify_output {ip=0x[a-f0-9]+} "ip=IP"
|
||||||
set good_string ""
|
set good_string ""
|
||||||
for {set r 1} {$r < $cpus} {incr r} {
|
for {set r 1} {$r < $cpus} {incr r} {
|
||||||
append good_string {no RM attachment (READ ADDR IP from pager_object: pd='init -> test-smp' thread='tlb_thread')}
|
append good_string {Error: illegal READ at address ADDR by pager_object: pd='init -> test-smp' thread='tlb_thread' ip=IP}
|
||||||
append good_string "\n"
|
append good_string "\n"
|
||||||
}
|
}
|
||||||
compare_output_to $good_string
|
compare_output_to $good_string
|
||||||
|
62
repos/base/src/core/include/addr_range.h
Normal file
62
repos/base/src/core/include/addr_range.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* \brief Memory-address range
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2023-06-11
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CORE__INCLUDE__ADDR_RANGE_H_
|
||||||
|
#define _CORE__INCLUDE__ADDR_RANGE_H_
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
namespace Core { struct Addr_range; }
|
||||||
|
|
||||||
|
|
||||||
|
struct Core::Addr_range
|
||||||
|
{
|
||||||
|
addr_t start;
|
||||||
|
addr_t end; /* last byte */
|
||||||
|
|
||||||
|
bool valid() const { return end > start; }
|
||||||
|
|
||||||
|
Addr_range intersected(Addr_range const &other) const
|
||||||
|
{
|
||||||
|
if (!valid() || !other.valid())
|
||||||
|
return { };
|
||||||
|
|
||||||
|
return { max(start, other.start), min(end, other.end) };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(addr_t at) const { return (at >= start) && (at <= end); }
|
||||||
|
|
||||||
|
Addr_range reduced_by(addr_t offset) const
|
||||||
|
{
|
||||||
|
if (!valid() || (offset > start))
|
||||||
|
return { };
|
||||||
|
|
||||||
|
return Addr_range { start - offset, end - offset };
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr_range increased_by(addr_t offset) const
|
||||||
|
{
|
||||||
|
if (!valid() || (offset + start < offset) || (offset + end < offset))
|
||||||
|
return { };
|
||||||
|
|
||||||
|
return Addr_range { start + offset, end + offset };
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(Output &out) const
|
||||||
|
{
|
||||||
|
Genode::print(out, "[", Hex(start), ",", Hex(end), "]");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _CORE__INCLUDE__ADDR_RANGE_H_ */
|
@ -37,6 +37,10 @@ namespace Core {
|
|||||||
|
|
||||||
class Core::Dataspace_component : public Rpc_object<Dataspace>
|
class Core::Dataspace_component : public Rpc_object<Dataspace>
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct Attr { addr_t base; size_t size; bool writeable; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
addr_t const _phys_addr = 0; /* address of dataspace in physical memory */
|
addr_t const _phys_addr = 0; /* address of dataspace in physical memory */
|
||||||
@ -137,6 +141,10 @@ class Core::Dataspace_component : public Rpc_object<Dataspace>
|
|||||||
return Core::map_src_addr(_core_local_addr, _phys_addr);
|
return Core::map_src_addr(_core_local_addr, _phys_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Attr attr() const { return { .base = map_src_addr(),
|
||||||
|
.size = _size,
|
||||||
|
.writeable = _writeable }; }
|
||||||
|
|
||||||
void assign_core_local_addr(void *addr) { _core_local_addr = (addr_t)addr; }
|
void assign_core_local_addr(void *addr) { _core_local_addr = (addr_t)addr; }
|
||||||
|
|
||||||
void attached_to(Rm_region ®ion);
|
void attached_to(Rm_region ®ion);
|
||||||
@ -161,6 +169,13 @@ class Core::Dataspace_component : public Rpc_object<Dataspace>
|
|||||||
|
|
||||||
size_t size() override { return _size; }
|
size_t size() override { return _size; }
|
||||||
bool writeable() override { return _writeable; }
|
bool writeable() override { return _writeable; }
|
||||||
|
|
||||||
|
|
||||||
|
void print(Output &out) const
|
||||||
|
{
|
||||||
|
addr_t const base = map_src_addr();
|
||||||
|
Genode::print(out, "[", Hex(base), ",", Hex(base + _size - 1), "]");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__DATASPACE_COMPONENT_H_ */
|
#endif /* _CORE__INCLUDE__DATASPACE_COMPONENT_H_ */
|
||||||
|
136
repos/base/src/core/include/log2_range.h
Normal file
136
repos/base/src/core/include/log2_range.h
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* \brief Utility for dealing with log2 alignment constraints
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2023-06-11
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CORE__INCLUDE__LOG2_RANGE_H_
|
||||||
|
#define _CORE__INCLUDE__LOG2_RANGE_H_
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <util.h>
|
||||||
|
#include <addr_range.h>
|
||||||
|
|
||||||
|
namespace Core { struct Log2_range; }
|
||||||
|
|
||||||
|
|
||||||
|
struct Core::Log2_range
|
||||||
|
{
|
||||||
|
Addr hotspot { 0 };
|
||||||
|
Addr base { 0 };
|
||||||
|
Log2 size { 0 };
|
||||||
|
|
||||||
|
bool valid() const { return size.log2 >= get_page_size_log2(); }
|
||||||
|
|
||||||
|
static constexpr Log2 UNCONSTRAINED = { uint8_t(~0) };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor, constructs invalid range
|
||||||
|
*/
|
||||||
|
Log2_range() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, hotspot area spans the maximum address-space size
|
||||||
|
*/
|
||||||
|
Log2_range(Addr hotspot) : hotspot(hotspot), size(UNCONSTRAINED) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constrain range to specified region
|
||||||
|
*/
|
||||||
|
Log2_range constrained(Addr_range region) const
|
||||||
|
{
|
||||||
|
addr_t const upper_bound = (size.log2 == UNCONSTRAINED.log2)
|
||||||
|
? ~0UL : (base.value + (1UL << size.log2) - 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find flexpage around hotspot that lies within the specified region.
|
||||||
|
*
|
||||||
|
* Start with a 'size' of one less than the minimal page size.
|
||||||
|
* If the specified constraint conflicts with the existing range,
|
||||||
|
* the loop breaks at the first iteration and we can check for this
|
||||||
|
* condition after the loop.
|
||||||
|
*/
|
||||||
|
Log2_range result { hotspot };
|
||||||
|
result.size = { get_page_size_log2() - 1 };
|
||||||
|
|
||||||
|
for (uint8_t try_size_log2 = get_page_size_log2();
|
||||||
|
try_size_log2 < sizeof(addr_t)*8 ; try_size_log2++) {
|
||||||
|
|
||||||
|
addr_t const fpage_mask = ~((1UL << try_size_log2) - 1);
|
||||||
|
addr_t const try_base = hotspot.value & fpage_mask;
|
||||||
|
|
||||||
|
/* check lower bound of existing range */
|
||||||
|
if (try_base < base.value)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* check against upper bound of existing range */
|
||||||
|
if (try_base + (1UL << try_size_log2) - 1 > upper_bound)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* check against lower bound of region */
|
||||||
|
if (try_base < region.start)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* check against upper bound of region */
|
||||||
|
if (try_base + (1UL << try_size_log2) - 1 > region.end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* flexpage is compatible with the range, use it */
|
||||||
|
result.size = { try_size_log2 };
|
||||||
|
result.base = { try_base };
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.valid() ? result : Log2_range { };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constrain range around hotspot to specified log2 size
|
||||||
|
*/
|
||||||
|
Log2_range constrained(Log2 value) const
|
||||||
|
{
|
||||||
|
Log2_range result = *this;
|
||||||
|
|
||||||
|
if (value.log2 >= size.log2)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result.base = { hotspot.value & ~((1UL << value.log2) - 1) };
|
||||||
|
result.size = value;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine common log2 size compatible with both ranges
|
||||||
|
*/
|
||||||
|
static Log2 common_log2(Log2_range const &r1, Log2_range const &r2)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We have to make sure that the offset of hotspot
|
||||||
|
* relative to the flexpage base is the same for both ranges.
|
||||||
|
* This condition is met by the flexpage size equal to the number
|
||||||
|
* of common least-significant bits of both offsets.
|
||||||
|
*/
|
||||||
|
size_t const diff = (r1.hotspot.value - r1.base.value)
|
||||||
|
^ (r2.hotspot.value - r2.base.value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find highest clear bit in 'diff', starting from the least
|
||||||
|
* significant candidate. We can skip all bits lower then
|
||||||
|
* 'get_page_size_log2()' because they are not relevant as
|
||||||
|
* flexpage size (and are always zero).
|
||||||
|
*/
|
||||||
|
uint8_t n = get_page_size_log2();
|
||||||
|
size_t const min_size_log2 = min(r1.size.log2, r2.size.log2);
|
||||||
|
for (; n < min_size_log2 && !(diff & (1UL << n)); n++);
|
||||||
|
|
||||||
|
return Log2 { n };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _CORE__INCLUDE__LOG2_RANGE_H_ */
|
@ -101,6 +101,8 @@ class Core::Pager_object : public Object_pool<Pager_object>::Entry
|
|||||||
|
|
||||||
unsigned long badge() const { return _badge; }
|
unsigned long badge() const { return _badge; }
|
||||||
|
|
||||||
|
enum class Pager_result { STOP, CONTINUE };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to be implemented by a derived class
|
* Interface to be implemented by a derived class
|
||||||
*
|
*
|
||||||
@ -108,7 +110,7 @@ class Core::Pager_object : public Object_pool<Pager_object>::Entry
|
|||||||
*
|
*
|
||||||
* Returns !0 on error and pagefault will not be answered.
|
* Returns !0 on error and pagefault will not be answered.
|
||||||
*/
|
*/
|
||||||
virtual int pager(Ipc_pager &ps) = 0;
|
virtual Pager_result pager(Ipc_pager &ps) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wake up the faulter
|
* Wake up the faulter
|
||||||
|
@ -33,18 +33,20 @@
|
|||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include <dataspace_component.h>
|
#include <dataspace_component.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
#include <log2_range.h>
|
||||||
#include <address_space.h>
|
#include <address_space.h>
|
||||||
|
|
||||||
/* base-internal includes */
|
/* base-internal includes */
|
||||||
#include <base/internal/stack_area.h>
|
#include <base/internal/stack_area.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
class Region_map_detach;
|
||||||
|
class Rm_region;
|
||||||
|
struct Fault;
|
||||||
class Cpu_thread_component;
|
class Cpu_thread_component;
|
||||||
class Dataspace_component;
|
class Dataspace_component;
|
||||||
class Region_map_component;
|
class Region_map_component;
|
||||||
class Region_map_detach;
|
|
||||||
class Rm_client;
|
class Rm_client;
|
||||||
class Rm_region;
|
|
||||||
class Rm_faulter;
|
class Rm_faulter;
|
||||||
class Rm_session_component;
|
class Rm_session_component;
|
||||||
}
|
}
|
||||||
@ -56,9 +58,9 @@ class Core::Region_map_detach : Interface
|
|||||||
|
|
||||||
virtual void detach(Region_map::Local_addr) = 0;
|
virtual void detach(Region_map::Local_addr) = 0;
|
||||||
virtual void unmap_region(addr_t base, size_t size) = 0;
|
virtual void unmap_region(addr_t base, size_t size) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of a single entry of a region map
|
* Representation of a single entry of a region map
|
||||||
*
|
*
|
||||||
@ -80,6 +82,13 @@ class Core::Rm_region : public List<Rm_region>::Element
|
|||||||
bool exec;
|
bool exec;
|
||||||
off_t off;
|
off_t off;
|
||||||
bool dma;
|
bool dma;
|
||||||
|
|
||||||
|
void print(Output &out) const
|
||||||
|
{
|
||||||
|
Genode::print(out, "[", Hex(base), ",", Hex(base + size - 1), " "
|
||||||
|
"(r", write ? "w" : "-", exec ? "x" : "-", ") "
|
||||||
|
"offset: ", Hex(off), dma ? " DMA" : "");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -104,6 +113,71 @@ class Core::Rm_region : public List<Rm_region>::Element
|
|||||||
bool dma() const { return _attr.dma; }
|
bool dma() const { return _attr.dma; }
|
||||||
Dataspace_component &dataspace() const { return _dsc; }
|
Dataspace_component &dataspace() const { return _dsc; }
|
||||||
Region_map_detach &rm() const { return _rm; }
|
Region_map_detach &rm() const { return _rm; }
|
||||||
|
|
||||||
|
Addr_range range() const { return { .start = _attr.base,
|
||||||
|
.end = _attr.base + _attr.size - 1 }; }
|
||||||
|
|
||||||
|
void print(Output &out) const { Genode::print(out, _attr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Core::Fault
|
||||||
|
{
|
||||||
|
Addr hotspot; /* page-fault address */
|
||||||
|
Access access; /* reason for the fault, used to detect violations */
|
||||||
|
Rwx rwx; /* mapping rights, downgraded by 'within_' methods */
|
||||||
|
Addr_range bounds; /* limits of the fault's coordinate system */
|
||||||
|
|
||||||
|
bool write_access() const { return access == Access::WRITE; }
|
||||||
|
bool exec_access() const { return access == Access::EXEC; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate fault information to region-relative coordinates
|
||||||
|
*/
|
||||||
|
Fault within_region(Rm_region const ®ion) const
|
||||||
|
{
|
||||||
|
return Fault {
|
||||||
|
.hotspot = hotspot.reduced_by(region.base()),
|
||||||
|
.access = access,
|
||||||
|
.rwx = { .w = rwx.w && region.write(),
|
||||||
|
.x = rwx.x && region.executable() },
|
||||||
|
.bounds = bounds.intersected(region.range())
|
||||||
|
.reduced_by(region.base())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate fault information to coordinates within a sub region map
|
||||||
|
*/
|
||||||
|
Fault within_sub_region_map(addr_t offset, size_t region_map_size) const
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
.hotspot = hotspot.increased_by(offset),
|
||||||
|
.access = access,
|
||||||
|
.rwx = rwx,
|
||||||
|
.bounds = bounds.intersected({ 0, region_map_size })
|
||||||
|
.increased_by(offset)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate fault information to physical coordinates for memory mapping
|
||||||
|
*/
|
||||||
|
Fault within_ram(addr_t offset, Dataspace_component::Attr dataspace) const
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
.hotspot = hotspot.increased_by(offset)
|
||||||
|
.increased_by(dataspace.base),
|
||||||
|
.access = access,
|
||||||
|
.rwx = { .w = rwx.w && dataspace.writeable,
|
||||||
|
.x = rwx.x },
|
||||||
|
.bounds = bounds.increased_by(offset)
|
||||||
|
.intersected({ 0, dataspace.size })
|
||||||
|
.increased_by(dataspace.base)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void print(Output &out) const { Genode::print(out, access, " at address ", hotspot); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -209,7 +283,7 @@ class Core::Rm_client : public Pager_object, public Rm_faulter,
|
|||||||
Rm_faulter(static_cast<Pager_object &>(*this)), _region_map(rm)
|
Rm_faulter(static_cast<Pager_object &>(*this)), _region_map(rm)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
int pager(Ipc_pager &pager) override;
|
Pager_result pager(Ipc_pager &pager) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return region map that the RM client is member of
|
* Return region map that the RM client is member of
|
||||||
@ -223,6 +297,11 @@ class Core::Region_map_component : private Weak_object<Region_map_component>,
|
|||||||
private List<Region_map_component>::Element,
|
private List<Region_map_component>::Element,
|
||||||
public Region_map_detach
|
public Region_map_detach
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum class With_mapping_result { RESOLVED, RECURSION_LIMIT, NO_REGION,
|
||||||
|
REFLECTED, WRITE_VIOLATION, EXEC_VIOLATION };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class List<Region_map_component>;
|
friend class List<Region_map_component>;
|
||||||
@ -235,8 +314,7 @@ class Core::Region_map_component : private Weak_object<Region_map_component>,
|
|||||||
|
|
||||||
Allocator &_md_alloc;
|
Allocator &_md_alloc;
|
||||||
|
|
||||||
Signal_transmitter _fault_notifier { }; /* notification mechanism for
|
Signal_context_capability _fault_sigh { };
|
||||||
region-manager faults */
|
|
||||||
|
|
||||||
Address_space *_address_space { nullptr };
|
Address_space *_address_space { nullptr };
|
||||||
|
|
||||||
@ -305,56 +383,87 @@ class Core::Region_map_component : private Weak_object<Region_map_component>,
|
|||||||
the region map and wait
|
the region map and wait
|
||||||
for fault resolution */
|
for fault resolution */
|
||||||
List<Rm_client> _clients { }; /* list of RM clients using this region map */
|
List<Rm_client> _clients { }; /* list of RM clients using this region map */
|
||||||
Mutex _mutex { }; /* mutex for map and list */
|
Mutex mutable _mutex { }; /* mutex for map and list */
|
||||||
Pager_entrypoint &_pager_ep;
|
Pager_entrypoint &_pager_ep;
|
||||||
Rm_dataspace_component _ds; /* dataspace representation of region map */
|
Rm_dataspace_component _ds; /* dataspace representation of region map */
|
||||||
Dataspace_capability _ds_cap;
|
Dataspace_capability _ds_cap;
|
||||||
|
|
||||||
template <typename F>
|
struct Recursion_limit { unsigned value; };
|
||||||
auto _apply_to_dataspace(addr_t addr, F const &f, addr_t offset,
|
|
||||||
unsigned level, addr_t dst_region_size)
|
/**
|
||||||
-> typename Trait::Functor<decltype(&F::operator())>::Return_type
|
* Resolve region at a given fault address
|
||||||
|
*
|
||||||
|
* /param resolved_fn functor called with the resolved region and the
|
||||||
|
* region-relative fault information
|
||||||
|
*
|
||||||
|
* Called recursively when resolving a page fault in nested region maps.
|
||||||
|
*/
|
||||||
|
With_mapping_result _with_region_at_fault(Recursion_limit const recursion_limit,
|
||||||
|
Fault const &fault,
|
||||||
|
auto const &resolved_fn,
|
||||||
|
auto const &reflect_fn)
|
||||||
{
|
{
|
||||||
using Functor = Trait::Functor<decltype(&F::operator())>;
|
using Result = With_mapping_result;
|
||||||
using Return_type = typename Functor::Return_type;
|
|
||||||
|
if (recursion_limit.value == 0)
|
||||||
|
return Result::RECURSION_LIMIT;
|
||||||
|
|
||||||
Mutex::Guard lock_guard(_mutex);
|
Mutex::Guard lock_guard(_mutex);
|
||||||
|
|
||||||
/* skip further lookup when reaching the recursion limit */
|
|
||||||
if (!level)
|
|
||||||
return f(this, nullptr, 0, 0, dst_region_size);
|
|
||||||
|
|
||||||
/* lookup region and dataspace */
|
/* lookup region and dataspace */
|
||||||
Rm_region *region = _map.metadata((void*)addr);
|
Rm_region const * const region_ptr = _map.metadata((void*)fault.hotspot.value);
|
||||||
Dataspace_component *dsc = region ? ®ion->dataspace()
|
|
||||||
: nullptr;
|
|
||||||
|
|
||||||
if (region && dst_region_size > region->size())
|
auto reflect_fault = [&] (Result result)
|
||||||
dst_region_size = region->size();
|
|
||||||
|
|
||||||
/* calculate offset in dataspace */
|
|
||||||
addr_t ds_offset = region ? (addr - region->base()
|
|
||||||
+ region->offset()) : 0;
|
|
||||||
|
|
||||||
/* check for nested dataspace */
|
|
||||||
Native_capability cap = dsc ? dsc->sub_rm()
|
|
||||||
: Native_capability();
|
|
||||||
|
|
||||||
if (!cap.valid())
|
|
||||||
return f(this, region, ds_offset, offset, dst_region_size);
|
|
||||||
|
|
||||||
/* in case of a nested dataspace perform a recursive lookup */
|
|
||||||
auto lambda = [&] (Region_map_component *rmc) -> Return_type
|
|
||||||
{
|
{
|
||||||
if (rmc)
|
if (!_fault_sigh.valid())
|
||||||
return rmc->_apply_to_dataspace(ds_offset, f,
|
return result; /* not reflected to user land */
|
||||||
offset + region->base() - region->offset(),
|
|
||||||
--level,
|
|
||||||
dst_region_size);
|
|
||||||
|
|
||||||
return f(nullptr, nullptr, ds_offset, offset, dst_region_size);
|
reflect_fn(*this, fault);
|
||||||
|
return Result::REFLECTED; /* omit diagnostics */
|
||||||
};
|
};
|
||||||
return _session_ep.apply(cap, lambda);
|
|
||||||
|
if (!region_ptr)
|
||||||
|
return reflect_fault(Result::NO_REGION);
|
||||||
|
|
||||||
|
Rm_region const ®ion = *region_ptr;
|
||||||
|
|
||||||
|
/* fault information relative to 'region' */
|
||||||
|
Fault const relative_fault = fault.within_region(region);
|
||||||
|
|
||||||
|
Dataspace_component &dataspace = region.dataspace();
|
||||||
|
|
||||||
|
Native_capability managed_ds_cap = dataspace.sub_rm();
|
||||||
|
|
||||||
|
/* region refers to a regular dataspace */
|
||||||
|
if (!managed_ds_cap.valid()) {
|
||||||
|
|
||||||
|
bool const writeable = relative_fault.rwx.w
|
||||||
|
&& dataspace.writeable();
|
||||||
|
|
||||||
|
bool const write_violation = relative_fault.write_access()
|
||||||
|
&& !writeable;
|
||||||
|
|
||||||
|
bool const exec_violation = relative_fault.exec_access()
|
||||||
|
&& !relative_fault.rwx.x;
|
||||||
|
|
||||||
|
if (write_violation) return reflect_fault(Result::WRITE_VIOLATION);
|
||||||
|
if (exec_violation) return reflect_fault(Result::EXEC_VIOLATION);
|
||||||
|
|
||||||
|
return resolved_fn(region, relative_fault);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* traverse into managed dataspace */
|
||||||
|
Fault const sub_region_map_relative_fault =
|
||||||
|
relative_fault.within_sub_region_map(region.offset(),
|
||||||
|
dataspace.size());
|
||||||
|
|
||||||
|
Result result = Result::NO_REGION;
|
||||||
|
_session_ep.apply(managed_ds_cap, [&] (Region_map_component *rmc_ptr) {
|
||||||
|
if (rmc_ptr)
|
||||||
|
result = rmc_ptr->_with_region_at_fault({ recursion_limit.value - 1 },
|
||||||
|
sub_region_map_relative_fault,
|
||||||
|
resolved_fn, reflect_fn); });
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -410,8 +519,6 @@ class Core::Region_map_component : private Weak_object<Region_map_component>,
|
|||||||
void address_space(Address_space *space) { _address_space = space; }
|
void address_space(Address_space *space) { _address_space = space; }
|
||||||
Address_space *address_space() { return _address_space; }
|
Address_space *address_space() { return _address_space; }
|
||||||
|
|
||||||
class Fault_area;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register fault
|
* Register fault
|
||||||
*
|
*
|
||||||
@ -436,18 +543,60 @@ class Core::Region_map_component : private Weak_object<Region_map_component>,
|
|||||||
Rm_dataspace_component &dataspace_component() { return _ds; }
|
Rm_dataspace_component &dataspace_component() { return _ds; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a function to dataspace attached at a given address
|
* Call 'apply_fn' with resolved mapping information for given fault
|
||||||
*
|
*
|
||||||
* /param addr address where the dataspace is attached
|
* /param apply_fn functor called with a 'Mapping' that is suitable
|
||||||
* /param f functor or lambda to apply
|
* for resolving given the 'fault'
|
||||||
|
* /param reflect_fn functor called to reflect a missing mapping
|
||||||
|
* to user space if a fault handler is registered
|
||||||
*/
|
*/
|
||||||
template <typename F>
|
With_mapping_result with_mapping_for_fault(Fault const &fault,
|
||||||
auto apply_to_dataspace(addr_t addr, F f)
|
auto const &apply_fn,
|
||||||
-> typename Trait::Functor<decltype(&F::operator())>::Return_type
|
auto const &reflect_fn)
|
||||||
{
|
{
|
||||||
enum { RECURSION_LIMIT = 5 };
|
return _with_region_at_fault(Recursion_limit { 5 }, fault,
|
||||||
|
[&] (Rm_region const ®ion, Fault const ®ion_relative_fault)
|
||||||
|
{
|
||||||
|
Dataspace_component &dataspace = region.dataspace();
|
||||||
|
|
||||||
return _apply_to_dataspace(addr, f, 0, RECURSION_LIMIT, ~0UL);
|
Fault const ram_relative_fault =
|
||||||
|
region_relative_fault.within_ram(region.offset(), dataspace.attr());
|
||||||
|
|
||||||
|
Log2_range src_range { ram_relative_fault.hotspot };
|
||||||
|
Log2_range dst_range { fault.hotspot };
|
||||||
|
|
||||||
|
src_range = src_range.constrained(ram_relative_fault.bounds);
|
||||||
|
|
||||||
|
Log2 const common_size = Log2_range::common_log2(dst_range,
|
||||||
|
src_range);
|
||||||
|
Log2 const map_size = kernel_constrained_map_size(common_size);
|
||||||
|
|
||||||
|
src_range = src_range.constrained(map_size);
|
||||||
|
dst_range = dst_range.constrained(map_size);
|
||||||
|
|
||||||
|
if (!src_range.valid() || !dst_range.valid()) {
|
||||||
|
error("invalid mapping");
|
||||||
|
return With_mapping_result::NO_REGION;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mapping const mapping {
|
||||||
|
.dst_addr = dst_range.base.value,
|
||||||
|
.src_addr = src_range.base.value,
|
||||||
|
.size_log2 = map_size.log2,
|
||||||
|
.cached = dataspace.cacheability() == CACHED,
|
||||||
|
.io_mem = dataspace.io_mem(),
|
||||||
|
.dma_buffer = region.dma(),
|
||||||
|
.write_combined = dataspace.cacheability() == WRITE_COMBINED,
|
||||||
|
.writeable = ram_relative_fault.rwx.w,
|
||||||
|
.executable = ram_relative_fault.rwx.x
|
||||||
|
};
|
||||||
|
|
||||||
|
apply_fn(mapping);
|
||||||
|
|
||||||
|
return With_mapping_result::RESOLVED;
|
||||||
|
},
|
||||||
|
reflect_fn
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -458,16 +607,6 @@ class Core::Region_map_component : private Weak_object<Region_map_component>,
|
|||||||
void add_client(Rm_client &);
|
void add_client(Rm_client &);
|
||||||
void remove_client(Rm_client &);
|
void remove_client(Rm_client &);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create mapping item to be placed into the page table
|
|
||||||
*/
|
|
||||||
static Mapping create_map_item(Region_map_component *region_map,
|
|
||||||
Rm_region ®ion,
|
|
||||||
addr_t ds_offset,
|
|
||||||
addr_t region_offset,
|
|
||||||
Dataspace_component &dsc,
|
|
||||||
addr_t, addr_t);
|
|
||||||
|
|
||||||
using Attach_dma_result = Pd_session::Attach_dma_result;
|
using Attach_dma_result = Pd_session::Attach_dma_result;
|
||||||
|
|
||||||
Attach_dma_result attach_dma(Dataspace_capability, addr_t);
|
Attach_dma_result attach_dma(Dataspace_capability, addr_t);
|
||||||
|
@ -19,6 +19,56 @@
|
|||||||
#include <util/interface.h>
|
#include <util/interface.h>
|
||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
|
|
||||||
namespace Core { using namespace Genode; }
|
namespace Core {
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
struct Log2 { uint8_t log2; };
|
||||||
|
|
||||||
|
enum class Access { READ, WRITE, EXEC };
|
||||||
|
|
||||||
|
struct Addr
|
||||||
|
{
|
||||||
|
addr_t value;
|
||||||
|
|
||||||
|
Addr reduced_by(addr_t offset) const
|
||||||
|
{
|
||||||
|
return { (value >= offset) ? (value - offset) : 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr increased_by(addr_t offset) const
|
||||||
|
{
|
||||||
|
return { (value + offset >= offset) ? (value + offset) : 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(Output &out) const { Genode::print(out, Hex(value)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Rwx
|
||||||
|
{
|
||||||
|
bool w, x;
|
||||||
|
|
||||||
|
static constexpr bool r = true;
|
||||||
|
|
||||||
|
static constexpr Rwx rwx() { return { true, true }; }
|
||||||
|
|
||||||
|
void print(Output &out) const
|
||||||
|
{
|
||||||
|
Genode::print(out, "(r", w ? "w" : "-", x ? "x" : "-", ")");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
|
||||||
|
static inline void print(Output &out, Core::Access access)
|
||||||
|
{
|
||||||
|
switch (access) {
|
||||||
|
case Core::Access::READ: print(out, "READ"); break;
|
||||||
|
case Core::Access::WRITE: print(out, "WRITE"); break;
|
||||||
|
case Core::Access::EXEC: print(out, "EXEC"); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__TYPES_H_ */
|
#endif /* _CORE__INCLUDE__TYPES_H_ */
|
||||||
|
@ -39,11 +39,8 @@ void Pager_entrypoint::entry()
|
|||||||
obj->submit_exception_signal();
|
obj->submit_exception_signal();
|
||||||
} else {
|
} else {
|
||||||
/* send reply if page-fault handling succeeded */
|
/* send reply if page-fault handling succeeded */
|
||||||
reply_pending = !obj->pager(_pager);
|
using Result = Pager_object::Pager_result;
|
||||||
if (!reply_pending)
|
reply_pending = (obj->pager(_pager) == Result::CONTINUE);
|
||||||
warning("page-fault, ", *obj,
|
|
||||||
" ip=", Hex(_pager.fault_ip()),
|
|
||||||
" pf-addr=", Hex(_pager.fault_addr()));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -23,240 +23,93 @@
|
|||||||
#include <region_map_component.h>
|
#include <region_map_component.h>
|
||||||
#include <dataspace_component.h>
|
#include <dataspace_component.h>
|
||||||
|
|
||||||
static const bool verbose_page_faults = false;
|
|
||||||
|
|
||||||
|
|
||||||
struct Core::Region_map_component::Fault_area
|
|
||||||
{
|
|
||||||
addr_t _fault_addr = 0;
|
|
||||||
addr_t _base = 0;
|
|
||||||
size_t _size_log2 = 0;
|
|
||||||
|
|
||||||
addr_t _upper_bound() const {
|
|
||||||
return (_size_log2 == ~0UL) ? ~0UL : (_base + (1UL << _size_log2) - 1); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor, constructs invalid fault area
|
|
||||||
*/
|
|
||||||
Fault_area() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor, fault area spans the maximum address-space size
|
|
||||||
*/
|
|
||||||
Fault_area(addr_t fault_addr) :
|
|
||||||
_fault_addr(fault_addr), _size_log2(~0UL) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constrain fault area to specified region
|
|
||||||
*/
|
|
||||||
void constrain(addr_t region_base, size_t region_size)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Find flexpage around _fault_addr that lies within the
|
|
||||||
* specified region.
|
|
||||||
*
|
|
||||||
* Start with a 'size_log2' of one less than the minimal
|
|
||||||
* page size. If the specified constraint conflicts with
|
|
||||||
* the existing fault area, the loop breaks at the first
|
|
||||||
* iteration and we can check for this condition after the
|
|
||||||
* loop.
|
|
||||||
*/
|
|
||||||
size_t size_log2 = get_page_size_log2() - 1;
|
|
||||||
addr_t base = 0;
|
|
||||||
for (size_t try_size_log2 = get_page_size_log2();
|
|
||||||
try_size_log2 < sizeof(addr_t)*8 ; try_size_log2++) {
|
|
||||||
addr_t fpage_mask = ~((1UL << try_size_log2) - 1);
|
|
||||||
addr_t try_base = _fault_addr & fpage_mask;
|
|
||||||
|
|
||||||
/* check lower bound of existing fault area */
|
|
||||||
if (try_base < _base)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* check against upper bound of existing fault area */
|
|
||||||
if (try_base + (1UL << try_size_log2) - 1 > _upper_bound())
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* check against lower bound of region */
|
|
||||||
if (try_base < region_base)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* check against upper bound of region */
|
|
||||||
if (try_base + (1UL << try_size_log2) - 1 > region_base + region_size - 1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* flexpage is compatible with fault area, use it */
|
|
||||||
size_log2 = try_size_log2;
|
|
||||||
base = try_base;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if constraint is compatible with the fault area, invalidate */
|
|
||||||
if (size_log2 < get_page_size_log2()) {
|
|
||||||
_size_log2 = 0;
|
|
||||||
_base = 0;
|
|
||||||
} else {
|
|
||||||
_size_log2 = size_log2;
|
|
||||||
_base = base;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constrain fault area to specified flexpage size
|
|
||||||
*/
|
|
||||||
void constrain(size_t size_log2)
|
|
||||||
{
|
|
||||||
if (size_log2 >= _size_log2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_base = _fault_addr & ~((1UL << size_log2) - 1);
|
|
||||||
_size_log2 = size_log2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine common flexpage size compatible with specified fault areas
|
|
||||||
*/
|
|
||||||
static size_t common_size_log2(Fault_area const &a1, Fault_area const &a2)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We have to make sure that the offset of page-fault address
|
|
||||||
* relative to the flexpage base is the same for both fault areas.
|
|
||||||
* This condition is met by the flexpage size equal to the number
|
|
||||||
* of common least-significant bits of both offsets.
|
|
||||||
*/
|
|
||||||
size_t const diff = (a1.fault_addr() - a1.base())
|
|
||||||
^ (a2.fault_addr() - a2.base());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find highest clear bit in 'diff', starting from the least
|
|
||||||
* significant candidate. We can skip all bits lower then
|
|
||||||
* 'get_page_size_log2()' because they are not relevant as
|
|
||||||
* flexpage size (and are always zero).
|
|
||||||
*/
|
|
||||||
size_t n = get_page_size_log2();
|
|
||||||
size_t const min_size_log2 = min(a1._size_log2, a2._size_log2);
|
|
||||||
for (; n < min_size_log2 && !(diff & (1UL << n)); n++);
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_t fault_addr() const { return _fault_addr; }
|
|
||||||
addr_t base() const { return _base; }
|
|
||||||
bool valid() const { return _size_log2 > 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
|
|
||||||
static void print_page_fault(char const *msg,
|
|
||||||
addr_t pf_addr,
|
|
||||||
addr_t pf_ip,
|
|
||||||
Region_map::State::Fault_type pf_type,
|
|
||||||
Pager_object const &obj)
|
|
||||||
{
|
|
||||||
log(msg, " (",
|
|
||||||
pf_type == Region_map::State::WRITE_FAULT ? "WRITE" :
|
|
||||||
pf_type == Region_map::State::READ_FAULT ? "READ" : "EXEC",
|
|
||||||
" pf_addr=", Hex(pf_addr), " pf_ip=", Hex(pf_ip), " from ", obj, ") ");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
** Region-map client **
|
|
||||||
***********************/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This code is executed by the page-fault handler thread.
|
* This code is executed by the page-fault handler thread.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int Rm_client::pager(Ipc_pager &pager)
|
Pager_object::Pager_result Rm_client::pager(Ipc_pager &pager)
|
||||||
{
|
{
|
||||||
Region_map::State::Fault_type pf_type = pager.write_fault() ? Region_map::State::WRITE_FAULT
|
Fault const fault {
|
||||||
: Region_map::State::READ_FAULT;
|
.hotspot = { pager.fault_addr() },
|
||||||
if (pager.exec_fault())
|
.access = pager.write_fault() ? Access::WRITE
|
||||||
pf_type = Region_map::State::EXEC_FAULT;
|
: pager.exec_fault() ? Access::EXEC
|
||||||
|
: Access::READ,
|
||||||
|
.rwx = Rwx::rwx(),
|
||||||
|
.bounds = { .start = 0, .end = ~0UL },
|
||||||
|
};
|
||||||
|
|
||||||
addr_t pf_addr = pager.fault_addr();
|
using Result = Region_map_component::With_mapping_result;
|
||||||
addr_t pf_ip = pager.fault_ip();
|
|
||||||
|
|
||||||
if (verbose_page_faults)
|
Result const result = member_rm().with_mapping_for_fault(fault,
|
||||||
print_page_fault("page fault", pf_addr, pf_ip, pf_type, *this);
|
|
||||||
|
|
||||||
auto lambda = [&] (Region_map_component *region_map,
|
[&] (Mapping const &mapping)
|
||||||
Rm_region *region,
|
|
||||||
addr_t const ds_offset,
|
|
||||||
addr_t const region_offset,
|
|
||||||
addr_t const dst_region_size) -> int
|
|
||||||
{
|
{
|
||||||
Dataspace_component * dsc = region ? ®ion->dataspace() : nullptr;
|
|
||||||
if (!dsc) {
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We found no attachment at the page-fault address and therefore have
|
* On kernels with a mapping database, the leaf dataspace
|
||||||
* to reflect the page fault as region-manager fault. The signal
|
* corresponds to a virtual address range within core. To prepare
|
||||||
* handler is then expected to request the state of the region map.
|
* the answer for the page fault, we make sure that this range is
|
||||||
|
* locally mapped in core.
|
||||||
*/
|
*/
|
||||||
|
if (!mapping.io_mem)
|
||||||
/* print a warning if it's no managed-dataspace */
|
|
||||||
if (region_map == &member_rm())
|
|
||||||
print_page_fault("no RM attachment", pf_addr, pf_ip,
|
|
||||||
pf_type, *this);
|
|
||||||
|
|
||||||
/* register fault at responsible region map */
|
|
||||||
if (region_map)
|
|
||||||
region_map->fault(*this, pf_addr - region_offset, pf_type);
|
|
||||||
|
|
||||||
/* there is no attachment return an error condition */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if dataspace is compatible with page-fault type
|
|
||||||
*/
|
|
||||||
if (pf_type == Region_map::State::WRITE_FAULT &&
|
|
||||||
(!region->write() || !dsc->writeable())) {
|
|
||||||
|
|
||||||
print_page_fault("attempted write at read-only memory",
|
|
||||||
pf_addr, pf_ip, pf_type, *this);
|
|
||||||
|
|
||||||
/* register fault at responsible region map */
|
|
||||||
if (region_map)
|
|
||||||
region_map->fault(*this, pf_addr - region_offset, pf_type);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pf_type == Region_map::State::EXEC_FAULT) {
|
|
||||||
|
|
||||||
print_page_fault("attempted exec at non-executable memory",
|
|
||||||
pf_addr, pf_ip, pf_type, *this);
|
|
||||||
|
|
||||||
/* register fault at responsible region map */
|
|
||||||
if (region_map)
|
|
||||||
region_map->fault(*this, pf_addr - region_offset, pf_type);
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mapping mapping = Region_map_component::create_map_item(region_map,
|
|
||||||
*region,
|
|
||||||
ds_offset,
|
|
||||||
region_offset,
|
|
||||||
*dsc, pf_addr,
|
|
||||||
dst_region_size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* On kernels with a mapping database, the 'dsc' dataspace is a leaf
|
|
||||||
* dataspace that corresponds to a virtual address range within core. To
|
|
||||||
* prepare the answer for the page fault, we make sure that this range is
|
|
||||||
* locally mapped in core. On platforms that support map operations of
|
|
||||||
* pages that are not locally mapped, the 'map_core_local' function may be
|
|
||||||
* empty.
|
|
||||||
*/
|
|
||||||
if (!dsc->io_mem())
|
|
||||||
mapping.prepare_map_operation();
|
mapping.prepare_map_operation();
|
||||||
|
|
||||||
/* answer page fault with a flex-page mapping */
|
/* answer page fault with a flex-page mapping */
|
||||||
pager.set_reply_mapping(mapping);
|
pager.set_reply_mapping(mapping);
|
||||||
return 0;
|
},
|
||||||
};
|
|
||||||
return member_rm().apply_to_dataspace(pf_addr, lambda);
|
[&] (Region_map_component &rm, Fault const &fault) /* reflect to user space */
|
||||||
|
{
|
||||||
|
using Type = Region_map::State::Fault_type;
|
||||||
|
Type const type = (fault.access == Access::READ) ? Type::READ_FAULT
|
||||||
|
: (fault.access == Access::WRITE) ? Type::WRITE_FAULT
|
||||||
|
: Type::EXEC_FAULT;
|
||||||
|
/* deliver fault info to responsible region map */
|
||||||
|
rm.fault(*this, fault.hotspot.value, type);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result == Result::RESOLVED)
|
||||||
|
return Pager_result::CONTINUE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error diagnostics
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Origin
|
||||||
|
{
|
||||||
|
addr_t ip;
|
||||||
|
Pager_object &obj;
|
||||||
|
|
||||||
|
void print(Output &out) const
|
||||||
|
{
|
||||||
|
Genode::print(out, "by ", obj, " ip=", Hex(ip));
|
||||||
|
}
|
||||||
|
} origin { pager.fault_ip(), *this };
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case Result::RESOLVED:
|
||||||
|
case Result::REFLECTED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Result::RECURSION_LIMIT:
|
||||||
|
error("giving up on unexpectedly deep memory-mapping structure");
|
||||||
|
error(fault, " ", origin);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Result::NO_REGION:
|
||||||
|
error("illegal ", fault, " ", origin);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Result::WRITE_VIOLATION:
|
||||||
|
case Result::EXEC_VIOLATION:
|
||||||
|
error(fault.access, " violation at address ",
|
||||||
|
fault.hotspot, " ", origin);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Pager_result::STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -309,47 +162,6 @@ void Rm_faulter::continue_after_resolved_fault()
|
|||||||
** Region-map component **
|
** Region-map component **
|
||||||
**************************/
|
**************************/
|
||||||
|
|
||||||
Mapping Region_map_component::create_map_item(Region_map_component *,
|
|
||||||
Rm_region ®ion,
|
|
||||||
addr_t const ds_offset,
|
|
||||||
addr_t const region_offset,
|
|
||||||
Dataspace_component &dataspace,
|
|
||||||
addr_t const page_addr,
|
|
||||||
addr_t const dst_region_size)
|
|
||||||
{
|
|
||||||
addr_t const ds_base = dataspace.map_src_addr();
|
|
||||||
|
|
||||||
Fault_area src_fault_area(ds_base + ds_offset);
|
|
||||||
Fault_area dst_fault_area(page_addr);
|
|
||||||
|
|
||||||
src_fault_area.constrain(ds_base, dataspace.size());
|
|
||||||
dst_fault_area.constrain(region_offset + region.base(), dst_region_size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine mapping size compatible with source and destination,
|
|
||||||
* and apply platform-specific constraint of mapping sizes.
|
|
||||||
*/
|
|
||||||
size_t map_size_log2 = dst_fault_area.common_size_log2(dst_fault_area,
|
|
||||||
src_fault_area);
|
|
||||||
map_size_log2 = constrain_map_size_log2(map_size_log2);
|
|
||||||
|
|
||||||
src_fault_area.constrain(map_size_log2);
|
|
||||||
dst_fault_area.constrain(map_size_log2);
|
|
||||||
if (!src_fault_area.valid() || !dst_fault_area.valid())
|
|
||||||
error("invalid mapping");
|
|
||||||
|
|
||||||
return Mapping { .dst_addr = dst_fault_area.base(),
|
|
||||||
.src_addr = src_fault_area.base(),
|
|
||||||
.size_log2 = map_size_log2,
|
|
||||||
.cached = dataspace.cacheability() == CACHED,
|
|
||||||
.io_mem = dataspace.io_mem(),
|
|
||||||
.dma_buffer = region.dma(),
|
|
||||||
.write_combined = dataspace.cacheability() == WRITE_COMBINED,
|
|
||||||
.writeable = region.write() && dataspace.writeable(),
|
|
||||||
.executable = region.executable() };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Region_map::Local_addr
|
Region_map::Local_addr
|
||||||
Region_map_component::_attach(Dataspace_capability ds_cap, Attach_attr const attr)
|
Region_map_component::_attach(Dataspace_capability ds_cap, Attach_attr const attr)
|
||||||
{
|
{
|
||||||
@ -665,7 +477,7 @@ void Region_map_component::fault(Rm_faulter &faulter, addr_t pf_addr,
|
|||||||
_faulters.enqueue(faulter);
|
_faulters.enqueue(faulter);
|
||||||
|
|
||||||
/* issue fault signal */
|
/* issue fault signal */
|
||||||
_fault_notifier.submit();
|
Signal_transmitter(_fault_sigh).submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -679,9 +491,9 @@ void Region_map_component::discard_faulter(Rm_faulter &faulter, bool do_lock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Region_map_component::fault_handler(Signal_context_capability handler)
|
void Region_map_component::fault_handler(Signal_context_capability sigh)
|
||||||
{
|
{
|
||||||
_fault_notifier.context(handler);
|
_fault_sigh = sigh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
namespace Genode
|
namespace Genode
|
||||||
{
|
{
|
||||||
constexpr size_t get_page_size_log2() { return 12; }
|
constexpr uint8_t get_page_size_log2() { return 12; }
|
||||||
constexpr size_t get_page_size() { return 1 << get_page_size_log2(); }
|
constexpr size_t get_page_size() { return 1 << get_page_size_log2(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user