2011-12-22 16:19:25 +01:00
|
|
|
/*
|
2015-07-29 10:58:17 +02:00
|
|
|
* \brief Pager support for Codezero
|
2011-12-22 16:19:25 +01:00
|
|
|
* \author Norman Feske
|
2015-07-29 10:58:17 +02:00
|
|
|
* \date 2010-02-16
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2015-07-29 10:58:17 +02:00
|
|
|
* Copyright (C) 2010-2013 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
/* Genode includes */
|
|
|
|
#include <base/printf.h>
|
2015-06-19 14:58:18 +02:00
|
|
|
#include <pager.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
/* Codezero includes */
|
|
|
|
#include <ipc_pager.h>
|
|
|
|
#include <codezero/syscalls.h>
|
|
|
|
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
using namespace Genode;
|
2015-07-29 10:58:17 +02:00
|
|
|
using namespace Codezero;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
enum { verbose_page_faults = false };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
/************************
|
|
|
|
** Page-fault utility **
|
|
|
|
************************/
|
|
|
|
|
|
|
|
class Fault
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2015-07-29 10:58:17 +02:00
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
enum Type { READ, WRITE, EXEC, UNKNOWN };
|
2012-12-14 10:03:55 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
private:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
/**
|
|
|
|
* 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;
|
2012-12-14 10:03:55 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
if ((pte & PTE_PROT_MASK) == (__MAP_USR_RO & PTE_PROT_MASK))
|
|
|
|
return WRITE;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
return READ;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2012-12-14 10:03:55 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
Type _type;
|
|
|
|
umword_t _addr;
|
|
|
|
umword_t _ip;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
2012-12-14 10:03:55 +01:00
|
|
|
*
|
2015-07-29 10:58:17 +02:00
|
|
|
* \param kdata Codezero-specific page-fault information
|
2012-12-14 10:03:55 +01:00
|
|
|
*/
|
2015-07-29 10:58:17 +02:00
|
|
|
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)
|
|
|
|
{ }
|
2012-12-14 10:03:55 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
Type type() const { return _type; }
|
|
|
|
umword_t addr() const { return _addr; }
|
|
|
|
umword_t ip() const { return _ip; }
|
|
|
|
};
|
2012-12-14 10:03:55 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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());
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
/***************
|
|
|
|
** IPC pager **
|
|
|
|
***************/
|
|
|
|
|
|
|
|
void Ipc_pager::wait_for_fault()
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
int ret = l4_receive(L4_ANYTHREAD);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
PERR("pager: l4_received returned ret=%d", ret);
|
|
|
|
continue;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
umword_t tag = l4_get_tag();
|
|
|
|
int faulter_tid = l4_get_sender();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
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;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
void Ipc_pager::reply_and_wait_for_fault()
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2015-07-29 10:58:17 +02:00
|
|
|
/* 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();
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
void Ipc_pager::acknowledge_wakeup()
|
|
|
|
{
|
|
|
|
enum { SUCCESS = 0 };
|
|
|
|
l4_set_sender(_last);
|
|
|
|
l4_ipc_return(SUCCESS);
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2015-07-29 10:58:17 +02:00
|
|
|
/**********************
|
|
|
|
** Pager entrypoint **
|
|
|
|
**********************/
|
|
|
|
|
|
|
|
Untyped_capability Pager_entrypoint::_manage(Pager_object *obj)
|
|
|
|
{
|
|
|
|
return Untyped_capability(_tid.l4id, obj->badge());
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|