mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-16 07:27:35 +00:00
nova: remove legacy vCPU creation support
Vbox5 was the last user. Seoul and VBox6 using the Genode VM interface. Issue #5492
This commit is contained in:
parent
016d63703d
commit
b72a6b3400
@ -57,35 +57,4 @@ inline void request_signal_sm_cap(Genode::addr_t const cap,
|
||||
}
|
||||
|
||||
|
||||
inline void translate_remote_pager(Genode::addr_t const cap,
|
||||
Genode::addr_t const sel)
|
||||
{
|
||||
Genode::Thread * myself = Genode::Thread::myself();
|
||||
Nova::Utcb *utcb = reinterpret_cast<Nova::Utcb *>(myself->utcb());
|
||||
|
||||
/* save original receive window */
|
||||
Nova::Crd orig_crd = utcb->crd_rcv;
|
||||
|
||||
utcb->crd_rcv = Nova::Obj_crd();
|
||||
|
||||
Genode::uint8_t res = Nova::NOVA_OK;
|
||||
enum {
|
||||
TRANSLATE = true, THIS_PD = false, NON_GUEST = false, HOTSPOT = 0
|
||||
};
|
||||
|
||||
/* translate one item */
|
||||
utcb->msg()[0] = 0xaffe;
|
||||
utcb->set_msg_word(1);
|
||||
|
||||
Nova::Obj_crd obj_crd(sel, 0);
|
||||
if (utcb->append_item(obj_crd, HOTSPOT, THIS_PD, NON_GUEST, TRANSLATE))
|
||||
/* trigger the translation */
|
||||
res = Nova::call(cap);
|
||||
|
||||
/* restore original receive window */
|
||||
utcb->crd_rcv = orig_crd;
|
||||
|
||||
if (res != Nova::NOVA_OK)
|
||||
Genode::error("setting exception portals for vCPU failed res=", res);
|
||||
}
|
||||
#endif /* _INCLUDE__NOVA__UTIL_H_ */
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
struct Genode::Cpu_session::Native_cpu : Interface
|
||||
{
|
||||
enum Thread_type { GLOBAL, LOCAL, VCPU };
|
||||
enum Thread_type { GLOBAL, LOCAL };
|
||||
|
||||
/*
|
||||
* Exception base of thread in caller protection domain - not in core!
|
||||
|
@ -47,10 +47,8 @@ class Core::Platform_thread
|
||||
|
||||
enum {
|
||||
MAIN_THREAD = 0x1U,
|
||||
VCPU = 0x2U,
|
||||
WORKER = 0x4U,
|
||||
SC_CREATED = 0x8U,
|
||||
REMOTE_PD = 0x10U,
|
||||
WORKER = 0x2U,
|
||||
SC_CREATED = 0x4U,
|
||||
};
|
||||
uint8_t _features;
|
||||
uint8_t _priority;
|
||||
@ -63,10 +61,8 @@ class Core::Platform_thread
|
||||
|
||||
/* convenience function to access _feature variable */
|
||||
inline bool main_thread() const { return _features & MAIN_THREAD; }
|
||||
inline bool vcpu() const { return _features & VCPU; }
|
||||
inline bool worker() const { return _features & WORKER; }
|
||||
inline bool sc_created() const { return _features & SC_CREATED; }
|
||||
inline bool remote_pd() const { return _features & REMOTE_PD; }
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
@ -81,15 +77,6 @@ class Core::Platform_thread
|
||||
|
||||
public:
|
||||
|
||||
/* mark as vcpu in remote pd if it is a vcpu */
|
||||
addr_t remote_vcpu() {
|
||||
if (!vcpu())
|
||||
return Native_thread::INVALID_INDEX;
|
||||
|
||||
_features |= Platform_thread::REMOTE_PD;
|
||||
return _sel_exc_base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -387,39 +387,6 @@ void Pager_object::_invoke_handler(Pager_object &obj)
|
||||
|
||||
addr_t const event = utcb.msg()[0];
|
||||
|
||||
/* check for translated pager portals - required for vCPU in remote PDs */
|
||||
if (utcb.msg_items() == 1 && utcb.msg_words() == 1 && event == 0xaffe) {
|
||||
|
||||
Nova::Utcb::Item const &item = *utcb.get_item(0);
|
||||
Nova::Crd const cap(item.crd);
|
||||
|
||||
/* valid item which got translated ? */
|
||||
if (!cap.is_null() && !item.is_del() && _core_ep_ptr) {
|
||||
_core_ep_ptr->apply(cap.base(),
|
||||
[&] (Cpu_thread_component *source) {
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
Platform_thread &p = source->platform_thread();
|
||||
addr_t const sel_exc_base = p.remote_vcpu();
|
||||
if (sel_exc_base == Native_thread::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
/* delegate VM-exit portals */
|
||||
map_vcpu_portals(p.pager(), sel_exc_base, sel_exc_base,
|
||||
utcb, obj.pd_sel());
|
||||
|
||||
/* delegate portal to contact pager */
|
||||
map_pagefault_portal(obj, p.pager().exc_pt_sel_client(),
|
||||
sel_exc_base, obj.pd_sel(), utcb);
|
||||
});
|
||||
}
|
||||
|
||||
utcb.mtd = 0;
|
||||
utcb.set_msg_word(0);
|
||||
reply(my_stack_top());
|
||||
}
|
||||
|
||||
utcb.mtd = 0;
|
||||
utcb.set_msg_word(0);
|
||||
|
||||
|
@ -67,7 +67,7 @@ void Platform_thread::affinity(Affinity::Location location)
|
||||
if (!_pager)
|
||||
return;
|
||||
|
||||
if (worker() || vcpu() || !sc_created())
|
||||
if (worker() || !sc_created())
|
||||
return;
|
||||
|
||||
_pager->migrate(platform_specific().sanitize(location));
|
||||
@ -109,7 +109,7 @@ void Platform_thread::start(void *ip, void *sp)
|
||||
|
||||
Pager_object &pager = *_pager;
|
||||
|
||||
if (main_thread() && !vcpu() && (_pd.parent_pt_sel() == Native_thread::INVALID_INDEX)) {
|
||||
if (main_thread() && (_pd.parent_pt_sel() == Native_thread::INVALID_INDEX)) {
|
||||
error("protection domain undefined");
|
||||
return;
|
||||
}
|
||||
@ -125,7 +125,7 @@ void Platform_thread::start(void *ip, void *sp)
|
||||
|
||||
if (!main_thread()) {
|
||||
addr_t const initial_sp = reinterpret_cast<addr_t>(sp);
|
||||
addr_t const utcb_addr = vcpu() ? 0 : round_page(initial_sp);
|
||||
addr_t const utcb_addr = round_page(initial_sp);
|
||||
|
||||
if (_sel_exc_base == Native_thread::INVALID_INDEX) {
|
||||
error("exception base not specified");
|
||||
@ -144,12 +144,11 @@ void Platform_thread::start(void *ip, void *sp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vcpu())
|
||||
res = map_thread_portals(pager, _sel_exc_base, utcb);
|
||||
res = map_thread_portals(pager, _sel_exc_base, utcb);
|
||||
|
||||
if (res != NOVA_OK) {
|
||||
revoke(Obj_crd(_sel_ec(), 0));
|
||||
error("creation of new thread/vcpu failed ", res);
|
||||
error("creation of new thread failed ", res);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -164,28 +163,26 @@ void Platform_thread::start(void *ip, void *sp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vcpu() && _sel_exc_base != Native_thread::INVALID_INDEX) {
|
||||
if (_sel_exc_base != Native_thread::INVALID_INDEX) {
|
||||
error("thread already started");
|
||||
return;
|
||||
}
|
||||
|
||||
addr_t pd_utcb = 0;
|
||||
|
||||
if (!vcpu()) {
|
||||
_sel_exc_base = 0;
|
||||
_sel_exc_base = 0;
|
||||
|
||||
pd_utcb = stack_area_virtual_base() + stack_virtual_size() - get_page_size();
|
||||
pd_utcb = stack_area_virtual_base() + stack_virtual_size() - get_page_size();
|
||||
|
||||
addr_t remap_src[] = { _pd.parent_pt_sel() };
|
||||
addr_t remap_dst[] = { PT_SEL_PARENT };
|
||||
addr_t remap_src[] = { _pd.parent_pt_sel() };
|
||||
addr_t remap_dst[] = { PT_SEL_PARENT };
|
||||
|
||||
/* remap exception portals for first thread */
|
||||
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
|
||||
if (map_local(source_pd, utcb,
|
||||
Obj_crd(remap_src[i], 0),
|
||||
Obj_crd(pager.exc_pt_sel_client() + remap_dst[i], 0)))
|
||||
return;
|
||||
}
|
||||
/* remap exception portals for first thread */
|
||||
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
|
||||
if (map_local(source_pd, utcb,
|
||||
Obj_crd(remap_src[i], 0),
|
||||
Obj_crd(pager.exc_pt_sel_client() + remap_dst[i], 0)))
|
||||
return;
|
||||
}
|
||||
|
||||
/* create first thread in task */
|
||||
@ -202,10 +199,7 @@ void Platform_thread::start(void *ip, void *sp)
|
||||
pager.initial_eip((addr_t)ip);
|
||||
pager.initial_esp((addr_t)sp);
|
||||
|
||||
if (vcpu())
|
||||
_features |= REMOTE_PD;
|
||||
else
|
||||
res = map_thread_portals(pager, 0, utcb);
|
||||
res = map_thread_portals(pager, 0, utcb);
|
||||
|
||||
if (res == NOVA_OK) {
|
||||
res = syscall_retry(pager,
|
||||
@ -333,13 +327,11 @@ void Platform_thread::thread_type(Cpu_session::Native_cpu::Thread_type thread_ty
|
||||
if (_sel_exc_base != Native_thread::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
if (!main_thread() || (thread_type == Cpu_session::Native_cpu::Thread_type::VCPU))
|
||||
if (!main_thread())
|
||||
_sel_exc_base = exception_base.exception_base;
|
||||
|
||||
if (thread_type == Cpu_session::Native_cpu::Thread_type::LOCAL)
|
||||
_features |= WORKER;
|
||||
else if (thread_type == Cpu_session::Native_cpu::Thread_type::VCPU)
|
||||
_features |= VCPU;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
* \brief Utilities for implementing VMMs on Genode/NOVA
|
||||
* \author Norman Feske
|
||||
* \date 2013-08-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__VMM__PRINTF_H_
|
||||
#define _INCLUDE__VMM__PRINTF_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <base/log.h>
|
||||
|
||||
/* NOVA includes */
|
||||
#include <nova/syscalls.h>
|
||||
|
||||
namespace Vmm {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
/**
|
||||
* Print message while preserving the UTCB content
|
||||
*/
|
||||
template <typename... ARGS>
|
||||
void log(ARGS... args)
|
||||
{
|
||||
struct Utcb_backup { char buf[Nova::Utcb::size()]; };
|
||||
|
||||
static Mutex mutex;
|
||||
static Utcb_backup utcb_backup;
|
||||
|
||||
Mutex::Guard guard(mutex);
|
||||
|
||||
utcb_backup = *(Utcb_backup *)Thread::myself()->utcb();
|
||||
|
||||
Genode::log("VMM: ", args...);
|
||||
|
||||
*(Utcb_backup *)Thread::myself()->utcb() = utcb_backup;
|
||||
}
|
||||
|
||||
template <typename... ARGS>
|
||||
void warning(ARGS... args)
|
||||
{
|
||||
struct Utcb_backup { char buf[Nova::Utcb::size()]; };
|
||||
|
||||
static Mutex mutex;
|
||||
static Utcb_backup utcb_backup;
|
||||
|
||||
Mutex::Guard guard(mutex);
|
||||
|
||||
utcb_backup = *(Utcb_backup *)Thread::myself()->utcb();
|
||||
|
||||
Genode::warning("VMM: ", args...);
|
||||
|
||||
*(Utcb_backup *)Thread::myself()->utcb() = utcb_backup;
|
||||
}
|
||||
|
||||
template <typename... ARGS>
|
||||
void error(ARGS... args)
|
||||
{
|
||||
struct Utcb_backup { char buf[Nova::Utcb::size()]; };
|
||||
|
||||
static Mutex mutex;
|
||||
static Utcb_backup utcb_backup;
|
||||
|
||||
Mutex::Guard guard(mutex);
|
||||
|
||||
utcb_backup = *(Utcb_backup *)Thread::myself()->utcb();
|
||||
|
||||
Genode::error("VMM: ", args...);
|
||||
|
||||
*(Utcb_backup *)Thread::myself()->utcb() = utcb_backup;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__VMM__PRINTF_H_ */
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* \brief Guard to save a UTCB and restore it during guard destruction
|
||||
* \author Alexander Boettcher
|
||||
* \date 2013-07-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__VMM__UTCB_GUARD_H_
|
||||
#define _INCLUDE__VMM__UTCB_GUARD_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/string.h>
|
||||
|
||||
/* NOVA syscalls */
|
||||
#include <nova/syscalls.h>
|
||||
|
||||
|
||||
namespace Vmm {
|
||||
using namespace Genode;
|
||||
class Utcb_guard;
|
||||
}
|
||||
|
||||
|
||||
class Vmm::Utcb_guard
|
||||
{
|
||||
public:
|
||||
|
||||
struct Utcb_backup { char buf[Nova::Utcb::size()]; };
|
||||
|
||||
private:
|
||||
|
||||
Utcb_backup &_backup_utcb;
|
||||
|
||||
public:
|
||||
|
||||
Utcb_guard(Utcb_backup &backup_utcb) : _backup_utcb(backup_utcb)
|
||||
{
|
||||
Nova::Utcb *utcb =
|
||||
reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb());
|
||||
|
||||
unsigned header_len = (char *)utcb->msg() - (char *)utcb;
|
||||
unsigned len = header_len + utcb->msg_words() * sizeof(Nova::mword_t);
|
||||
Genode::memcpy(&_backup_utcb, utcb, len);
|
||||
|
||||
if (utcb->msg_items())
|
||||
Genode::warning("Error: msg items on UTCB are not saved and restored!");
|
||||
}
|
||||
|
||||
~Utcb_guard()
|
||||
{
|
||||
Nova::Utcb *utcb = reinterpret_cast<Nova::Utcb *>(&_backup_utcb);
|
||||
|
||||
unsigned header_len = (char *)utcb->msg() - (char *)utcb;
|
||||
unsigned len = header_len + utcb->msg_words() * sizeof(Nova::mword_t);
|
||||
Genode::memcpy(Thread::myself()->utcb(), utcb, len);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__VMM__UTCB_GUARD_H_ */
|
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* \brief Utilities for implementing VMMs on Genode/NOVA
|
||||
* \author Norman Feske
|
||||
* \date 2013-08-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__VMM__VCPU_DISPATCHER_H_
|
||||
#define _INCLUDE__VMM__VCPU_DISPATCHER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/retry.h>
|
||||
#include <nova_native_pd/client.h>
|
||||
#include <nova/capability_space.h>
|
||||
|
||||
namespace Vmm {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
template <class T>
|
||||
class Vcpu_dispatcher;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thread that handles virtualization events of a 'Vmm::Vcpu_thread'
|
||||
*/
|
||||
template <class T>
|
||||
class Vmm::Vcpu_dispatcher : public T
|
||||
{
|
||||
private:
|
||||
|
||||
enum { WEIGHT = Genode::Cpu_session::Weight::DEFAULT_WEIGHT };
|
||||
|
||||
Env &_env;
|
||||
Nova_native_pd_client _native_pd { _env.pd().native_pd() };
|
||||
|
||||
/**
|
||||
* Portal entry point entered on virtualization events
|
||||
*
|
||||
* For each event type used as argument of the 'register_handler'
|
||||
* function template, the compiler automatically generates a separate
|
||||
* instance of this function. The sole purpose of this function is to
|
||||
* call the 'Vcpu' member function corresponding to the event type.
|
||||
*/
|
||||
template <unsigned EV, typename DISPATCHER, void (DISPATCHER::*FUNC)()>
|
||||
static void _portal_entry()
|
||||
{
|
||||
/* obtain this pointer of the event handler */
|
||||
Genode::Thread *myself = Genode::Thread::myself();
|
||||
DISPATCHER *vd = static_cast<DISPATCHER *>(myself);
|
||||
|
||||
vd->exit_reason = EV;
|
||||
|
||||
/* call event-specific handler function */
|
||||
(vd->*FUNC)();
|
||||
|
||||
/* continue execution of the guest */
|
||||
Nova::reply(myself->stack_top());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
unsigned int exit_reason = 0;
|
||||
|
||||
Vcpu_dispatcher(Genode::Env &env, Genode::size_t stack_size,
|
||||
Cpu_connection *,
|
||||
Genode::Affinity::Location location,
|
||||
const char * name = "vCPU dispatcher")
|
||||
:
|
||||
T(WEIGHT, name, stack_size, location), _env(env)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* request creation of a 'local' EC */
|
||||
T::with_native_thread([&] (Native_thread &nt) {
|
||||
nt.ec_sel = Native_thread::INVALID_INDEX - 1; });
|
||||
|
||||
T::start();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Register virtualization event handler
|
||||
*/
|
||||
template <unsigned EV, typename DISPATCHER, void (DISPATCHER::*FUNC)()>
|
||||
bool register_handler(addr_t exc_base, Nova::Mtd mtd)
|
||||
{
|
||||
/*
|
||||
* Let the compiler generate an instance of a portal entry
|
||||
*/
|
||||
void (*entry)() = &_portal_entry<EV, DISPATCHER, FUNC>;
|
||||
|
||||
Untyped_capability handler { };
|
||||
|
||||
T::with_native_thread([&] (Native_thread &nt) {
|
||||
|
||||
/* create the portal at the desired selector index (EV) */
|
||||
Native_capability thread_cap =
|
||||
Capability_space::import(nt.ec_sel);
|
||||
|
||||
Thread::myself()->with_native_thread([&] (Native_thread &myself_nt) {
|
||||
|
||||
handler = retry<Genode::Out_of_ram>(
|
||||
[&] () {
|
||||
/* manually define selector used for RPC result */
|
||||
myself_nt.client_rcv_sel = exc_base + EV;
|
||||
return _native_pd.alloc_rpc_cap(thread_cap, (addr_t)entry,
|
||||
mtd.value());
|
||||
},
|
||||
[&] () {
|
||||
myself_nt.reset_client_rcv_sel();
|
||||
_env.parent().upgrade(Parent::Env::pd(), "ram_quota=16K");
|
||||
});
|
||||
|
||||
/* revert selector allocation to automatic mode of operation */
|
||||
myself_nt.reset_client_rcv_sel();
|
||||
});
|
||||
});
|
||||
|
||||
return handler.valid() && (exc_base + EV == (addr_t)handler.local_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unused member of the 'Thread' interface
|
||||
*
|
||||
* Similarly to how 'Rpc_entrypoints' are handled, a 'Vcpu_dispatcher'
|
||||
* comes with a custom initialization procedure, which does not call
|
||||
* the thread's normal entry function. Instead, the thread's EC gets
|
||||
* associated with several portals, each for handling a specific
|
||||
* virtualization event.
|
||||
*/
|
||||
void entry() override { }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__VMM__VCPU_DISPATCHER_H_ */
|
@ -1,138 +0,0 @@
|
||||
/*
|
||||
* \brief Utilities for implementing VMMs on Genode/NOVA
|
||||
* \author Norman Feske
|
||||
* \date 2013-08-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__VMM__VCPU_THREAD_H_
|
||||
#define _INCLUDE__VMM__VCPU_THREAD_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/thread.h>
|
||||
#include <cpu_session/connection.h>
|
||||
#include <pd_session/connection.h>
|
||||
#include <region_map/client.h>
|
||||
#include <cpu_thread/client.h>
|
||||
#include <nova_native_cpu/client.h>
|
||||
|
||||
/* NOVA includes */
|
||||
#include <nova/native_thread.h>
|
||||
#include <nova/cap_map.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;
|
||||
|
||||
virtual ~Vcpu_thread() { };
|
||||
};
|
||||
|
||||
class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Capability<Genode::Pd_session> _pd_cap;
|
||||
Genode::Affinity::Location _location;
|
||||
Genode::Cpu_connection *_cpu_connection;
|
||||
|
||||
Genode::addr_t _exc_pt_sel;
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Vcpu_other_pd(Vcpu_other_pd const &);
|
||||
Vcpu_other_pd &operator = (Vcpu_other_pd const &);
|
||||
|
||||
public:
|
||||
|
||||
Vcpu_other_pd(Cpu_connection * cpu_connection,
|
||||
Genode::Affinity::Location location,
|
||||
Genode::Capability<Genode::Pd_session> pd_cap,
|
||||
Genode::size_t = 0 /* stack_size */)
|
||||
:
|
||||
_pd_cap(pd_cap), _location(location), _cpu_connection(cpu_connection),
|
||||
_exc_pt_sel(Genode::cap_map().insert(Nova::NUM_INITIAL_VCPU_PT_LOG2))
|
||||
{ }
|
||||
|
||||
void start(Genode::addr_t sel_ec) override
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Thread_capability vcpu_vm { };
|
||||
|
||||
while (!vcpu_vm.valid()) {
|
||||
|
||||
bool denied = false;
|
||||
|
||||
using Error = Cpu_session::Create_thread_error;
|
||||
_cpu_connection->create_thread(_pd_cap, "vCPU", _location,
|
||||
Cpu_session::Weight()).with_result(
|
||||
[&] (Thread_capability cap) { vcpu_vm = cap; },
|
||||
[&] (Error e) {
|
||||
if (e == Error::OUT_OF_RAM) _cpu_connection->upgrade_ram(8*1024);
|
||||
else if (e == Error::OUT_OF_CAPS) _cpu_connection->upgrade_caps(2);
|
||||
else
|
||||
denied = true;
|
||||
}
|
||||
);
|
||||
|
||||
if (denied) {
|
||||
error("Vcpu_other_pd: failed to create vCPU");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* tell parent that this will be a vCPU */
|
||||
Cpu_session::Native_cpu::Thread_type thread_type { Cpu_session::Native_cpu::Thread_type::VCPU };
|
||||
Cpu_session::Native_cpu::Exception_base exception_base { _exc_pt_sel };
|
||||
Nova_native_cpu_client native_cpu(_cpu_connection->native_cpu());
|
||||
native_cpu.thread_type(vcpu_vm, thread_type, exception_base);
|
||||
|
||||
Cpu_thread_client cpu_thread(vcpu_vm);
|
||||
|
||||
/*
|
||||
* Translate vcpu_vm thread cap via current executing thread,
|
||||
* which is used to lookup current PD to delegate VM-exit portals.
|
||||
*/
|
||||
Thread::myself()->with_native_thread([&] (Native_thread &nt) {
|
||||
addr_t const current = nt.exc_pt_sel + Nova::PT_SEL_PAGE_FAULT;
|
||||
translate_remote_pager(current, vcpu_vm.local_name()); });
|
||||
|
||||
/* start vCPU in separate PD */
|
||||
cpu_thread.start(0, 0);
|
||||
|
||||
/*
|
||||
* Request native EC thread cap used for recalling vCPU
|
||||
*/
|
||||
addr_t const pager_pt = _exc_pt_sel + Nova::PT_SEL_PAGE_FAULT;
|
||||
request_native_ec_cap(pager_pt, sel_ec);
|
||||
|
||||
/* solely needed for vcpu to request native ec cap - drop it */
|
||||
Nova::revoke(Nova::Obj_crd(pager_pt, 0));
|
||||
|
||||
/* request creation of SC to let vCPU run */
|
||||
cpu_thread.resume();
|
||||
}
|
||||
|
||||
Genode::addr_t exc_base() override { return _exc_pt_sel; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__VMM__VCPU_THREAD_H_ */
|
Loading…
x
Reference in New Issue
Block a user