core: unify and simplify paging code (Fix #1641)

For most platforms except of NOVA a distinction between pager entrypoint
and pager activation is not needed, and only exists due to historical
reasons. Moreover, the pager thread's execution path is almost identical
between most platforms excluding NOVA, HW, and Fisco.OC. Therefore,
this commit unifies the pager loop for the other platforms, and removes
the pager activation class.
This commit is contained in:
Stefan Kalkowski 2015-07-29 10:58:17 +02:00 committed by Christian Helmuth
parent a574f73005
commit eafe5e81e3
31 changed files with 644 additions and 1238 deletions

View File

@ -71,7 +71,7 @@ namespace Genode {
/**
* Special paging server class
*/
class Ipc_pager : public Native_capability
class Ipc_pager
{
private:
@ -96,11 +96,6 @@ namespace Genode {
public:
/**
* Constructor
*/
Ipc_pager();
/**
* Wait for a new page fault received as short message IPC
*/
@ -141,9 +136,9 @@ namespace Genode {
void acknowledge_wakeup();
/**
* Return thread ID of last faulter
* Returns true if the last request was send from a core thread
*/
Native_thread_id last() const { return _last; }
bool request_from_core() { return true; }
/**
* Return badge for faulting thread

View File

@ -1,175 +0,0 @@
/*
* \brief Pager support for Codezero
* \author Norman Feske
* \date 2010-02-16
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* Codezero includes */
#include <ipc_pager.h>
#include <codezero/syscalls.h>
using namespace Genode;
using namespace Codezero;
enum { verbose_page_faults = false };
/************************
** Page-fault utility **
************************/
class Fault
{
public:
enum Type { READ, WRITE, EXEC, UNKNOWN };
private:
/**
* Translate Codezero page-fault information to generic fault type
*
* \param sr status
* \param pte page-table entry
*/
static Type _fault_type(umword_t sr, umword_t pte)
{
if (is_prefetch_abort(sr))
return EXEC;
if ((pte & PTE_PROT_MASK) == (__MAP_USR_RO & PTE_PROT_MASK))
return WRITE;
return READ;
}
Type _type;
umword_t _addr;
umword_t _ip;
public:
/**
* Constructor
*
* \param kdata Codezero-specific page-fault information
*/
Fault(struct fault_kdata const &kdata)
:
_type(_fault_type(kdata.fsr, kdata.pte)),
_addr(_type == EXEC ? kdata.faulty_pc : kdata.far),
_ip(kdata.faulty_pc)
{ }
Type type() const { return _type; }
umword_t addr() const { return _addr; }
umword_t ip() const { return _ip; }
};
/**
* Print page-fault information in a human-readable form
*/
inline void print_page_fault(Fault &fault, int from)
{
printf("page (%s%s%s) fault from %d at pf_addr=%lx, pf_ip=%lx\n",
fault.type() == Fault::READ ? "r" : "-",
fault.type() == Fault::WRITE ? "w" : "-",
fault.type() == Fault::EXEC ? "x" : "-",
from, fault.addr(), fault.ip());
}
/***************
** IPC pager **
***************/
void Ipc_pager::wait_for_fault()
{
for (;;) {
int ret = l4_receive(L4_ANYTHREAD);
if (ret < 0) {
PERR("pager: l4_received returned ret=%d", ret);
continue;
}
umword_t tag = l4_get_tag();
int faulter_tid = l4_get_sender();
if (tag != L4_IPC_TAG_PFAULT) {
PWRN("got an unexpected IPC from %d", faulter_tid);
continue;
}
/* copy fault information from message registers */
struct fault_kdata fault_kdata;
for (unsigned i = 0; i < sizeof(fault_kdata_t)/sizeof(umword_t); i++)
((umword_t *)&fault_kdata)[i] = read_mr(MR_UNUSED_START + i);
Fault fault(fault_kdata);
if (verbose_page_faults)
print_page_fault(fault, faulter_tid);
/* determine corresponding page in our own address space */
_pf_addr = fault.addr();
_pf_write = fault.type() == Fault::WRITE;
_pf_ip = fault.ip();
_last = faulter_tid;
return;
}
}
void Ipc_pager::reply_and_wait_for_fault()
{
/* install mapping */
umword_t flags = _reply_mapping.writeable() ? MAP_USR_RW
: MAP_USR_RO;
/*
* XXX: remove heuristics for mapping device registers.
*/
if (_reply_mapping.from_phys() == 0x10120000 /* LCD */
|| _reply_mapping.from_phys() == 0x10006000 /* keyboard */
|| _reply_mapping.from_phys() == 0x10007000) /* mouse */
flags = MAP_USR_IO;
int ret = l4_map((void *)_reply_mapping.from_phys(),
(void *)_reply_mapping.to_virt(),
_reply_mapping.num_pages(), flags, _last);
/* wake up faulter if mapping succeeded */
if (ret < 0)
PERR("l4_map returned %d, putting thread %d to sleep", ret, _last);
else
acknowledge_wakeup();
/* wait for next page fault */
wait_for_fault();
}
void Ipc_pager::acknowledge_wakeup()
{
enum { SUCCESS = 0 };
l4_set_sender(_last);
l4_ipc_return(SUCCESS);
}
Ipc_pager::Ipc_pager() : Native_capability(thread_myself(), 0) { }

View File

@ -1,105 +1,182 @@
/*
* \brief Dummy pager framework
* \brief Pager support for Codezero
* \author Norman Feske
* \date 2009-10-02
* \date 2010-02-16
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Core includes */
/* Genode includes */
#include <base/printf.h>
#include <pager.h>
/* Codezero includes */
#include <ipc_pager.h>
#include <codezero/syscalls.h>
using namespace Genode;
using namespace Codezero;
enum { verbose_page_faults = false };
/**********************
** Pager activation **
**********************/
/************************
** Page-fault utility **
************************/
void Pager_activation_base::entry()
class Fault
{
Ipc_pager pager;
_cap = pager;
_cap_valid.unlock();
public:
bool reply = false;
enum Type { READ, WRITE, EXEC, UNKNOWN };
while (1) {
private:
if (reply)
pager.reply_and_wait_for_fault();
else
pager.wait_for_fault();
/**
* Translate Codezero page-fault information to generic fault type
*
* \param sr status
* \param pte page-table entry
*/
static Type _fault_type(umword_t sr, umword_t pte)
{
if (is_prefetch_abort(sr))
return EXEC;
/* lookup referenced object */
Object_pool<Pager_object>::Guard _obj(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
Pager_object * obj = _obj;
reply = false;
if ((pte & PTE_PROT_MASK) == (__MAP_USR_RO & PTE_PROT_MASK))
return WRITE;
/* handle request */
if (obj) {
reply = !obj->pager(pager);
/* something strange occurred - leave thread in pagefault */
return READ;
}
Type _type;
umword_t _addr;
umword_t _ip;
public:
/**
* Constructor
*
* \param kdata Codezero-specific page-fault information
*/
Fault(struct fault_kdata const &kdata)
:
_type(_fault_type(kdata.fsr, kdata.pte)),
_addr(_type == EXEC ? kdata.faulty_pc : kdata.far),
_ip(kdata.faulty_pc)
{ }
Type type() const { return _type; }
umword_t addr() const { return _addr; }
umword_t ip() const { return _ip; }
};
/**
* Print page-fault information in a human-readable form
*/
inline void print_page_fault(Fault &fault, int from)
{
printf("page (%s%s%s) fault from %d at pf_addr=%lx, pf_ip=%lx\n",
fault.type() == Fault::READ ? "r" : "-",
fault.type() == Fault::WRITE ? "w" : "-",
fault.type() == Fault::EXEC ? "x" : "-",
from, fault.addr(), fault.ip());
}
/***************
** IPC pager **
***************/
void Ipc_pager::wait_for_fault()
{
for (;;) {
int ret = l4_receive(L4_ANYTHREAD);
if (ret < 0) {
PERR("pager: l4_received returned ret=%d", ret);
continue;
}
/*
* We got a request from one of cores region-manager sessions
* to answer the pending page fault of a resolved region-manager
* client. Hence, we have to send the page-fault reply to the
* specified thread and answer the call of the region-manager
* session.
*
* When called from a region-manager session, we receive the
* core-local address of the targeted pager object via the
* first message word, which corresponds to the 'fault_ip'
* argument of normal page-fault messages.
*/
obj = reinterpret_cast<Pager_object *>(pager.fault_ip());
umword_t tag = l4_get_tag();
int faulter_tid = l4_get_sender();
/* send reply to the calling region-manager session */
pager.acknowledge_wakeup();
if (tag != L4_IPC_TAG_PFAULT) {
PWRN("got an unexpected IPC from %d", faulter_tid);
continue;
}
/* answer page fault of resolved pager object */
pager.set_reply_dst(obj->cap());
pager.acknowledge_wakeup();
/* copy fault information from message registers */
struct fault_kdata fault_kdata;
for (unsigned i = 0; i < sizeof(fault_kdata_t)/sizeof(umword_t); i++)
((umword_t *)&fault_kdata)[i] = read_mr(MR_UNUSED_START + i);
Fault fault(fault_kdata);
if (verbose_page_faults)
print_page_fault(fault, faulter_tid);
/* determine corresponding page in our own address space */
_pf_addr = fault.addr();
_pf_write = fault.type() == Fault::WRITE;
_pf_ip = fault.ip();
_last = faulter_tid;
return;
}
}
void Ipc_pager::reply_and_wait_for_fault()
{
/* install mapping */
umword_t flags = _reply_mapping.writeable() ? MAP_USR_RW
: MAP_USR_RO;
/*
* XXX: remove heuristics for mapping device registers.
*/
if (_reply_mapping.from_phys() == 0x10120000 /* LCD */
|| _reply_mapping.from_phys() == 0x10006000 /* keyboard */
|| _reply_mapping.from_phys() == 0x10007000) /* mouse */
flags = MAP_USR_IO;
int ret = l4_map((void *)_reply_mapping.from_phys(),
(void *)_reply_mapping.to_virt(),
_reply_mapping.num_pages(), flags, _last);
/* wake up faulter if mapping succeeded */
if (ret < 0)
PERR("l4_map returned %d, putting thread %d to sleep", ret, _last);
else
acknowledge_wakeup();
/* wait for next page fault */
wait_for_fault();
}
void Ipc_pager::acknowledge_wakeup()
{
enum { SUCCESS = 0 };
l4_set_sender(_last);
l4_ipc_return(SUCCESS);
}
/**********************
** Pager entrypoint **
**********************/
Pager_entrypoint::Pager_entrypoint(Cap_session *, Pager_activation_base *a)
: _activation(a)
{ _activation->ep(this); }
void Pager_entrypoint::dissolve(Pager_object *obj)
Untyped_capability Pager_entrypoint::_manage(Pager_object *obj)
{
remove_locked(obj);
}
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
/* return invalid capability if no activation is present */
if (!_activation) return Pager_capability();
_activation->cap();
Untyped_capability cap = Native_capability(_activation->cap().dst(), 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);
return Untyped_capability(_tid.l4id, obj->badge());
}

View File

@ -12,11 +12,11 @@ SRC_CC += cap_session_component.cc \
dump_alloc.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
ipc_pager.cc \
irq_session_component.cc \
main.cc \
pager.cc \
pager_common.cc \
pager_ep.cc \
pager_object.cc \
pd_session_component.cc \
platform.cc \
platform_pd.cc \
@ -58,5 +58,6 @@ vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)
vpath pager_common.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
vpath pager_object.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core

View File

@ -85,7 +85,7 @@ namespace Genode {
/**
* Special paging server class
*/
class Ipc_pager : public Native_capability
class Ipc_pager
{
private:
@ -96,11 +96,6 @@ namespace Genode {
public:
/**
* Constructor
*/
Ipc_pager();
/**
* Wait for a new page fault received as short message IPC
*/
@ -144,9 +139,13 @@ namespace Genode {
void acknowledge_wakeup();
/**
* Return thread ID of last faulter
* Returns true if the last request was send from a core thread
*/
Native_thread_id last() const { return _last; }
bool request_from_core()
{
enum { CORE_TASK_ID = 4 };
return _last.id.task == CORE_TASK_ID;
}
/**
* Return badge for faulting thread

View File

@ -1,72 +0,0 @@
/*
* \brief Pager support for Fiasco
* \author Christian Helmuth
* \date 2006-06-14
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* Core includes */
#include <ipc_pager.h>
namespace Fiasco {
#include <l4/sys/ipc.h>
#include <l4/sys/syscalls.h>
}
using namespace Genode;
using namespace Fiasco;
void Ipc_pager::wait_for_fault()
{
l4_msgdope_t result;
do {
l4_ipc_wait(&_last,
L4_IPC_SHORT_MSG, &_pf_addr, &_pf_ip,
L4_IPC_NEVER, &result);
if (L4_IPC_IS_ERROR(result))
PERR("Ipc error %lx", L4_IPC_ERROR(result));
} while (L4_IPC_IS_ERROR(result));
}
void Ipc_pager::reply_and_wait_for_fault()
{
l4_msgdope_t result;
l4_ipc_reply_and_wait(_last,
L4_IPC_SHORT_FPAGE, _reply_mapping.dst_addr(),
_reply_mapping.fpage().fpage, &_last,
L4_IPC_SHORT_MSG, &_pf_addr, &_pf_ip,
L4_IPC_SEND_TIMEOUT_0, &result);
if (L4_IPC_IS_ERROR(result)) {
PERR("Ipc error %lx", L4_IPC_ERROR(result));
/* ignore all errors and wait for next proper message */
wait_for_fault();
}
}
void Ipc_pager::acknowledge_wakeup()
{
/* answer wakeup call from one of core's region-manager sessions */
l4_msgdope_t result;
l4_ipc_send(_last, L4_IPC_SHORT_MSG, 0, 0, L4_IPC_SEND_TIMEOUT_0, &result);
}
Ipc_pager::Ipc_pager() : Native_capability(Fiasco::l4_myself(), 0) { }

View File

@ -1,10 +1,7 @@
/*
* \brief Fiasco pager framework
* \author Norman Feske
* \brief Pager support for Fiasco
* \author Christian Helmuth
* \date 2006-07-14
*
* FIXME Isn't this file generic?
* \date 2006-06-14
*/
/*
@ -14,7 +11,11 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* Core includes */
#include <ipc_pager.h>
#include <pager.h>
namespace Fiasco {
@ -23,101 +24,61 @@ namespace Fiasco {
}
using namespace Genode;
using namespace Fiasco;
/**********************
** Pager activation **
**********************/
/***************
** Ipc_pager **
***************/
void Pager_activation_base::entry()
void Ipc_pager::wait_for_fault()
{
Ipc_pager pager;
_cap = pager;
_cap_valid.unlock();
l4_msgdope_t result;
Pager_object * obj;
bool reply = false;
do {
l4_ipc_wait(&_last,
L4_IPC_SHORT_MSG, &_pf_addr, &_pf_ip,
L4_IPC_NEVER, &result);
while (1) {
if (L4_IPC_IS_ERROR(result))
PERR("Ipc error %lx", L4_IPC_ERROR(result));
if (reply)
pager.reply_and_wait_for_fault();
else
pager.wait_for_fault();
} while (L4_IPC_IS_ERROR(result));
}
/* lookup referenced object */
Object_pool<Pager_object>::Guard _obj(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
obj = _obj;
reply = false;
/* handle request */
if (obj) {
reply = !obj->pager(pager);
/* something strange occurred - leave thread in pagefault */
continue;
} else {
void Ipc_pager::reply_and_wait_for_fault()
{
l4_msgdope_t result;
/* prevent threads outside of core to mess with our wake-up interface */
enum { CORE_TASK_ID = 4 };
if (pager.last().id.task != CORE_TASK_ID) {
l4_ipc_reply_and_wait(_last,
L4_IPC_SHORT_FPAGE, _reply_mapping.dst_addr(),
_reply_mapping.fpage().fpage, &_last,
L4_IPC_SHORT_MSG, &_pf_addr, &_pf_ip,
L4_IPC_SEND_TIMEOUT_0, &result);
PWRN("page fault from unknown partner %x.%02x",
(int)pager.last().id.task, (int)pager.last().id.lthread);
if (L4_IPC_IS_ERROR(result)) {
PERR("Ipc error %lx", L4_IPC_ERROR(result));
} else {
/* ignore all errors and wait for next proper message */
wait_for_fault();
}
}
/*
* We got a request from one of cores region-manager sessions
* to answer the pending page fault of a resolved region-manager
* client. Hence, we have to send the page-fault reply to the
* specified thread and answer the call of the region-manager
* session.
*
* When called from a region-manager session, we receive the
* core-local address of the targeted pager object via the
* first message word, which corresponds to the 'fault_ip'
* argument of normal page-fault messages.
*/
obj = reinterpret_cast<Pager_object *>(pager.fault_ip());
/* send reply to the calling region-manager session */
pager.acknowledge_wakeup();
/* answer page fault of resolved pager object */
pager.set_reply_dst(obj->cap());
pager.acknowledge_wakeup();
}
}
};
void Ipc_pager::acknowledge_wakeup()
{
/* answer wakeup call from one of core's region-manager sessions */
l4_msgdope_t result;
l4_ipc_send(_last, L4_IPC_SHORT_MSG, 0, 0, L4_IPC_SEND_TIMEOUT_0, &result);
}
/**********************
** Pager entrypoint **
** Pager Entrypoint **
**********************/
Pager_entrypoint::Pager_entrypoint(Cap_session *, Pager_activation_base *a)
: _activation(a)
{ _activation->ep(this); }
void Pager_entrypoint::dissolve(Pager_object *obj)
Untyped_capability Pager_entrypoint::_manage(Pager_object *obj)
{
remove_locked(obj);
}
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
/* return invalid capability if no activation is present */
if (!_activation) return Pager_capability();
Native_capability cap(_activation->cap().dst(), 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);
return Untyped_capability(_tid.l4id, obj->badge());
}

View File

@ -12,12 +12,12 @@ SRC_CC += cap_session_component.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
io_port_session_component.cc \
ipc_pager.cc \
irq_session_component.cc \
main.cc \
multiboot_info.cc \
pager.cc \
pager_common.cc \
pager_ep.cc \
pager_object.cc \
pd_session_component.cc \
platform.cc \
platform_pd.cc \
@ -58,6 +58,7 @@ vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)
vpath pager_common.cc $(GEN_CORE_DIR)
vpath pager_object.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/base/console
vpath %.cc $(REP_DIR)/src/core

View File

@ -4,8 +4,6 @@
* \author Christian Helmuth
* \author Stefan Kalkowski
* \date 2006-07-14
*
* FIXME Isn't this file generic?
*/
/*
@ -32,33 +30,20 @@ namespace Fiasco {
using namespace Genode;
/**********************
** Pager activation **
**********************/
void Pager_activation_base::entry()
void Pager_entrypoint::entry()
{
Ipc_pager pager;
_cap = Native_capability(Thread_base::_thread_cap);
_cap_valid.unlock();
bool reply_pending = false;
while (1) {
if (reply_pending)
pager.reply_and_wait_for_fault();
_pager.reply_and_wait_for_fault();
else
pager.wait_for_fault();
_pager.wait_for_fault();
reply_pending = false;
if (!_ep) {
PWRN("Pager entrypoint not yet defined");
continue;
}
/* lookup referenced object */
Object_pool<Pager_object>::Guard obj(_ep->lookup_and_lock(pager.badge()));
Object_pool<Pager_object>::Guard obj(lookup_and_lock(_pager.badge()));
/* the pager_object might be destroyed, while we got the message */
if (!obj) {
@ -66,14 +51,14 @@ void Pager_activation_base::entry()
continue;
}
switch (pager.msg_type()) {
switch (_pager.msg_type()) {
case Ipc_pager::PAGEFAULT:
case Ipc_pager::EXCEPTION:
{
if (pager.is_exception()) {
if (_pager.is_exception()) {
Lock::Guard guard(obj->state.lock);
pager.get_regs(&obj->state);
_pager.get_regs(&obj->state);
obj->state.exceptions++;
obj->state.in_exception = true;
obj->submit_exception_signal();
@ -81,12 +66,12 @@ void Pager_activation_base::entry()
}
/* handle request */
if (obj->pager(pager)) {
if (obj->pager(_pager)) {
/* could not resolv - leave thread in pagefault */
PDBG("Could not resolve pf=%p ip=%p",
(void*)pager.fault_addr(), (void*)pager.fault_ip());
(void*)_pager.fault_addr(), (void*)_pager.fault_ip());
} else {
pager.set_reply_dst(obj->badge());
_pager.set_reply_dst(obj->badge());
reply_pending = true;
continue;
}
@ -104,20 +89,20 @@ void Pager_activation_base::entry()
*/
/* send reply to the caller */
pager.set_reply_dst(Native_thread());
pager.acknowledge_wakeup();
_pager.set_reply_dst(Native_thread());
_pager.acknowledge_wakeup();
{
Lock::Guard guard(obj->state.lock);
/* revert exception flag */
obj->state.in_exception = false;
/* set new register contents */
pager.set_regs(obj->state);
_pager.set_regs(obj->state);
}
/* send wake up message to requested thread */
pager.set_reply_dst(obj->badge());
pager.acknowledge_exception();
_pager.set_reply_dst(obj->badge());
_pager.acknowledge_exception();
break;
}
@ -128,7 +113,7 @@ void Pager_activation_base::entry()
case Ipc_pager::PAUSE:
{
Lock::Guard guard(obj->state.lock);
pager.get_regs(&obj->state);
_pager.get_regs(&obj->state);
obj->state.exceptions++;
obj->state.in_exception = true;
@ -138,31 +123,19 @@ void Pager_activation_base::entry()
* that case we unblock it immediately.
*/
if (!obj->state.paused) {
pager.set_reply_dst(obj->badge());
_pager.set_reply_dst(obj->badge());
reply_pending = true;
}
break;
}
default:
PERR("Got unknown message type %x!", pager.msg_type());
PERR("Got unknown message type %x!", _pager.msg_type());
}
};
}
/**********************
** Pager entrypoint **
**********************/
Pager_entrypoint::Pager_entrypoint(Cap_session *cap_session,
Pager_activation_base *a)
: _activation(a), _cap_session(cap_session)
{
_activation->ep(this);
}
void Pager_entrypoint::dissolve(Pager_object *obj)
{
/* cleanup at cap session */
@ -176,11 +149,7 @@ Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
using namespace Fiasco;
/* return invalid capability if no activation is present */
if (!_activation) return Pager_capability();
Native_capability c = _activation->cap();
Native_capability cap(_cap_session->alloc(c));
Native_capability cap(_cap_session->alloc({Thread_base::_thread_cap}));
/* add server object to object pool */
obj->cap(cap);

View File

@ -19,7 +19,7 @@ SRC_CC += cap_session_component.cc \
main.cc \
multiboot_info.cc \
pager.cc \
pager_common.cc \
pager_object.cc \
pd_session_component.cc \
pd_session_extension.cc \
platform.cc \
@ -59,7 +59,7 @@ vpath rm_session_component.cc $(GEN_CORE_DIR)
vpath rom_session_component.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath pager_common.cc $(GEN_CORE_DIR)
vpath pager_object.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/base/console
vpath %.cc $(REP_DIR)/src/core
vpath %.cc $(REP_DIR)/src/base/thread

View File

@ -47,15 +47,7 @@ namespace Genode
*/
class Pager_entrypoint;
/**
* A thread that processes one page fault of a pager object at a time
*/
class Pager_activation_base;
/**
* Pager-activation base with custom stack size
*/
template <unsigned STACK_SIZE> class Pager_activation;
enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 };
}
struct Genode::Mapping
@ -198,26 +190,30 @@ class Genode::Pager_object
void thread_cap(Thread_capability const & c);
};
class Genode::Pager_activation_base
: public Thread_base,
public Kernel_object<Kernel::Signal_receiver>,
public Ipc_pager
class Genode::Pager_entrypoint : public Object_pool<Pager_object>,
public Thread<PAGER_EP_STACK_SIZE>,
public Kernel_object<Kernel::Signal_receiver>,
public Ipc_pager
{
private:
Lock _startup_lock;
Pager_entrypoint * _ep;
public:
/**
* Constructor
*
* \param name name of the new thread
* \param stack_size stack size of the new thread
* \param a activation that shall handle the objects of the entrypoint
*/
Pager_activation_base(char const * const name,
size_t const stack_size);
Pager_entrypoint(Cap_session * cap_session);
/**
* Associate pager object 'obj' with entry point
*/
Pager_capability manage(Pager_object * const obj);
/**
* Dissolve pager object 'obj' from entry point
*/
void dissolve(Pager_object * const obj);
/**
* Bring current mapping data into effect
@ -233,55 +229,6 @@ class Genode::Pager_activation_base
**********************/
void entry();
/***************
** Accessors **
***************/
void ep(Pager_entrypoint * const ep);
};
class Genode::Pager_entrypoint : public Object_pool<Pager_object>
{
private:
Pager_activation_base * const _activation;
public:
/**
* Constructor
*
* \param a activation that shall handle the objects of the entrypoint
*/
Pager_entrypoint(Cap_session *, Pager_activation_base * const a);
/**
* Associate pager object 'obj' with entry point
*/
Pager_capability manage(Pager_object * const obj);
/**
* Dissolve pager object 'obj' from entry point
*/
void dissolve(Pager_object * const obj);
};
template <unsigned STACK_SIZE>
class Genode::Pager_activation : public Pager_activation_base
{
public:
/**
* Constructor
*/
Pager_activation()
:
Pager_activation_base("pager_activation", STACK_SIZE)
{
start();
}
};
#endif /* _CORE__INCLUDE__PAGER_H_ */

View File

@ -97,21 +97,6 @@ Pager_object::Pager_object(unsigned const badge, Affinity::Location)
{ }
/***************************
** Pager_activation_base **
***************************/
void Pager_activation_base::ep(Pager_entrypoint * const ep) { _ep = ep; }
Pager_activation_base::Pager_activation_base(char const * const name,
size_t const stack_size)
: Thread_base(0, name, stack_size),
Kernel_object<Kernel::Signal_receiver>(true),
_startup_lock(Lock::LOCKED), _ep(0)
{ }
/**********************
** Pager_entrypoint **
**********************/
@ -122,15 +107,16 @@ void Pager_entrypoint::dissolve(Pager_object * const o)
}
Pager_entrypoint::Pager_entrypoint(Cap_session *,
Pager_activation_base * const activation)
: _activation(activation) {
_activation->ep(this); }
Pager_entrypoint::Pager_entrypoint(Cap_session *)
: Thread<PAGER_EP_STACK_SIZE>("pager_ep"),
Kernel_object<Kernel::Signal_receiver>(true)
{ start(); }
Pager_capability Pager_entrypoint::manage(Pager_object * const o)
{
o->start_paging(_activation->kernel_object());
o->start_paging(kernel_object());
insert(o);
return reinterpret_cap_cast<Pager_object>(o->cap());
}

View File

@ -36,11 +36,11 @@ void Rm_client::unmap(addr_t, addr_t virt_base, size_t size)
}
/***************************
** Pager_activation_base **
***************************/
/**********************
** Pager_entrypoint **
**********************/
int Pager_activation_base::apply_mapping()
int Pager_entrypoint::apply_mapping()
{
Page_flags const flags =
Page_flags::apply_mapping(_mapping.writable,
@ -54,10 +54,8 @@ int Pager_activation_base::apply_mapping()
}
void Pager_activation_base::entry()
void Pager_entrypoint::entry()
{
/* get ready to receive faults */
_startup_lock.unlock();
while (1)
{
/* receive fault */
@ -71,7 +69,7 @@ void Pager_activation_base::entry()
* FIXME: The implicit lookup of the oject isn't needed.
*/
unsigned const pon = po->cap().local_name();
Object_pool<Pager_object>::Guard pog(_ep->lookup_and_lock(pon));
Object_pool<Pager_object>::Guard pog(lookup_and_lock(pon));
if (!pog) continue;
/* fetch fault data */

View File

@ -45,14 +45,12 @@ namespace Genode {
void release() { }
};
class Pager_activation_base { };
struct Pager_entrypoint
{
Pager_entrypoint(Cap_session *, Pager_activation_base *) { }
Pager_entrypoint(Cap_session *) { }
Pager_object *lookup_and_lock(Pager_capability) { return 0; }
};
template <int FOO> class Pager_activation : public Pager_activation_base { };
}
#endif /* _CORE__INCLUDE__PAGER_H_ */

View File

@ -379,9 +379,8 @@ namespace Genode {
* \param cap_session Cap_session for creating capabilities
* for the pager objects managed by this
* entry point
* \param a initial activation
*/
Pager_entrypoint(Cap_session *cap_session, Pager_activation_base *a = 0);
Pager_entrypoint(Cap_session *cap_session);
/**
* Associate Pager_object with the entry point

View File

@ -620,9 +620,8 @@ void Pager_activation_base::entry() { }
**********************/
Pager_entrypoint::Pager_entrypoint(Cap_session *cap_session,
Pager_activation_base *a)
: _activation(a), _cap_session(cap_session)
Pager_entrypoint::Pager_entrypoint(Cap_session *cap_session)
: _cap_session(cap_session)
{
/* sanity check space for pager threads */
if (kernel_hip()->cpu_max() > PAGER_CPUS) {
@ -631,20 +630,11 @@ Pager_entrypoint::Pager_entrypoint(Cap_session *cap_session,
nova_die();
}
/* determine boot cpu */
unsigned master_cpu = boot_cpu();
/* detect enabled CPUs and create per CPU a pager thread */
typedef Pager_activation<PAGER_STACK_SIZE> Pager;
Pager * pager_of_cpu = reinterpret_cast<Pager *>(&pager_activation_mem);
for (unsigned i = 0; i < kernel_hip()->cpu_max(); i++, pager_of_cpu++) {
if (i == master_cpu) {
pager_threads[master_cpu] = a;
a->ep(this);
continue;
}
if (!kernel_hip()->is_cpu_enabled(i))
continue;

View File

@ -73,7 +73,7 @@ namespace Genode {
/**
* Special paging server class
*/
class Ipc_pager : public Native_capability
class Ipc_pager
{
private:
@ -99,11 +99,6 @@ namespace Genode {
public:
/**
* Constructor
*/
Ipc_pager();
/**
* Wait for a new fault received as short message IPC
*/
@ -147,14 +142,13 @@ namespace Genode {
void acknowledge_wakeup();
/**
* Return thread ID of last faulter
* Returns true if the last request was send from a core thread
*/
Native_thread_id last() const { return _last; }
/**
* Return address space where the last page fault occurred
*/
unsigned long last_space() const { return _last_space; }
bool request_from_core() const
{
enum { CORE_SPACE = 0 };
return _last_space == CORE_SPACE;
}
/**
* Return badge for faulting thread

View File

@ -1,148 +0,0 @@
/*
* \brief Pager support for OKL4
* \author Norman Feske
* \date 2009-03-31
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* Core includes */
#include <ipc_pager.h>
namespace Okl4 { extern "C" {
#include <l4/message.h>
#include <l4/ipc.h>
#include <l4/schedule.h>
#include <l4/kdebug.h>
} }
static const bool verbose_page_fault = false;
static const bool verbose_exception = false;
using namespace Genode;
using namespace Okl4;
/**
* Print page-fault information in a human-readable form
*/
static inline void print_page_fault(L4_Word_t type, L4_Word_t addr, L4_Word_t ip,
unsigned long badge)
{
printf("page (%s%s%s) fault at fault_addr=%lx, fault_ip=%lx, from=%lx\n",
type & L4_Readable ? "r" : "-",
type & L4_Writable ? "w" : "-",
type & L4_eXecutable ? "x" : "-",
addr, ip, badge);
}
/**
* Return the global thread ID of the calling thread
*
* On OKL4 we cannot use 'L4_Myself()' to determine our own thread's
* identity. By convention, each thread stores its global ID in a
* defined entry of its UTCB.
*/
static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
{
Okl4::L4_ThreadId_t myself;
myself.raw = Okl4::__L4_TCR_ThreadWord(UTCB_TCR_THREAD_WORD_MYSELF);
return myself;
}
/*************
** Mapping **
*************/
Mapping::Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute cacheability, bool io_mem,
unsigned l2size, bool rw)
:
_fpage(L4_FpageLog2(dst_addr, l2size)),
/*
* OKL4 does not support write-combining as mapping attribute.
*/
_phys_desc(L4_PhysDesc(src_addr, 0))
{
L4_Set_Rights(&_fpage, rw ? L4_ReadWriteOnly : L4_ReadeXecOnly);
}
Mapping::Mapping() { }
/***************
** IPC pager **
***************/
void Ipc_pager::wait_for_fault()
{
/* wait for fault */
_faulter_tag = L4_Wait(&_last);
/*
* Read fault information
*/
/* exception */
if (is_exception()) {
L4_StoreMR(1, &_fault_ip);
if (verbose_exception)
PERR("Exception (label 0x%x) occured in space %d at IP 0x%p",
(int)L4_Label(_faulter_tag), (int)L4_SenderSpace().raw,
(void *)_fault_ip);
}
/* page fault */
else {
L4_StoreMR(1, &_fault_addr);
L4_StoreMR(2, &_fault_ip);
if (verbose_page_fault)
print_page_fault(L4_Label(_faulter_tag), _fault_addr, _fault_ip, _last.raw);
}
_last_space = L4_SenderSpace().raw;
}
void Ipc_pager::reply_and_wait_for_fault()
{
L4_SpaceId_t to_space;
to_space.raw = L4_ThreadNo(_last) >> Thread_id_bits::THREAD;
/* map page to faulting space */
int ret = L4_MapFpage(to_space, _reply_mapping.fpage(),
_reply_mapping.phys_desc());
if (ret != 1)
PERR("L4_MapFpage returned %d, error_code=%d",
ret, (int)L4_ErrorCode());
/* reply to page-fault message to resume the faulting thread */
acknowledge_wakeup();
wait_for_fault();
}
void Ipc_pager::acknowledge_wakeup()
{
/* answer wakeup call from one of core's region-manager sessions */
L4_LoadMR(0, 0);
L4_Send(_last);
}
Ipc_pager::Ipc_pager() : Native_capability(thread_get_my_global_id(), 0) { }

View File

@ -1,5 +1,5 @@
/*
* \brief OKL4-specific pager framework
* \brief Pager support for OKL4
* \author Norman Feske
* \date 2009-03-31
*/
@ -11,85 +11,137 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* Core includes */
#include <ipc_pager.h>
#include <pager.h>
namespace Okl4 { extern "C" {
#include <l4/message.h>
#include <l4/ipc.h>
#include <l4/schedule.h>
#include <l4/kdebug.h>
} }
static const bool verbose_page_fault = false;
static const bool verbose_exception = false;
using namespace Genode;
using namespace Okl4;
/**********************
** Pager activation **
**********************/
void Pager_activation_base::entry()
/**
* Print page-fault information in a human-readable form
*/
static inline void print_page_fault(L4_Word_t type, L4_Word_t addr, L4_Word_t ip,
unsigned long badge)
{
Ipc_pager pager;
_cap = pager;
_cap_valid.unlock();
printf("page (%s%s%s) fault at fault_addr=%lx, fault_ip=%lx, from=%lx\n",
type & L4_Readable ? "r" : "-",
type & L4_Writable ? "w" : "-",
type & L4_eXecutable ? "x" : "-",
addr, ip, badge);
}
bool reply_pending = false;
while (1) {
if (reply_pending)
pager.reply_and_wait_for_fault();
else
pager.wait_for_fault();
/**
* Return the global thread ID of the calling thread
*
* On OKL4 we cannot use 'L4_Myself()' to determine our own thread's
* identity. By convention, each thread stores its global ID in a
* defined entry of its UTCB.
*/
static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
{
Okl4::L4_ThreadId_t myself;
myself.raw = Okl4::__L4_TCR_ThreadWord(UTCB_TCR_THREAD_WORD_MYSELF);
return myself;
}
reply_pending = false;
/* lookup referenced object */
Object_pool<Pager_object>::Guard _obj(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
Pager_object *obj = _obj;
/*************
** Mapping **
*************/
/* handle request */
if (obj) {
if (pager.is_exception()) {
obj->submit_exception_signal();
continue;
}
Mapping::Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute cacheability, bool io_mem,
unsigned l2size, bool rw)
:
_fpage(L4_FpageLog2(dst_addr, l2size)),
/*
* OKL4 does not support write-combining as mapping attribute.
*/
_phys_desc(L4_PhysDesc(src_addr, 0))
{
L4_Set_Rights(&_fpage, rw ? L4_ReadWriteOnly : L4_ReadeXecOnly);
}
/* send reply if page-fault handling succeeded */
if (!obj->pager(pager))
reply_pending = true;
continue;
Mapping::Mapping() { }
} else {
/*
* Prevent threads outside of core to mess with our wake-up
* interface. This condition can trigger if a process gets
* destroyed which triggered a page fault shortly before getting
* killed. In this case, 'wait_for_fault()' returns (because of
* the page fault delivery) but the pager-object lookup will fail
* (because core removed the process already).
*/
enum { CORE_SPACE = 0 };
if (pager.last_space() == CORE_SPACE) {
/***************
** IPC pager **
***************/
/*
* We got a request from one of cores region-manager sessions
* to answer the pending page fault of a resolved region-manager
* client. Hence, we have to send the page-fault reply to the
* specified thread and answer the call of the region-manager
* session.
*
* When called from a region-manager session, we receive the
* core-local address of the targeted pager object via the
* first message word, which corresponds to the 'fault_ip'
* argument of normal page-fault messages.
*/
obj = reinterpret_cast<Pager_object *>(pager.fault_ip());
void Ipc_pager::wait_for_fault()
{
/* wait for fault */
_faulter_tag = L4_Wait(&_last);
/* send reply to the calling region-manager session */
pager.acknowledge_wakeup();
/*
* Read fault information
*/
/* answer page fault of resolved pager object */
pager.set_reply_dst(obj->cap());
pager.acknowledge_wakeup();
}
}
};
/* exception */
if (is_exception()) {
L4_StoreMR(1, &_fault_ip);
if (verbose_exception)
PERR("Exception (label 0x%x) occured in space %d at IP 0x%p",
(int)L4_Label(_faulter_tag), (int)L4_SenderSpace().raw,
(void *)_fault_ip);
}
/* page fault */
else {
L4_StoreMR(1, &_fault_addr);
L4_StoreMR(2, &_fault_ip);
if (verbose_page_fault)
print_page_fault(L4_Label(_faulter_tag), _fault_addr, _fault_ip, _last.raw);
}
_last_space = L4_SenderSpace().raw;
}
void Ipc_pager::reply_and_wait_for_fault()
{
L4_SpaceId_t to_space;
to_space.raw = L4_ThreadNo(_last) >> Thread_id_bits::THREAD;
/* map page to faulting space */
int ret = L4_MapFpage(to_space, _reply_mapping.fpage(),
_reply_mapping.phys_desc());
if (ret != 1)
PERR("L4_MapFpage returned %d, error_code=%d",
ret, (int)L4_ErrorCode());
/* reply to page-fault message to resume the faulting thread */
acknowledge_wakeup();
wait_for_fault();
}
void Ipc_pager::acknowledge_wakeup()
{
/* answer wakeup call from one of core's region-manager sessions */
L4_LoadMR(0, 0);
L4_Send(_last);
}
@ -97,28 +149,7 @@ void Pager_activation_base::entry()
** Pager entrypoint **
**********************/
Pager_entrypoint::Pager_entrypoint(Cap_session *, Pager_activation_base *a)
: _activation(a)
{ _activation->ep(this); }
void Pager_entrypoint::dissolve(Pager_object *obj)
Untyped_capability Pager_entrypoint::_manage(Pager_object *obj)
{
remove_locked(obj);
}
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
/* return invalid capability if no activation is present */
if (!_activation) return Pager_capability();
Native_capability cap = Native_capability(_activation->cap().dst(), 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);
return Untyped_capability(_tid.l4id, obj->badge());
}

View File

@ -15,12 +15,12 @@ SRC_CC += cap_session_component.cc \
dump_alloc.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
ipc_pager.cc \
irq_session_component.cc \
main.cc \
okl4_pd_session_component.cc \
pager.cc \
pager_common.cc \
pager_ep.cc \
pager_object.cc \
pd_session_component.cc \
platform.cc \
platform_pd.cc \
@ -61,7 +61,8 @@ vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)
vpath pager_common.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
vpath pager_object.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core
vpath core_printf.cc $(BASE_DIR)/src/base/console

View File

@ -83,7 +83,7 @@ namespace Genode {
/**
* Special paging server class
*/
class Ipc_pager : public Native_capability
class Ipc_pager
{
private:
@ -108,11 +108,6 @@ namespace Genode {
public:
/**
* Constructor
*/
Ipc_pager();
/**
* Wait for a new fault received as short message IPC
*/
@ -156,9 +151,9 @@ namespace Genode {
void acknowledge_wakeup();
/**
* Return thread ID of last faulter
* Returns true if the last request was send from a core thread
*/
Native_thread_id last() const { return _last; }
bool request_from_core() { return true; }
/**
* Return badge for faulting thread

View File

@ -1,141 +0,0 @@
/*
* \brief Pager support for Pistachio
* \author Christian Helmuth
* \date 2006-06-14
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/sleep.h>
/* Core includes */
#include <ipc_pager.h>
namespace Pistachio
{
#include <l4/message.h>
#include <l4/ipc.h>
#include <l4/schedule.h>
#include <l4/kdebug.h>
}
using namespace Genode;
using namespace Pistachio;
/*************
** Mapping **
*************/
Mapping::Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute, bool io_mem, unsigned l2size,
bool rw, bool grant)
{
L4_Fpage_t fpage = L4_FpageLog2(src_addr, l2size);
fpage += rw ? L4_FullyAccessible : L4_Readable;
if (grant)
_grant_item = L4_GrantItem(fpage, dst_addr);
else
_map_item = L4_MapItem(fpage, dst_addr);
}
Mapping::Mapping() { _map_item = L4_MapItem(L4_Nilpage, 0); }
/***************
** IPC pager **
***************/
void Ipc_pager::wait_for_fault()
{
L4_MsgTag_t result;
L4_ThreadId_t sender = L4_nilthread;
bool failed;
do {
L4_Accept(L4_UntypedWordsAcceptor);
result = L4_Wait(&sender);
failed = L4_IpcFailed(result);
if (failed)
PERR("Page fault IPC error. (continuable)");
if (L4_UntypedWords(result) != 2) {
PERR("Malformed page-fault ipc. (sender = 0x%08lx)",
sender.raw);
failed = true;
}
} while (failed);
L4_Msg_t msg;
// TODO Error checking. Did we really receive 2 words?
L4_Store(result, &msg);
_pf_addr = L4_Get(&msg, 0);
_pf_ip = L4_Get(&msg, 1);
_flags = L4_Label(result);
_last = sender;
}
void Ipc_pager::reply_and_wait_for_fault()
{
/*
* XXX call memory-control if mapping has enabled write-combining
*/
L4_Msg_t msg;
L4_Accept(L4_UntypedWordsAcceptor);
L4_Clear(&msg);
/* this should work even if _map_item is a grant item */
L4_Append(&msg, _map_item);
L4_Load(&msg);
L4_MsgTag_t result = L4_ReplyWait(_last, &_last);
if (L4_IpcFailed(result)) {
PERR("Page fault IPC error. (continuable)");
wait_for_fault();
return;
}
if (L4_UntypedWords(result) != 2) {
PERR("Malformed page-fault ipc. (sender = 0x%08lx)", _last.raw);
wait_for_fault();
return;
}
L4_Clear(&msg);
// TODO Error checking. Did we really receive 2 words?
L4_Store(result, &msg);
_pf_addr = L4_Get(&msg, 0);
_pf_ip = L4_Get(&msg, 1);
_flags = L4_Label(result);
}
void Ipc_pager::acknowledge_wakeup()
{
PERR("acknowledge_wakeup called, not yet implemented");
// /* answer wakeup call from one of core's region-manager sessions */
// l4_msgdope_t result;
// l4_ipc_send(_last, L4_IPC_SHORT_MSG, 0, 0, L4_IPC_SEND_TIMEOUT_0, &result);
}
Ipc_pager::Ipc_pager()
: Native_capability(L4_Myself(), 0)
{ }

View File

@ -1,10 +1,7 @@
/*
* \brief Pistachio pager framework
* \author Norman Feske
* \brief Pager support for Pistachio
* \author Christian Helmuth
* \date 2006-07-14
*
* FIXME Isn't this file generic?
* \date 2006-06-14
*/
/*
@ -14,83 +11,128 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/sleep.h>
/* Core includes */
#include <ipc_pager.h>
#include <pager.h>
using namespace Genode;
namespace Pistachio {
#include <l4/thread.h>
namespace Pistachio
{
#include <l4/message.h>
#include <l4/ipc.h>
#include <l4/schedule.h>
#include <l4/kdebug.h>
}
/**********************
** Pager activation **
**********************/
using namespace Genode;
using namespace Pistachio;
void Pager_activation_base::entry()
/*************
** Mapping **
*************/
Mapping::Mapping(addr_t dst_addr, addr_t src_addr,
Cache_attribute, bool io_mem, unsigned l2size,
bool rw, bool grant)
{
Ipc_pager pager;
_cap = pager;
_cap_valid.unlock();
L4_Fpage_t fpage = L4_FpageLog2(src_addr, l2size);
Pager_object * obj;
bool reply = false;
fpage += rw ? L4_FullyAccessible : L4_Readable;
while (1) {
if (grant)
_grant_item = L4_GrantItem(fpage, dst_addr);
else
_map_item = L4_MapItem(fpage, dst_addr);
}
if (reply)
pager.reply_and_wait_for_fault();
else
pager.wait_for_fault();
/* lookup referenced object */
Object_pool<Pager_object>::Guard _obj(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
obj = _obj;
reply = false;
Mapping::Mapping() { _map_item = L4_MapItem(L4_Nilpage, 0); }
/* handle request */
if (obj) {
/* if something strange occurred - leave thread in pagefault */
reply = !obj->pager(pager);
continue;
} else {
/* prevent threads outside of core to mess with our wake-up interface */
// enum { CORE_TASK_ID = 4 };
// if (pager.last().id.task != CORE_TASK_ID) {
/***************
** IPC pager **
***************/
#warning Check for messages from outside of core
if (0) {
PWRN("page fault to 0x%08lx from unknown partner %lx.",
Pistachio::L4_Myself().raw,
pager.last().raw);
void Ipc_pager::wait_for_fault()
{
L4_MsgTag_t result;
L4_ThreadId_t sender = L4_nilthread;
bool failed;
} else {
do {
L4_Accept(L4_UntypedWordsAcceptor);
result = L4_Wait(&sender);
failed = L4_IpcFailed(result);
if (failed)
PERR("Page fault IPC error. (continuable)");
/*
* We got a request from one of cores region-manager sessions
* to answer the pending page fault of a resolved region-manager
* client. Hence, we have to send the page-fault reply to the
* specified thread and answer the call of the region-manager
* session.
*
* When called from a region-manager session, we receive the
* core-local address of the targeted pager object via the
* first message word, which corresponds to the 'fault_ip'
* argument of normal page-fault messages.
*/
obj = reinterpret_cast<Pager_object *>(pager.fault_ip());
/* send reply to the calling region-manager session */
pager.acknowledge_wakeup();
/* answer page fault of resolved pager object */
pager.set_reply_dst(obj->cap());
pager.acknowledge_wakeup();
}
if (L4_UntypedWords(result) != 2) {
PERR("Malformed page-fault ipc. (sender = 0x%08lx)",
sender.raw);
failed = true;
}
} while (failed);
L4_Msg_t msg;
// TODO Error checking. Did we really receive 2 words?
L4_Store(result, &msg);
_pf_addr = L4_Get(&msg, 0);
_pf_ip = L4_Get(&msg, 1);
_flags = L4_Label(result);
_last = sender;
}
void Ipc_pager::reply_and_wait_for_fault()
{
/*
* XXX call memory-control if mapping has enabled write-combining
*/
L4_Msg_t msg;
L4_Accept(L4_UntypedWordsAcceptor);
L4_Clear(&msg);
/* this should work even if _map_item is a grant item */
L4_Append(&msg, _map_item);
L4_Load(&msg);
L4_MsgTag_t result = L4_ReplyWait(_last, &_last);
if (L4_IpcFailed(result)) {
PERR("Page fault IPC error. (continuable)");
wait_for_fault();
return;
}
if (L4_UntypedWords(result) != 2) {
PERR("Malformed page-fault ipc. (sender = 0x%08lx)", _last.raw);
wait_for_fault();
return;
}
L4_Clear(&msg);
// TODO Error checking. Did we really receive 2 words?
L4_Store(result, &msg);
_pf_addr = L4_Get(&msg, 0);
_pf_ip = L4_Get(&msg, 1);
_flags = L4_Label(result);
}
void Ipc_pager::acknowledge_wakeup()
{
PERR("acknowledge_wakeup called, not yet implemented");
// /* answer wakeup call from one of core's region-manager sessions */
// l4_msgdope_t result;
// l4_ipc_send(_last, L4_IPC_SHORT_MSG, 0, 0, L4_IPC_SEND_TIMEOUT_0, &result);
}
@ -98,28 +140,7 @@ void Pager_activation_base::entry()
** Pager entrypoint **
**********************/
Pager_entrypoint::Pager_entrypoint(Cap_session *, Pager_activation_base *a)
: _activation(a)
{ _activation->ep(this); }
void Pager_entrypoint::dissolve(Pager_object *obj)
Untyped_capability Pager_entrypoint::_manage(Pager_object *obj)
{
remove_locked(obj);
}
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
/* return invalid capability if no activation is present */
if (!_activation) return Pager_capability();
Native_capability cap = Native_capability(_activation->cap().dst(), 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);
return Untyped_capability(_tid.l4id, obj->badge());
}

View File

@ -13,14 +13,14 @@ SRC_CC = cap_session_component.cc \
dump_alloc.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
ipc_pager.cc \
irq_session_component.cc \
kip.cc \
main.cc \
multiboot_info.cc \
pd_session_component.cc \
pager.cc \
pager_common.cc \
pager_ep.cc \
pager_object.cc \
platform.cc \
platform_pd.cc \
platform_services.cc \
@ -57,7 +57,8 @@ vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)
vpath pager_common.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
vpath pager_object.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/base/console
vpath kip.cc $(REP_DIR)/src/base/kip
vpath %.cc $(REP_DIR)/src/core

View File

@ -30,7 +30,8 @@ SRC_CC += \
dump_alloc.cc \
context_area.cc \
capability_space.cc \
pager.cc
pager.cc \
pager_ep.cc
LIBS += core_printf base-common syscall
@ -56,5 +57,6 @@ vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core

View File

@ -129,9 +129,9 @@ namespace Genode {
void acknowledge_wakeup();
/**
* Return thread ID of last faulter
* Returns true if the last request was send from a core thread
*/
Native_thread_id last() const { return _last; }
bool request_from_core() { return false; }
/**
* Return badge for faulting thread

View File

@ -97,51 +97,7 @@ void Ipc_pager::acknowledge_wakeup()
}
Ipc_pager::Ipc_pager()
:
Native_capability(Capability_space::create_ep_cap(*Thread_base::myself())),
_last(0)
{ }
/**********************
** Pager activation **
**********************/
void Pager_activation_base::entry()
{
Ipc_pager pager;
_cap = pager;
_cap_valid.unlock();
bool reply_pending = false;
while (1) {
if (reply_pending)
pager.reply_and_wait_for_fault();
else
pager.wait_for_fault();
reply_pending = false;
/* lookup referenced object */
Object_pool<Pager_object>::Guard _obj(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
Pager_object *obj = _obj;
/* handle request */
if (obj) {
if (pager.is_exception()) {
obj->submit_exception_signal();
continue;
}
/* send reply if page-fault handling succeeded */
if (!obj->pager(pager))
reply_pending = true;
}
}
}
Ipc_pager::Ipc_pager() : _last(0) { }
/******************
@ -164,39 +120,16 @@ void Pager_object::unresolved_page_fault_occurred()
** Pager entrypoint **
**********************/
Pager_entrypoint::Pager_entrypoint(Cap_session *, Pager_activation_base *a)
: _activation(a)
{ _activation->ep(this); }
void Pager_entrypoint::dissolve(Pager_object *obj)
Untyped_capability Pager_entrypoint::_manage(Pager_object *obj)
{
remove_locked(obj);
}
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
/* return invalid capability if no activation is present */
if (!_activation) return Pager_capability();
/*
* 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.
*/
Native_capability ep_cap = _activation->cap();
Rpc_obj_key rpc_obj_key((addr_t)obj->badge());
Untyped_capability new_obj_cap =
Capability_space::create_rpc_obj_cap(ep_cap, 0, rpc_obj_key);
/* add server object to object pool */
obj->cap(new_obj_cap);
insert(obj);
return reinterpret_cap_cast<Pager_object>(new_obj_cap);
Untyped_capability ep_cap(Capability_space::create_ep_cap(*this));
return Capability_space::create_rpc_obj_cap(ep_cap, nullptr, rpc_obj_key);
}

View File

@ -2,11 +2,12 @@
* \brief Paging-server framework
* \author Norman Feske
* \author Christian Helmuth
* \author Stefan Kalkowski
* \date 2006-04-28
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -16,31 +17,31 @@
#define _CORE__INCLUDE__PAGER_H_
#include <base/thread.h>
#include <base/thread_state.h>
#include <ipc_pager.h>
#include <base/printf.h>
#include <base/object_pool.h>
#include <base/signal.h>
#include <cap_session/cap_session.h>
#include <pager/capability.h>
#include <ipc_pager.h>
namespace Genode {
/**
* Special server object for paging
*
* A 'Pager_object' is very similar to a 'Rpc_object'. It is just a
* special implementation for page-fault handling, which does not allow to
* define a "badge" for pager capabilities.
*/
class Pager_object;
/**
* Paging entry point
*/
class Pager_entrypoint;
class Pager_activation_base;
template <int> class Pager_activation;
enum { PAGER_EP_STACK_SIZE = sizeof(addr_t) * 2048 };
}
/**
* Special server object for paging
*
* A 'Pager_object' is very similar to a 'Rpc_object'. It is just a
* special implementation for page-fault handling, which does not allow to
* define a "badge" for pager capabilities.
*/
class Genode::Pager_object : public Object_pool<Pager_object>::Entry
{
protected:
@ -125,69 +126,15 @@ class Genode::Pager_object : public Object_pool<Pager_object>::Entry
};
/**
* A 'Pager_activation' processes one page fault of a 'Pager_object' at a time.
*/
class Genode::Pager_activation_base: public Thread_base
class Genode::Pager_entrypoint : public Object_pool<Pager_object>,
public Thread<PAGER_EP_STACK_SIZE>
{
private:
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
Ipc_pager _pager;
Cap_session *_cap_session;
Native_capability _cap;
Pager_entrypoint *_ep; /* entry point to which the
activation belongs */
/**
* Lock used for blocking until '_cap' is initialized
*/
Lock _cap_valid;
public:
Pager_activation_base(const char *name, size_t stack_size)
: Thread_base(WEIGHT, name, stack_size), _cap(Native_capability()),
_ep(0), _cap_valid(Lock::LOCKED) { }
/**
* Set entry point, which the activation serves
*
* This method is only called by the 'Pager_entrypoint'
* constructor.
*/
void ep(Pager_entrypoint *ep) { _ep = ep; }
/**
* Thread interface
*/
void entry();
/**
* Return capability to this activation
*
* This method should only be called from 'Pager_entrypoint'
*/
Native_capability cap()
{
/* ensure that the initialization of our 'Ipc_pager' is done */
if (!_cap.valid())
_cap_valid.lock();
return _cap;
}
};
/**
* Paging entry point
*
* For a paging entry point can hold only one activation. So, paging is
* strictly serialized for one entry point.
*/
class Genode::Pager_entrypoint : public Object_pool<Pager_object>
{
private:
Pager_activation_base *_activation;
Cap_session *_cap_session;
Untyped_capability _manage(Pager_object *obj);
public:
@ -197,9 +144,10 @@ class Genode::Pager_entrypoint : public Object_pool<Pager_object>
* \param cap_session Cap_session for creating capabilities
* for the pager objects managed by this
* entry point
* \param a initial activation
*/
Pager_entrypoint(Cap_session *cap_session, Pager_activation_base *a = 0);
Pager_entrypoint(Cap_session *cap_session)
: Thread<PAGER_EP_STACK_SIZE>("pager_ep"),
_cap_session(cap_session) { start(); }
/**
* Associate Pager_object with the entry point
@ -210,16 +158,13 @@ class Genode::Pager_entrypoint : public Object_pool<Pager_object>
* Dissolve Pager_object from entry point
*/
void dissolve(Pager_object *obj);
};
template <int STACK_SIZE>
class Genode::Pager_activation : public Pager_activation_base
{
public:
/**********************
** Thread interface **
**********************/
Pager_activation() : Pager_activation_base("pager", STACK_SIZE)
{ start(); }
void entry();
};
#endif /* _CORE__INCLUDE__PAGER_H_ */

View File

@ -29,12 +29,7 @@ namespace Genode {
Rpc_entrypoint *_ds_ep;
Rpc_entrypoint *_thread_ep;
Allocator *_md_alloc;
enum { PAGER_STACK_SIZE = 2*4096 };
Pager_activation<PAGER_STACK_SIZE> _pager_thread;
Pager_entrypoint _pager_ep;
addr_t _vm_start;
size_t _vm_size;
@ -105,8 +100,8 @@ namespace Genode {
:
Root_component<Rm_session_component>(session_ep, md_alloc),
_ds_ep(ds_ep), _thread_ep(thread_ep), _md_alloc(md_alloc),
_pager_thread(), _pager_ep(cap_session, &_pager_thread),
_vm_start(vm_start), _vm_size(vm_size) { }
_pager_ep(cap_session), _vm_start(vm_start), _vm_size(vm_size)
{ }
/**
* Return pager entrypoint

View File

@ -0,0 +1,103 @@
/*
* \brief Generic implmentation of pager entrypoint
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2009-03-31
*/
/*
* Copyright (C) 2009-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Core includes */
#include <pager.h>
using namespace Genode;
void Pager_entrypoint::entry()
{
bool reply_pending = false;
while (1) {
if (reply_pending)
_pager.reply_and_wait_for_fault();
else
_pager.wait_for_fault();
reply_pending = false;
/* lookup referenced object */
Object_pool<Pager_object>::Guard _obj(lookup_and_lock(_pager.badge()));
Pager_object *obj = _obj;
/* handle request */
if (obj) {
if (_pager.is_exception()) {
obj->submit_exception_signal();
continue;
}
/* send reply if page-fault handling succeeded */
reply_pending = !obj->pager(_pager);
continue;
} else {
/*
* Prevent threads outside of core to mess with our wake-up
* interface. This condition can trigger if a process gets
* destroyed which triggered a page fault shortly before getting
* killed. In this case, 'wait_for_fault()' returns (because of
* the page fault delivery) but the pager-object lookup will fail
* (because core removed the process already).
*/
if (_pager.request_from_core()) {
/*
* We got a request from one of cores region-manager sessions
* to answer the pending page fault of a resolved region-manager
* client. Hence, we have to send the page-fault reply to the
* specified thread and answer the call of the region-manager
* session.
*
* When called from a region-manager session, we receive the
* core-local address of the targeted pager object via the
* first message word, which corresponds to the 'fault_ip'
* argument of normal page-fault messages.
*/
obj = reinterpret_cast<Pager_object *>(_pager.fault_ip());
/* send reply to the calling region-manager session */
_pager.acknowledge_wakeup();
/* answer page fault of resolved pager object */
_pager.set_reply_dst(obj->cap());
_pager.acknowledge_wakeup();
}
}
};
}
void Pager_entrypoint::dissolve(Pager_object *obj)
{
remove_locked(obj);
}
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
Native_capability cap = _manage(obj);
/* 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);
}