genode/repos/ports/include/vmm/vcpu_thread.h
Norman Feske b49e588c1c Assign threads to PD at its creation time
This patch replaces the former 'Pd_session::bind_thread' function by a
PD-capability argument of the 'Cpu_session::create_thread' function, and
removes the ancient thread-start protocol via 'Rm_session::add_client' and
'Cpu_session::set_pager'. Threads are now bound to PDs at their creation
time and implicitly paged according to the address space of the PD.

Note the API change:

This patch changes the signature of the 'Child' and 'Process' constructors.
There is a new 'address_space' argument, which represents the region map
representing the child's address space. It is supplied separately to the
PD session capability (which principally can be invoked to obtain the
PD's address space) to allow the population of the address space
without relying on an 'Pd_session::address_space' RPC call.
Furthermore, a new (optional) env_pd argument allows the explicit
overriding of the PD capability handed out to the child as part of its
environment. It can be used to intercept the interaction of the child
with its PD session at core. This is used by Noux.

Issue #1938
2016-05-09 13:10:52 +02:00

160 lines
4.1 KiB
C++

/*
* \brief Utilities for implementing VMMs on Genode/NOVA
* \author Norman Feske
* \date 2013-08-20
*/
/*
* 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 _INCLUDE__VMM__VCPU_THREAD_H_
#define _INCLUDE__VMM__VCPU_THREAD_H_
/* Genode includes */
#include <base/cap_map.h>
#include <base/thread.h>
#include <cap_session/connection.h>
#include <nova_cpu_session/connection.h>
#include <cpu_session/connection.h>
#include <pd_session/connection.h>
#include <region_map/client.h>
#include <nova_native_cpu/client.h>
/* NOVA includes */
#include <nova/native_thread.h>
namespace Vmm {
using namespace Genode;
class Vcpu_thread;
class Vcpu_other_pd;
class Vcpu_same_pd;
}
class Vmm::Vcpu_thread
{
public:
virtual Genode::addr_t exc_base() = 0;
virtual void start(Genode::addr_t) = 0;
};
class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
{
private:
Genode::Pd_connection _pd_session;
Genode::Affinity::Location _location;
Genode::Cpu_session *_cpu_session;
Genode::addr_t _exc_pt_sel;
public:
Vcpu_other_pd(Cpu_session * cpu_session,
Genode::Affinity::Location location)
:
_pd_session("VM"), _location(location), _cpu_session(cpu_session),
_exc_pt_sel(Genode::cap_map()->insert(Nova::NUM_INITIAL_VCPU_PT_LOG2))
{ }
void start(Genode::addr_t sel_ec)
{
using namespace Genode;
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
Thread_capability vcpu_vm =
_cpu_session->create_thread(_pd_session, WEIGHT, "vCPU", _location);
/* tell parent that this will be a vCPU */
Thread_state state;
state.sel_exc_base = Native_thread::INVALID_INDEX;
state.is_vcpu = true;
_cpu_session->state(vcpu_vm, state);
/* obtain interface to NOVA-specific CPU session operations */
Nova_native_cpu_client native_cpu(_cpu_session->native_cpu());
/* create new pager object and assign it to the new thread */
Native_capability pager_cap = native_cpu.pager_cap(vcpu_vm);
/*
* Delegate parent the vCPU exception portals required during PD
* creation.
*/
delegate_vcpu_portals(pager_cap, exc_base());
/* start vCPU in separate PD */
_cpu_session->start(vcpu_vm, 0, 0);
/*
* Request native EC thread cap and put it next to the
* SM cap - see Vcpu_dispatcher->sel_sm_ec description
*/
request_native_ec_cap(pager_cap, sel_ec);
}
Genode::addr_t exc_base() { return _exc_pt_sel; }
};
class Vmm::Vcpu_same_pd : public Vmm::Vcpu_thread, Genode::Thread_base
{
enum { WEIGHT = Genode::Cpu_session::DEFAULT_WEIGHT };
public:
Vcpu_same_pd(size_t stack_size, Cpu_session * cpu_session,
Genode::Affinity::Location location)
:
Thread_base(WEIGHT, "vCPU", stack_size, Type::NORMAL, cpu_session, location)
{
/* release pre-allocated selectors of Thread */
Genode::cap_map()->remove(native_thread().exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2);
/* allocate correct number of selectors */
this->native_thread().exc_pt_sel = cap_map()->insert(Nova::NUM_INITIAL_VCPU_PT_LOG2);
/* tell generic thread code that this becomes a vCPU */
this->native_thread().is_vcpu = true;
}
~Vcpu_same_pd()
{
using namespace Nova;
revoke(Nova::Obj_crd(this->native_thread().exc_pt_sel, NUM_INITIAL_VCPU_PT_LOG2));
cap_map()->remove(this->native_thread().exc_pt_sel, NUM_INITIAL_VCPU_PT_LOG2, false);
/* allocate selectors for ~Thread */
this->native_thread().exc_pt_sel = cap_map()->insert(Nova::NUM_INITIAL_PT_LOG2);
}
addr_t exc_base() { return this->native_thread().exc_pt_sel; }
void start(Genode::addr_t sel_ec)
{
this->Thread_base::start();
/* obtain interface to NOVA-specific CPU session operations */
Nova_native_cpu_client native_cpu(_cpu_session->native_cpu());
/*
* Request native EC thread cap and put it next to the
* SM cap - see Vcpu_dispatcher->sel_sm_ec description
*/
Native_capability pager_cap = native_cpu.pager_cap(_thread_cap);
request_native_ec_cap(pager_cap, sel_ec);
}
void entry() { }
};
#endif /* _INCLUDE__VMM__VCPU_THREAD_H_ */