mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 15:02:25 +00:00
f4bd2368f6
If an RM client gets dissolved the RM server tries to first dissolve and then destruct the according pager object. As pager objects previously cancelled unresolved faults only in destructor the dissolve operation blocked forever when an unresolved fault existed. As every pager object should get dissolved before it gets destructed (signal-context complains otherwise) no more unresolved-fault cancelling is needed in the destructor. ref #989
352 lines
6.6 KiB
C++
352 lines
6.6 KiB
C++
/*
|
|
* \brief Paging framework
|
|
* \author Martin Stein
|
|
* \date 2013-11-07
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 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.
|
|
*/
|
|
|
|
#ifndef _BASE__PAGER_H_
|
|
#define _BASE__PAGER_H_
|
|
|
|
/* Genode includes */
|
|
#include <base/thread.h>
|
|
#include <base/object_pool.h>
|
|
#include <base/signal.h>
|
|
#include <pager/capability.h>
|
|
|
|
/* base-hw includes */
|
|
#include <placement_new.h>
|
|
|
|
namespace Genode
|
|
{
|
|
class Cap_session;
|
|
|
|
/**
|
|
* Translation of a virtual page frame
|
|
*/
|
|
struct Mapping;
|
|
|
|
/**
|
|
* Interface between the generic paging system and the base-hw backend
|
|
*/
|
|
class Ipc_pager;
|
|
|
|
/**
|
|
* Represents a faulter and its paging context
|
|
*/
|
|
class Pager_object;
|
|
|
|
/**
|
|
* Paging entry point that manages a pool of pager objects
|
|
*/
|
|
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;
|
|
}
|
|
|
|
struct Genode::Mapping
|
|
{
|
|
addr_t virt_address;
|
|
addr_t phys_address;
|
|
bool write_combined;
|
|
bool io_mem;
|
|
unsigned size_log2;
|
|
bool writable;
|
|
|
|
/**
|
|
* Constructor for invalid mappings
|
|
*/
|
|
Mapping();
|
|
|
|
/**
|
|
* Constructor for valid mappings
|
|
*/
|
|
Mapping(addr_t const va, addr_t const pa, bool const wc,
|
|
bool const io, unsigned const sl2, bool const w);
|
|
|
|
/**
|
|
* Prepare for the application of the mapping
|
|
*/
|
|
void prepare_map_operation();
|
|
};
|
|
|
|
class Genode::Ipc_pager
|
|
{
|
|
protected:
|
|
|
|
/**
|
|
* Page-fault data that is read from the faulters thread registers
|
|
*/
|
|
struct Fault_thread_regs
|
|
{
|
|
addr_t tlb;
|
|
addr_t ip;
|
|
addr_t addr;
|
|
addr_t writes;
|
|
addr_t signal;
|
|
};
|
|
|
|
Fault_thread_regs _fault;
|
|
Mapping _mapping;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Instruction pointer of current page fault
|
|
*/
|
|
addr_t fault_ip() const;
|
|
|
|
/**
|
|
* Faulter-local fault address of current page fault
|
|
*/
|
|
addr_t fault_addr() const;
|
|
|
|
/**
|
|
* Access direction of current page fault
|
|
*/
|
|
bool is_write_fault() const;
|
|
|
|
/**
|
|
* Input mapping data as reply to current page fault
|
|
*/
|
|
void set_reply_mapping(Mapping m);
|
|
};
|
|
|
|
class Genode::Pager_object : public Object_pool<Pager_object>::Entry,
|
|
public Signal_context
|
|
{
|
|
friend class Pager_entrypoint;
|
|
|
|
private:
|
|
|
|
Signal_context_capability _signal_context_cap;
|
|
Thread_capability _thread_cap;
|
|
bool _signal_valid;
|
|
char _signal_buf[sizeof(Signal)];
|
|
unsigned const _badge;
|
|
|
|
/**
|
|
* Remember an incoming fault for handling
|
|
*
|
|
* \param s fault signal
|
|
*/
|
|
void _take_fault(Signal const & s)
|
|
{
|
|
new (_signal_buf) Signal(s);
|
|
_signal_valid = 1;
|
|
}
|
|
|
|
/**
|
|
* End handling of current fault
|
|
*/
|
|
void _end_fault()
|
|
{
|
|
_signal()->~Signal();
|
|
_signal_valid = 0;
|
|
}
|
|
|
|
/**
|
|
* End handling of current fault if there is one
|
|
*/
|
|
void _end_fault_if_pending()
|
|
{
|
|
if (_signal_valid) { _end_fault(); }
|
|
}
|
|
|
|
|
|
/***************
|
|
** Accessors **
|
|
***************/
|
|
|
|
Signal * _signal() const;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* \param badge user identifaction of pager object
|
|
*/
|
|
Pager_object(unsigned const badge, Affinity::Location);
|
|
|
|
/**
|
|
* The faulter has caused a fault and awaits paging
|
|
*
|
|
* \param s signal that communicated the fault
|
|
*/
|
|
void fault_occured(Signal const & s) { _take_fault(s); }
|
|
|
|
/**
|
|
* Current fault has been resolved so resume faulter
|
|
*/
|
|
void fault_resolved() { _end_fault(); }
|
|
|
|
/**
|
|
* User identification of pager object
|
|
*/
|
|
unsigned badge() const { return _badge; }
|
|
|
|
/**
|
|
* Resume faulter
|
|
*/
|
|
void wake_up();
|
|
|
|
/**
|
|
* Unnecessary as base-hw doesn't use exception handlers
|
|
*/
|
|
void exception_handler(Signal_context_capability);
|
|
|
|
/**
|
|
* Install information that is necessary to handle page faults
|
|
*
|
|
* \param c linkage between signal context and a signal receiver
|
|
* \param p linkage between pager object and a pager entry-point
|
|
*/
|
|
void start_paging(Signal_context_capability const & c,
|
|
Pager_capability const & p)
|
|
{
|
|
_signal_context_cap = c;
|
|
Object_pool<Pager_object>::Entry::cap(p);
|
|
}
|
|
|
|
/**
|
|
* Uninstall paging information and cancel unresolved faults
|
|
*/
|
|
void stop_paging()
|
|
{
|
|
Object_pool<Pager_object>::Entry::cap(Native_capability());
|
|
_signal_context_cap = Signal_context_capability();
|
|
_end_fault_if_pending();
|
|
}
|
|
|
|
|
|
/******************
|
|
** Pure virtual **
|
|
******************/
|
|
|
|
/**
|
|
* Request a mapping that resolves a fault directly
|
|
*
|
|
* \param p offers the fault data and receives mapping data
|
|
*
|
|
* \retval 0 succeeded
|
|
* \retval !=0 fault can't be received directly
|
|
*/
|
|
virtual int pager(Ipc_pager & p) = 0;
|
|
|
|
|
|
/***************
|
|
** Accessors **
|
|
***************/
|
|
|
|
Thread_capability thread_cap() const;
|
|
|
|
void thread_cap(Thread_capability const & c);
|
|
|
|
unsigned signal_context_id() const;
|
|
};
|
|
|
|
class Genode::Pager_activation_base : public Thread_base,
|
|
public Signal_receiver,
|
|
public Ipc_pager
|
|
{
|
|
private:
|
|
|
|
Native_capability _cap;
|
|
Lock _cap_valid;
|
|
Pager_entrypoint * _ep;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* \param name name of the new thread
|
|
* \param stack_size stack size of the new thread
|
|
*/
|
|
Pager_activation_base(char const * const name,
|
|
size_t const stack_size);
|
|
|
|
/**
|
|
* Bring current mapping data into effect
|
|
*
|
|
* \retval 0 succeeded
|
|
* \retval -1 failed
|
|
*/
|
|
int apply_mapping();
|
|
|
|
|
|
/**********************
|
|
** Thread interface **
|
|
**********************/
|
|
|
|
void entry();
|
|
|
|
|
|
/***************
|
|
** Accessors **
|
|
***************/
|
|
|
|
Native_capability cap();
|
|
|
|
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 /* _BASE__PAGER_H_ */
|