mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 07:46:42 +00:00
parent
6d03292a1e
commit
349262a655
@ -73,15 +73,20 @@ namespace Genode
|
||||
};
|
||||
|
||||
/**
|
||||
* Special paging server class
|
||||
* Paging-server backend
|
||||
*/
|
||||
class Ipc_pager : public Native_capability
|
||||
{
|
||||
enum { VERBOSE = 1 };
|
||||
private:
|
||||
|
||||
Pagefault _pagefault; /* data of lastly received pagefault */
|
||||
Mapping _mapping; /* mapping to resolve last pagefault */
|
||||
|
||||
/**
|
||||
* Backend for wait_for_fault and wait_for_first_fault
|
||||
*/
|
||||
void _wait_for_fault(size_t s);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -99,6 +104,11 @@ namespace Genode
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the first pagefault request
|
||||
*/
|
||||
void wait_for_first_fault();
|
||||
|
||||
/**
|
||||
* Wait for the next pagefault request
|
||||
*/
|
||||
|
@ -31,19 +31,15 @@ void Pager_activation_base::entry()
|
||||
|
||||
/* receive and handle faults */
|
||||
bool mapping_pending = 0;
|
||||
pager.wait_for_first_fault();
|
||||
while (1)
|
||||
{
|
||||
if (mapping_pending) {
|
||||
/* apply mapping and await next fault */
|
||||
if (pager.resolve_and_wait_for_fault()) {
|
||||
PERR("failed to resolve page fault");
|
||||
pager.wait_for_fault();
|
||||
}
|
||||
} else {
|
||||
pager.wait_for_fault();
|
||||
}
|
||||
/* protect bottom half of loop against pager-object guard */
|
||||
{
|
||||
/* lookup pager object for current faulter */
|
||||
Object_pool<Pager_object>::Guard o(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
|
||||
Object_pool<Pager_object>::Guard
|
||||
o(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
|
||||
|
||||
if (!o) {
|
||||
PERR("invalid pager object");
|
||||
mapping_pending = 0;
|
||||
@ -52,6 +48,14 @@ void Pager_activation_base::entry()
|
||||
mapping_pending = !o->pager(pager);
|
||||
}
|
||||
}
|
||||
if (mapping_pending) {
|
||||
/* apply mapping and await next fault */
|
||||
if (pager.resolve_and_wait_for_fault()) {
|
||||
PERR("failed to resolve page fault");
|
||||
pager.wait_for_fault();
|
||||
}
|
||||
} else { pager.wait_for_fault(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -59,8 +63,8 @@ void Pager_activation_base::entry()
|
||||
** Pager_entrypoint **
|
||||
**********************/
|
||||
|
||||
Pager_entrypoint::Pager_entrypoint(Cap_session *,
|
||||
Pager_activation_base * const a)
|
||||
Pager_entrypoint::
|
||||
Pager_entrypoint(Cap_session *, Pager_activation_base * const a)
|
||||
: _activation(a) { _activation->ep(this); }
|
||||
|
||||
|
||||
@ -89,18 +93,31 @@ Pager_capability Pager_entrypoint::manage(Pager_object * const o)
|
||||
** Ipc_pager **
|
||||
***************/
|
||||
|
||||
void Ipc_pager::wait_for_first_fault()
|
||||
{
|
||||
/* receive message */
|
||||
size_t const s = Kernel::wait_for_request();
|
||||
_wait_for_fault(s);
|
||||
}
|
||||
|
||||
|
||||
void Ipc_pager::wait_for_fault()
|
||||
{
|
||||
/* receive first message */
|
||||
size_t s = Kernel::wait_for_request();
|
||||
while (1) {
|
||||
size_t const s = Kernel::reply(0, 1);
|
||||
_wait_for_fault(s);
|
||||
}
|
||||
|
||||
|
||||
void Ipc_pager::_wait_for_fault(size_t s)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
/*
|
||||
* FIXME: the message size is a weak indicator for the message type
|
||||
*/
|
||||
switch (s) {
|
||||
|
||||
switch (s)
|
||||
{
|
||||
case sizeof(Pagefault): {
|
||||
|
||||
/* message is a pagefault */
|
||||
@ -114,7 +131,7 @@ void Ipc_pager::wait_for_fault()
|
||||
}
|
||||
/* pagefault is invalid so get the next message */
|
||||
else {
|
||||
PERR("%s:%d: Invalid pagefault", __FILE__, __LINE__);
|
||||
PERR("invalid pagefault");
|
||||
continue;
|
||||
}
|
||||
continue; }
|
||||
@ -132,9 +149,8 @@ void Ipc_pager::wait_for_fault()
|
||||
|
||||
default: {
|
||||
|
||||
PERR("%s:%d: Invalid message format", __FILE__, __LINE__);
|
||||
PERR("invalid message format");
|
||||
continue; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -619,12 +619,12 @@ namespace Arm
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a pagefault has occured due to a translation miss
|
||||
* Return if the context is in a pagefault due to a translation miss
|
||||
*
|
||||
* \param va holds the virtual fault-address if this returns 1
|
||||
* \param w wether it is a write fault if this returns 1
|
||||
* \param va holds the virtual fault-address if call returns 1
|
||||
* \param w holds wether it's a write fault if call returns 1
|
||||
*/
|
||||
bool translation_miss(addr_t & va, bool & w) const
|
||||
bool pagefault(addr_t & va, bool & w) const
|
||||
{
|
||||
/* determine fault type */
|
||||
switch (cpu_exception) {
|
||||
|
@ -226,24 +226,6 @@ namespace Kernel
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle an usermode pagefault
|
||||
*
|
||||
* \param user thread that has caused the pagefault
|
||||
*/
|
||||
void handle_pagefault(Thread * const user)
|
||||
{
|
||||
/* check out cause and attributes of abort */
|
||||
addr_t virt_addr = 0;
|
||||
bool write = 0;
|
||||
bool is_transl_miss = user->translation_miss(virt_addr, write);
|
||||
assert(is_transl_miss);
|
||||
|
||||
/* the user might be able to resolve the pagefault */
|
||||
user->pagefault(virt_addr, write);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle request of an unknown signal type
|
||||
*/
|
||||
|
@ -37,7 +37,6 @@ namespace Kernel
|
||||
typedef Genode::Native_utcb Native_utcb;
|
||||
|
||||
unsigned core_id();
|
||||
void handle_pagefault(Thread * const);
|
||||
void handle_syscall(Thread * const);
|
||||
void handle_interrupt(void);
|
||||
void handle_invalid_excpt(void);
|
||||
@ -90,14 +89,16 @@ class Kernel::Thread
|
||||
|
||||
enum State
|
||||
{
|
||||
SCHEDULED,
|
||||
AWAIT_START,
|
||||
AWAIT_IPC,
|
||||
AWAIT_RESUMPTION,
|
||||
AWAIT_IRQ,
|
||||
AWAIT_SIGNAL,
|
||||
AWAIT_SIGNAL_CONTEXT_KILL,
|
||||
CRASHED,
|
||||
SCHEDULED = 1,
|
||||
AWAIT_START = 2,
|
||||
AWAIT_IPC = 3,
|
||||
AWAIT_RESUME = 4,
|
||||
AWAIT_PAGER = 5,
|
||||
AWAIT_PAGER_IPC = 6,
|
||||
AWAIT_IRQ = 7,
|
||||
AWAIT_SIGNAL = 8,
|
||||
AWAIT_SIGNAL_CONTEXT_KILL = 9,
|
||||
CRASHED = 10,
|
||||
};
|
||||
|
||||
Platform_thread * const _platform_thread;
|
||||
@ -173,14 +174,39 @@ class Kernel::Thread
|
||||
|
||||
void _has_received(size_t const s)
|
||||
{
|
||||
switch (_state) {
|
||||
case AWAIT_IPC:
|
||||
_schedule();
|
||||
case SCHEDULED:
|
||||
user_arg_0(s);
|
||||
if (_state != SCHEDULED) { _schedule(); }
|
||||
return;
|
||||
case AWAIT_PAGER_IPC:
|
||||
_schedule();
|
||||
return;
|
||||
case AWAIT_PAGER:
|
||||
/* pager replied before pagefault has been resolved */
|
||||
_state = AWAIT_RESUME;
|
||||
return;
|
||||
default:
|
||||
PERR("wrong thread state to receive IPC");
|
||||
crash();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void _awaits_receipt()
|
||||
{
|
||||
switch (_state) {
|
||||
case SCHEDULED:
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_IPC;
|
||||
case AWAIT_PAGER:
|
||||
return;
|
||||
default:
|
||||
PERR("wrong thread state to await IPC");
|
||||
crash();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -293,9 +319,9 @@ class Kernel::Thread
|
||||
*/
|
||||
void pause()
|
||||
{
|
||||
assert(_state == AWAIT_RESUMPTION || _state == SCHEDULED);
|
||||
assert(_state == AWAIT_RESUME || _state == SCHEDULED);
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_RESUMPTION;
|
||||
_state = AWAIT_RESUME;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -313,9 +339,13 @@ class Kernel::Thread
|
||||
int resume()
|
||||
{
|
||||
switch (_state) {
|
||||
case AWAIT_RESUMPTION:
|
||||
case AWAIT_RESUME:
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_PAGER:
|
||||
/* pagefault has been resolved before pager replied */
|
||||
_state = AWAIT_PAGER_IPC;
|
||||
return 0;
|
||||
case SCHEDULED:
|
||||
return 1;
|
||||
case AWAIT_IPC:
|
||||
@ -339,7 +369,8 @@ class Kernel::Thread
|
||||
return 0;
|
||||
case AWAIT_START:
|
||||
default:
|
||||
PERR("unresumable state");
|
||||
PERR("wrong state to resume thread");
|
||||
crash();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -376,22 +407,26 @@ class Kernel::Thread
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a pagefault that originates from this thread
|
||||
*
|
||||
* \param va virtual fault address
|
||||
* \param w if fault was caused by a write access
|
||||
* Handle an exception thrown by the MMU
|
||||
*/
|
||||
void pagefault(addr_t const va, bool const w)
|
||||
void handle_mmu_exception()
|
||||
{
|
||||
assert(_state == SCHEDULED && _pager);
|
||||
|
||||
/* pause faulter */
|
||||
/* pause thread */
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_RESUMPTION;
|
||||
_state = AWAIT_PAGER;
|
||||
|
||||
/* inform pager through IPC */
|
||||
/* check out cause and attributes */
|
||||
addr_t va = 0;
|
||||
bool w = 0;
|
||||
if (!pagefault(va, w)) {
|
||||
PERR("unknown MMU exception");
|
||||
return;
|
||||
}
|
||||
/* inform pager */
|
||||
_pagefault = Pagefault(id(), (Tlb *)tlb(), ip, va, w);
|
||||
Ipc_node::send_note(_pager, &_pagefault, sizeof(_pagefault));
|
||||
void * const base = &_pagefault;
|
||||
size_t const size = sizeof(_pagefault);
|
||||
Ipc_node::send_request_await_reply(_pager, base, size, base, size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -411,10 +446,10 @@ class Kernel::Thread
|
||||
handle_syscall(this);
|
||||
return;
|
||||
case PREFETCH_ABORT:
|
||||
handle_pagefault(this);
|
||||
handle_mmu_exception();
|
||||
return;
|
||||
case DATA_ABORT:
|
||||
handle_pagefault(this);
|
||||
handle_mmu_exception();
|
||||
return;
|
||||
case INTERRUPT_REQUEST:
|
||||
handle_interrupt();
|
||||
|
Loading…
Reference in New Issue
Block a user