/*
 * \brief  Pager implementations that are specific for the HW-core
 * \author Martin Stein
 * \date   2012-03-29
 */

/*
 * Copyright (C) 2012-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.
 */

/* Genode includes */
#include <base/pager.h>
#include <base/printf.h>

using namespace Genode;


/***************************
 ** Pager_activation_base **
 ***************************/

void Pager_activation_base::entry()
{
	/* acknowledge that we're ready to work */
	Ipc_pager pager;
	_cap = pager;
	_cap_valid.unlock();

	/* wait for the first pagefault */
	bool reply = false;
	while (1)
	{
		if (reply)
			pager.resolve_and_wait_for_fault();
		else
			pager.wait_for_fault();

		/* lookup pager object for the current faulter */
		Object_pool<Pager_object>::Guard o(_ep ? _ep->lookup_and_lock(pager.badge()) : 0);
		if (!o) {
			PERR("%s:%d: Invalid pager object", __FILE__, __LINE__);
			while (1) ;
		}
		/* let pager handle the pagefault, apply mapping, await pagefault */
		reply = !o->pager(pager);
	}
}


/**********************
 ** Pager_entrypoint **
 **********************/

Pager_entrypoint::Pager_entrypoint(Cap_session *,
                                   Pager_activation_base * const a)
: _activation(a) { _activation->ep(this); }


void Pager_entrypoint::dissolve(Pager_object * const o) { remove_locked(o); }


Pager_capability Pager_entrypoint::manage(Pager_object * const o)
{
	/* do we have an activation */
	if (!_activation) return Pager_capability();

	/* create cap with the object badge as local name */
	Native_capability c;
	c = Native_capability(_activation->cap().dst(), o->badge());

	/* let activation provide the pager object */
	o->cap(c);
	insert(o);

	/* return pager-object cap */
	return reinterpret_cap_cast<Pager_object>(c);
}


/***************
 ** Ipc_pager **
 ***************/


void Ipc_pager::wait_for_fault()
{
	/* receive first message */
	size_t s = Kernel::wait_for_request();
	while (1) {
		switch (s) {

		case sizeof(Pagefault): {

			/* message is a pagefault */
			Native_utcb * const utcb = Thread_base::myself()->utcb();
			Pagefault * const pf = (Pagefault *)utcb;
			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("%s:%d: Invalid pagefault", __FILE__, __LINE__);
				continue;
			}
			continue; }

		case sizeof(Pagefault_resolved): {

			/* message is a release request from a RM session */
			Native_utcb * const utcb = Thread_base::myself()->utcb();
			Pagefault_resolved * const msg = (Pagefault_resolved *)utcb;

			/* resume faulter, send ack to RM and get the next message */
			Kernel::resume_thread(msg->pager_object->badge());
			s = Kernel::reply(0, 1);
			continue; }

		default: {

			PERR("%s:%d: Invalid message format", __FILE__, __LINE__);
			continue; }
		}
	}
}

