Hi,
As a toy exercise I'm trying to write a very simple custom pager
which simply allocates memory from RAM to handle page faults.
When I try to handle the fault I get a region conflict exception.
Can someone tell me why?? I think I am missing something
fundamental here.
Thanks
Daniel
----
#include <base/printf.h>
#include <base/sleep.h>
#include <base/rpc_server.h>
#include <cap_session/connection.h>
#include <dataspace/client.h>
#include <rom_session/connection.h>
#include <rm_session/connection.h>
#include <ram_session/connection.h>
#include <root/component.h>
#include <util/avl_string.h>
#include <util/misc_math.h>
#include <assert.h>
#define PAGE_SIZE 4096
using namespace Genode;
namespace Test
{
/**
* Example pager class
*
* @return
*/
class Pager : public Thread<8192>
{
private:
Signal_receiver _receiver;
public:
Signal_receiver *signal_receiver() { return &_receiver; }
void entry();
};
/**
* Example backing store class - this one uses physical memory
*
*/
class Physical_backing_store : public Signal_context
{
private:
Rm_connection _rm;
size_t _size;
public:
// ctor
Physical_backing_store(size_t size): _rm(0,_size) {
_size = size;
assert(_size > 0);
}
virtual ~Physical_backing_store() {
}
/**
* Page fault handler.
*
*/
void handle_fault()
{
Rm_session::State state = _rm.state();
printf("Test::Physical_backing_store:: rm session state is
%s, pf_addr=0x%lx\n",
state.type == Rm_session::READ_FAULT ? "READ_FAULT"
:
state.type == Rm_session::WRITE_FAULT ? "WRITE_FAULT"
:
state.type == Rm_session::EXEC_FAULT ? "EXEC_FAULT"
: "READY",
state.addr);
if (state.type == Rm_session::READY)
return;
try {
Dataspace_capability _ds;
try {
_ds = env()->ram_session()->alloc(PAGE_SIZE);
}
catch(...) { PERR("Actual page allocation failed.\n"); }
_rm.attach_at(_ds, state.addr & ~(PAGE_SIZE - 1));
PDBG("attached data space OK!\n");
}
catch (Genode::Rm_session::Region_conflict) {
PERR("Region conflict - this should not happen\n");
}
catch (Genode::Rm_session::Out_of_metadata) {
PERR("Out of meta data!\n");
}
catch(...) {
PERR("Something else caused attach to fail in fault
handler.\n");
}
return;
}
Rm_connection *rm() { return &_rm; }
Dataspace_capability ds() { return _rm.dataspace(); }
void connect_pager(Pager& _pager) {
/* connect pager signal receiver to the fault handler */
_rm.fault_handler(_pager.signal_receiver()->manage(this));
}
};
/**
* Entry point for pager thread.
*
*/
void Pager::entry()
{
printf("Pager thread started OK.\n");
while (true) {
try {
Signal signal = _receiver.wait_for_signal();
for (int i = 0; i < signal.num(); i++) {
static_cast<Physical_backing_store
*>(signal.context())->handle_fault();
}
} catch (...) {
PDBG("unexpected error while waiting for signal");
}
}
}
}
int main()
{
Genode::printf("Test-pager example. ;-))\n");
Test::Pager _pager;
/* start pager thread */
_pager.start();
/* create dataspace etc. */
try {
enum { MANAGED_DS_SIZE = 64*1024*1024 };
Test::Physical_backing_store bs(MANAGED_DS_SIZE);
/* connect pager to fault handler */
bs.connect_pager(_pager);
/* attach to dataspace */
char * addr = (char*)
env()->rm_session()->attach(bs.ds());
assert(addr);
/* trigger read fault */
printf("!!!Triggering fault...\n");
printf("%c%c%c\n",addr[0],addr[1],addr[2]);
printf("Fault handled OK.\n");
}
catch(...) {
PERR("Something failed ????.\n");
}
printf("test-pager completed.\n");
Genode::sleep_forever();
return 0;
}