214 lines
4.8 KiB
C++
214 lines
4.8 KiB
C++
/*
|
|
* \brief Pager
|
|
* \author Norman Feske
|
|
* \date 2015-05-01
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2015-2017 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.
|
|
*/
|
|
|
|
/* core includes */
|
|
#include <pager.h>
|
|
#include <core_capability_space.h>
|
|
#include <install_mapping.h>
|
|
#include <platform.h>
|
|
|
|
/* base-internal includes */
|
|
#include <base/internal/capability_space_sel4.h>
|
|
|
|
#include "fault_info.h"
|
|
|
|
/* seL4 includes */
|
|
#include <sel4/sel4.h>
|
|
|
|
using namespace Genode;
|
|
|
|
/***************
|
|
** IPC pager **
|
|
***************/
|
|
|
|
|
|
void Ipc_pager::wait_for_fault()
|
|
{
|
|
if (_badge && _reply_sel) {
|
|
seL4_CNode const service = seL4_CapInitThreadCNode;
|
|
seL4_Word const index = _reply_sel;
|
|
uint8_t const depth = 32;
|
|
int ret = seL4_CNode_SaveCaller(service, index, depth);
|
|
if (ret != seL4_NoError)
|
|
Genode::error("saving reply cap failed with ", ret);
|
|
}
|
|
_reply_sel = 0;
|
|
_badge = 0;
|
|
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()
|
|
{
|
|
seL4_Word badge = Rpc_obj_key::INVALID;
|
|
|
|
seL4_MessageInfo_t page_fault_msg_info;
|
|
|
|
if (_badge) {
|
|
|
|
seL4_MessageInfo_t const reply_msg = seL4_MessageInfo_new(0, 0, 0, 0);
|
|
|
|
page_fault_msg_info =
|
|
seL4_ReplyRecv(Thread::myself()->native_thread().ep_sel, reply_msg, &badge);
|
|
|
|
} else {
|
|
page_fault_msg_info =
|
|
seL4_Recv(Thread::myself()->native_thread().ep_sel, &badge);
|
|
}
|
|
|
|
Fault_info const fault_info(page_fault_msg_info);
|
|
|
|
_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);
|
|
_pf_align = fault_info.align_fault();
|
|
|
|
_badge = badge;
|
|
}
|
|
|
|
|
|
Ipc_pager::Ipc_pager() { }
|
|
|
|
|
|
/******************
|
|
** Pager object **
|
|
******************/
|
|
|
|
Pager_object::Pager_object(Cpu_session_capability cpu_session,
|
|
Thread_capability thread,
|
|
unsigned long badge, Affinity::Location,
|
|
Session_label const &pd_label,
|
|
Cpu_session::Name const &name)
|
|
:
|
|
_badge(badge), _cpu_session_cap(cpu_session), _thread_cap(thread),
|
|
_reply_cap(platform_specific().core_sel_alloc().alloc()),
|
|
_pd_label(pd_label), _name(name)
|
|
{ }
|
|
|
|
|
|
Pager_object::~Pager_object()
|
|
{
|
|
seL4_CNode_Delete(seL4_CapInitThreadCNode, _reply_cap.value(), 32);
|
|
platform_specific().core_sel_alloc().free(_reply_cap);
|
|
/* invalidate reply cap for Pager_object::wait_for_fault() _reply_sel */
|
|
_reply_cap = Cap_sel(0);
|
|
}
|
|
|
|
|
|
void Pager_object::wake_up()
|
|
{
|
|
seL4_MessageInfo_t const send_msg = seL4_MessageInfo_new(0, 0, 0, 0);
|
|
seL4_Send(_reply_cap.value(), send_msg);
|
|
}
|
|
|
|
|
|
void Pager_object::unresolved_page_fault_occurred()
|
|
{
|
|
state.unresolved_page_fault = true;
|
|
}
|
|
|
|
|
|
/**********************
|
|
** Pager entrypoint **
|
|
**********************/
|
|
|
|
Untyped_capability Pager_entrypoint::_pager_object_cap(unsigned long badge)
|
|
{
|
|
/*
|
|
* Create minted endpoint capability of the pager entrypoint.
|
|
* The badge of the page-fault message is used to find the pager
|
|
* object for faulted thread.
|
|
*/
|
|
Rpc_obj_key rpc_obj_key((addr_t)badge);
|
|
|
|
Untyped_capability ep_cap(Capability_space::create_ep_cap(*this));
|
|
return Capability_space::create_rpc_obj_cap(ep_cap, nullptr, rpc_obj_key);
|
|
}
|
|
|
|
|
|
void Pager_entrypoint::dissolve(Pager_object &obj)
|
|
{
|
|
using Pool = Object_pool<Pager_object>;
|
|
|
|
Pool::remove(&obj);
|
|
}
|
|
|
|
|
|
Pager_capability Pager_entrypoint::manage(Pager_object &obj)
|
|
{
|
|
Native_capability cap = _pager_object_cap(obj.badge());
|
|
|
|
/* add server object to object pool */
|
|
obj.cap(cap);
|
|
insert(&obj);
|
|
|
|
/* return capability that uses the object id as badge */
|
|
return reinterpret_cap_cast<Pager_object>(cap);
|
|
}
|
|
|
|
|
|
void Pager_entrypoint::entry()
|
|
{
|
|
using Pool = Object_pool<Pager_object>;
|
|
|
|
bool reply_pending = false;
|
|
|
|
while (1) {
|
|
|
|
if (reply_pending)
|
|
_pager.reply_and_wait_for_fault();
|
|
else
|
|
_pager.wait_for_fault();
|
|
|
|
reply_pending = false;
|
|
|
|
Pool::apply(_pager.badge(), [&] (Pager_object *obj) {
|
|
if (!obj)
|
|
return;
|
|
|
|
/* send reply if page-fault handling succeeded */
|
|
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;
|
|
}
|
|
|
|
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();
|
|
}
|
|
});
|
|
}
|
|
}
|