hw: distinct pagefault and IPC message type

ref #874
This commit is contained in:
Martin Stein 2013-10-18 17:01:51 +02:00 committed by Norman Feske
parent 6f935af278
commit 002a5b8978
7 changed files with 137 additions and 165 deletions

View File

@ -79,30 +79,28 @@ namespace Genode
{
private:
Pagefault _pagefault; /* data of lastly received pagefault */
Mapping _mapping; /* mapping to resolve last pagefault */
Pagefault_msg _pagefault_msg;
Mapping _mapping;
/**
* Backend for wait_for_fault and wait_for_first_fault
*/
void _wait_for_fault(size_t s);
void _wait_for_fault();
/**
* Get global name of pager thread
*/
static unsigned _thread_id()
{
return Genode::thread_get_my_native_id();
}
public:
/**
* Constructor
*/
Ipc_pager() :
Native_capability(Genode::thread_get_my_native_id(), 0)
{
/* check if we can distinguish all message types */
if (sizeof(Pagefault) == sizeof(Pagefault_resolved))
{
kernel_log() << __PRETTY_FUNCTION__
<< ": Message types indiscernible\n";
while (1) ;
}
}
Ipc_pager() : Native_capability(_thread_id(), 0) { }
/**
* Wait for the first pagefault request
@ -125,12 +123,12 @@ namespace Genode
/**
* Request instruction pointer of current page fault
*/
addr_t fault_ip() { return _pagefault.virt_ip; }
addr_t fault_ip() { return _pagefault_msg.virt_ip; }
/**
* Request fault address of current page fault
*/
addr_t fault_addr() { return _pagefault.virt_address; }
addr_t fault_addr() { return _pagefault_msg.virt_address; }
/**
* Set parameters for next reply
@ -159,17 +157,17 @@ namespace Genode
/**
* Return thread ID of last faulter
*/
Native_thread_id last() const { return _pagefault.thread_id; }
Native_thread_id last() const { return _pagefault_msg.thread_id; }
/**
* Return badge for faulting thread
*/
unsigned badge() const { return _pagefault.thread_id; }
unsigned badge() const { return _pagefault_msg.thread_id; }
/**
* Return true if last fault was a write fault
*/
bool is_write_fault() const { return _pagefault.write; }
bool is_write_fault() const { return _pagefault_msg.write; }
/**
* Return true if last fault was an exception

View File

@ -48,61 +48,52 @@ namespace Genode
*/
inline Native_thread_id thread_invalid_id() { return 0; }
/**
* Describes a pagefault
*/
struct Pagefault
{
unsigned thread_id; /* thread ID of the faulter */
Tlb * tlb; /* TLB to wich the faulter is assigned */
addr_t virt_ip; /* the faulters virtual instruction pointer */
addr_t virt_address; /* virtual fault address */
bool write; /* write access attempted at fault? */
/**
* Placement new operator
*/
void * operator new (size_t, void * p) { return p; }
/**
* Construct invalid pagefault
*/
Pagefault() : thread_id(0) { }
/**
* Construct valid pagefault
*/
Pagefault(unsigned const tid, Tlb * const tlb,
addr_t const vip, addr_t const va, bool const w)
:
thread_id(tid), tlb(tlb), virt_ip(vip),
virt_address(va), write(w)
{ }
/**
* Validation
*/
bool valid() const { return thread_id != 0; }
};
/**
* Types of synchronously communicated messages
*/
struct Msg_type
{
enum Id {
INVALID = 0,
IPC = 1,
};
};
/**
* Message that is communicated synchronously
*/
struct Msg
{
Msg_type::Id type;
uint8_t data[];
/**
* Types of synchronously communicated messages
*/
struct Type
{
enum Id {
INVALID = 0,
IPC = 1,
PAGEFAULT = 2,
};
};
Type::Id type;
uint8_t data[];
};
/**
* Message that reports a pagefault
*/
struct Pagefault_msg : Msg
{
unsigned thread_id;
Tlb * tlb;
addr_t virt_ip;
addr_t virt_address;
bool write;
static void init(void * const p, unsigned const tid, Tlb * const tlb,
addr_t const vip, addr_t const va, bool const w)
{
Pagefault_msg * msg = (Pagefault_msg *)p;
msg->Msg::type = Msg::Type::PAGEFAULT;
msg->thread_id = tid;
msg->tlb = tlb;
msg->virt_ip = vip;
msg->virt_address = va;
msg->write = w;
}
void * base() { return this; }
size_t size() { return sizeof(Pagefault_msg); }
};
/**
@ -120,30 +111,43 @@ namespace Genode
struct Native_utcb
{
union {
uint8_t data[1 << MIN_MAPPING_SIZE_LOG2];
Msg msg;
Ipc_msg ipc_msg;
uint8_t data[1 << MIN_MAPPING_SIZE_LOG2];
Msg msg;
Ipc_msg ipc_msg;
Pagefault_msg pagefault_msg;
};
/**
* Get the base of the UTCB region
*/
void * base() { return data; }
void syscall_wait_for_request(void * & buf_base, size_t & buf_size)
{
msg.type = Msg::Type::INVALID;
buf_base = base();
buf_size = size();
}
void syscall_request_and_wait(void * & msg_base, size_t & msg_size,
void * & buf_base, size_t & buf_size)
{
msg.type = Msg::Type::IPC;
msg_base = ipc_msg_base();
msg_size = ipc_msg_size();
buf_base = base();
buf_size = size();
}
void syscall_reply(void * & msg_base, size_t & msg_size)
{
msg.type = Msg::Type::IPC;
msg_base = ipc_msg_base();
msg_size = ipc_msg_size();
}
/**
* Get the size of the UTCB region
*/
size_t size() { return sizeof(data) / sizeof(data[0]); }
/**
* Get the top of the UTCB region
*/
addr_t top() { return (addr_t)data + size(); }
/**
* Maximum size of an IPC message that can be held by the UTCB
*/
size_t ipc_msg_max_size() { return top() - (addr_t)ipc_msg.data; }
void * base() { return &data; }
addr_t top() { return (addr_t)base() + size(); }
void * ipc_msg_base() { return &ipc_msg; }
size_t ipc_msg_size() { return ipc_msg_header_size() + ipc_msg.size; }
size_t ipc_msg_max_size() { return top() - (addr_t)&ipc_msg; }
size_t ipc_msg_header_size() { return (addr_t)ipc_msg.data - (addr_t)&ipc_msg; }
};
struct Cap_dst_policy

View File

@ -123,7 +123,7 @@ void Ipc_client::_call()
/* receive reply */
Native_utcb * const utcb = Thread_base::myself()->utcb();
if (utcb->msg.type != Msg_type::IPC) {
if (utcb->msg.type != Msg::Type::IPC) {
PERR("failed to receive reply");
throw Blocking_canceled();
}
@ -169,7 +169,7 @@ void Ipc_server::_wait()
/* receive next request */
Kernel::wait_for_request();
Native_utcb * const utcb = Thread_base::myself()->utcb();
if (utcb->msg.type != Msg_type::IPC) {
if (utcb->msg.type != Msg::Type::IPC) {
PERR("failed to receive request");
throw Blocking_canceled();
}
@ -202,7 +202,7 @@ void Ipc_server::_reply_wait()
/* fetch request */
Native_utcb * const utcb = Thread_base::myself()->utcb();
if (utcb->msg.type != Msg_type::IPC) {
if (utcb->msg.type != Msg::Type::IPC) {
PERR("failed to receive request");
throw Blocking_canceled();
}

View File

@ -95,13 +95,8 @@ Pager_capability Pager_entrypoint::manage(Pager_object * const o)
void Ipc_pager::wait_for_first_fault()
{
Native_utcb * const utcb = Thread_base::myself()->utcb();
while (1) {
Kernel::wait_for_request();
if (utcb->msg.type == Msg_type::IPC) { break; }
PERR("failed to receive fault");
}
_wait_for_fault(utcb->ipc_msg.size);
Kernel::wait_for_request();
_wait_for_fault();
}
@ -110,62 +105,41 @@ void Ipc_pager::wait_for_fault()
Native_utcb * const utcb = Thread_base::myself()->utcb();
utcb->ipc_msg.size = 0;
Kernel::reply(1);
while (utcb->msg.type != Msg_type::IPC) {
PERR("failed to receive fault");
Kernel::wait_for_request();
}
_wait_for_fault(utcb->ipc_msg.size);
_wait_for_fault();
}
void Ipc_pager::_wait_for_fault(size_t s)
void Ipc_pager::_wait_for_fault()
{
Native_utcb * const utcb = Thread_base::myself()->utcb();
while (1)
{
/*
* FIXME: the message size is a weak indicator for the message type
*/
switch (s)
{
case sizeof(Pagefault): {
switch (utcb->msg.type) {
/* message is a pagefault */
Native_utcb * const utcb = Thread_base::myself()->utcb();
Pagefault * const pf = (Pagefault *)utcb->ipc_msg.data;
if (pf->valid())
{
/* give our caller the chance to handle the fault */
_pagefault = *pf;
return;
}
/* pagefault is invalid so get the next message */
else {
PERR("invalid pagefault");
continue;
}
continue; }
case Msg::Type::PAGEFAULT: {
case sizeof(Pagefault_resolved): {
/* receive pagefault report */
_pagefault_msg = utcb->pagefault_msg;
return; }
/* message is a release request from a RM session */
case Msg::Type::IPC: {
/* receive release request from region manager */
Native_utcb * const utcb = Thread_base::myself()->utcb();
void * const msg_base = utcb->ipc_msg.data;
Pagefault_resolved * const msg = (Pagefault_resolved *)msg_base;
/* resume faulter, send ack to RM and get the next message */
/* resume faulter */
Kernel::resume_thread(msg->pager_object->badge());
utcb->ipc_msg.size = 0;
/* send ack to region manager and get next message */
Kernel::reply(1);
while (utcb->msg.type != Msg_type::IPC) {
PERR("failed to receive fault");
Kernel::wait_for_request();
}
s = utcb->ipc_msg.size;
continue; }
default: {
PERR("invalid message format");
PERR("unknown message type");
continue; }
}
}

View File

@ -24,7 +24,6 @@
using namespace Kernel;
typedef Genode::Thread_state Thread_state;
typedef Genode::Msg_type Msg_type;
bool Thread::_core() const
@ -91,8 +90,6 @@ void Thread::_received_ipc_request(size_t const s)
{
switch (_state) {
case SCHEDULED:
_phys_utcb->msg.type = Msg_type::IPC;
_phys_utcb->ipc_msg.size = s;
return;
default:
PERR("wrong thread state to receive IPC");
@ -122,8 +119,6 @@ void Thread::_await_ipc_succeeded(size_t const s)
{
switch (_state) {
case AWAITS_IPC:
_phys_utcb->msg.type = Msg_type::IPC;
_phys_utcb->ipc_msg.size = s;
_schedule();
return;
case AWAITS_PAGER_IPC:
@ -144,7 +139,6 @@ void Thread::_await_ipc_failed()
{
switch (_state) {
case AWAITS_IPC:
_phys_utcb->msg.type = Msg_type::INVALID;
_schedule();
return;
case SCHEDULED:
@ -340,10 +334,10 @@ void Thread::_mmu_exception()
PERR("unknown MMU exception");
return;
}
/* inform pager */
_pagefault = Pagefault(id(), (Tlb *)tlb(), ip, va, w);
void * const base = &_pagefault;
size_t const size = sizeof(_pagefault);
/* send pagefault message to pager */
Pagefault_msg::init(&_pagefault_msg, id(), (Tlb *)tlb(), ip, va, w);
void * const base = _pagefault_msg.base();
size_t const size = _pagefault_msg.size();
Ipc_node::send_request_await_reply(_pager, base, size, base, size);
}
@ -605,8 +599,9 @@ void Thread::_syscall_get_thread()
*/
void Thread::_syscall_wait_for_request()
{
void * const buf_base = _phys_utcb->ipc_msg.data;
size_t const buf_size = _phys_utcb->ipc_msg_max_size();
void * buf_base;
size_t buf_size;
_phys_utcb->syscall_wait_for_request(buf_base, buf_size);
Ipc_node::await_request(buf_base, buf_size);
}
@ -622,9 +617,14 @@ void Thread::_syscall_request_and_wait()
_await_ipc();
return;
}
Ipc_node::send_request_await_reply(
dst, _phys_utcb->ipc_msg.data, _phys_utcb->ipc_msg.size,
_phys_utcb->ipc_msg.data, _phys_utcb->ipc_msg_max_size());
void * msg_base;
size_t msg_size;
void * buf_base;
size_t buf_size;
_phys_utcb->syscall_request_and_wait(msg_base, msg_size,
buf_base, buf_size);
Ipc_node::send_request_await_reply(dst, msg_base, msg_size,
buf_base, buf_size);
}
@ -633,16 +633,12 @@ void Thread::_syscall_request_and_wait()
*/
void Thread::_syscall_reply()
{
bool const await_request = user_arg_1();
void * const msg_base = _phys_utcb->ipc_msg.data;
size_t const msg_size = _phys_utcb->ipc_msg.size;
void * msg_base;
size_t msg_size;
_phys_utcb->syscall_reply(msg_base, msg_size);
Ipc_node::send_reply(msg_base, msg_size);
if (await_request) {
void * const buf_base = _phys_utcb->ipc_msg.data;
size_t const buf_size = _phys_utcb->ipc_msg_max_size();
Ipc_node::await_request(buf_base, buf_size);
} else { _phys_utcb->msg.type = Msg_type::INVALID; }
bool const await_request = user_arg_1();
if (await_request) { _syscall_wait_for_request(); }
}

View File

@ -32,9 +32,9 @@ namespace Kernel
class Thread;
class Pd;
typedef Genode::Cpu Cpu;
typedef Genode::Pagefault Pagefault;
typedef Genode::Native_utcb Native_utcb;
typedef Genode::Cpu Cpu;
typedef Genode::Pagefault_msg Pagefault_msg;
typedef Genode::Native_utcb Native_utcb;
void reset_lap_time();
@ -82,7 +82,7 @@ class Kernel::Thread
Platform_thread * const _platform_thread;
State _state;
Pagefault _pagefault;
Pagefault_msg _pagefault_msg;
Thread * _pager;
unsigned _pd_id;
Native_utcb * _phys_utcb;

View File

@ -60,7 +60,7 @@ int Ipc_pager::resolve_and_wait_for_fault()
return -1;
}
/* prepare mapping */
Tlb * const tlb = _pagefault.tlb;
Tlb * const tlb = _pagefault_msg.tlb;
Page_flags::access_t const flags =
Page_flags::resolve_and_wait_for_fault(_mapping.writable,
_mapping.write_combined,
@ -91,7 +91,7 @@ int Ipc_pager::resolve_and_wait_for_fault()
}
}
/* wake up faulter */
Kernel::resume_faulter(_pagefault.thread_id);
Kernel::resume_faulter(_pagefault_msg.thread_id);
/* wait for next page fault */
wait_for_fault();