nova: support creation of vCPU in own PD

With the patch a VMM is not forced anymore to co-located the VMM and VM in same
PD.

Fixes #949
This commit is contained in:
Alexander Boettcher 2013-11-14 10:35:44 +01:00 committed by Norman Feske
parent 1df48b8331
commit 67c1ad4cdd
5 changed files with 83 additions and 31 deletions

View File

@ -52,6 +52,7 @@ namespace Genode {
addr_t _initial_esp; addr_t _initial_esp;
addr_t _initial_eip; addr_t _initial_eip;
addr_t _client_exc_pt_sel; addr_t _client_exc_pt_sel;
addr_t _client_exc_vcpu;
struct struct
{ {
@ -131,6 +132,7 @@ namespace Genode {
*/ */
addr_t exc_pt_sel() { return _tid.exc_pt_sel; } addr_t exc_pt_sel() { return _tid.exc_pt_sel; }
addr_t exc_pt_sel_client() { return _client_exc_pt_sel; } addr_t exc_pt_sel_client() { return _client_exc_pt_sel; }
addr_t exc_pt_vcpu() { return _client_exc_vcpu; }
/** /**
* Set initial stack pointer used by the startup handler * Set initial stack pointer used by the startup handler
@ -226,6 +228,18 @@ namespace Genode {
* all remotely available portals had been revoked beforehand. * all remotely available portals had been revoked beforehand.
*/ */
void cleanup_call(); void cleanup_call();
/**
* Open receive window for initial portals for vCPU.
*/
void prepare_vCPU_portals()
{
_client_exc_vcpu = cap_map()->insert(Nova::NUM_INITIAL_VCPU_PT_LOG2);
Nova::Utcb *utcb = reinterpret_cast<Nova::Utcb *>(Thread_base::utcb());
utcb->crd_rcv = Nova::Obj_crd(_client_exc_vcpu, Nova::NUM_INITIAL_VCPU_PT_LOG2);
}
}; };

View File

@ -550,6 +550,7 @@ namespace Nova {
NUM_INITIAL_PT_LOG2 = 5, NUM_INITIAL_PT_LOG2 = 5,
NUM_INITIAL_PT = 1UL << NUM_INITIAL_PT_LOG2, NUM_INITIAL_PT = 1UL << NUM_INITIAL_PT_LOG2,
NUM_INITIAL_PT_RESERVED = 2 * NUM_INITIAL_PT, NUM_INITIAL_PT_RESERVED = 2 * NUM_INITIAL_PT,
NUM_INITIAL_VCPU_PT_LOG2 = 8,
}; };
/** /**

View File

@ -64,4 +64,27 @@ inline void request_signal_sm_cap(Genode::Native_capability const &cap,
Genode::addr_t sel) { Genode::addr_t sel) {
request_event_portal(cap, sel, ~0UL - 1, 0); } request_event_portal(cap, sel, ~0UL - 1, 0); }
inline void delegate_vcpu_portals(Genode::Native_capability const &cap,
Genode::addr_t sel)
{
using namespace Nova;
Utcb *utcb = reinterpret_cast<Utcb *>(Genode::Thread_base::myself()->utcb());
/* save original receive window */
Crd orig_crd = utcb->crd_rcv;
utcb->crd_rcv = Obj_crd();
utcb->set_msg_word(0);
uint8_t res = utcb->append_item(Obj_crd(sel, NUM_INITIAL_VCPU_PT_LOG2), 0);
(void)res;
res = call(cap.local_name());
/* restore original receive window */
utcb->crd_rcv = orig_crd;
if (res)
PERR("setting exception portals for vCPU failed %u", res);
}
#endif /* _NOVA__INCLUDE__UTIL_H_ */ #endif /* _NOVA__INCLUDE__UTIL_H_ */

View File

@ -194,6 +194,12 @@ void Pager_object::_invoke_handler()
Pager_object *obj; Pager_object *obj;
Utcb *utcb = _check_handler(myself, obj); Utcb *utcb = _check_handler(myself, obj);
/* if protocol is violated ignore request and close receive window */
if (utcb->msg_words() != 2) {
utcb->crd_rcv = Obj_crd();
reply(myself->stack_top());
}
/* send single portal as reply */ /* send single portal as reply */
addr_t const event = utcb->msg[0]; addr_t const event = utcb->msg[0];
addr_t const logcount = utcb->msg[1]; addr_t const logcount = utcb->msg[1];
@ -325,8 +331,10 @@ static uint8_t create_portal(addr_t pt, addr_t pd, addr_t ec, Mtd mtd,
Pager_object::Pager_object(unsigned long badge, Affinity::Location location) Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
: Thread_base("pager:", PF_HANDLER_STACK_SIZE), :
_badge(reinterpret_cast<unsigned long>(_context->name + 6)) Thread_base("pager:", PF_HANDLER_STACK_SIZE),
_badge(reinterpret_cast<unsigned long>(_context->name + 6)),
_client_exc_vcpu(Native_thread::INVALID_INDEX)
{ {
class Create_exception_pt_failed { }; class Create_exception_pt_failed { };
uint8_t res; uint8_t res;
@ -441,6 +449,13 @@ Pager_object::~Pager_object()
cap_map()->remove(_pt_cleanup, 1, false); cap_map()->remove(_pt_cleanup, 1, false);
cap_map()->remove(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2, false); cap_map()->remove(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2, false);
if (_client_exc_vcpu == Native_thread::INVALID_INDEX)
return;
/* revoke vCPU exception portals */
revoke(Obj_crd(_client_exc_vcpu, NUM_INITIAL_VCPU_PT_LOG2));
cap_map()->remove(_client_exc_vcpu, NUM_INITIAL_VCPU_PT_LOG2, false);
} }

View File

@ -100,38 +100,32 @@ int Platform_thread::start(void *ip, void *sp)
return -5; return -5;
} }
/*
* For the first thread of a new PD, use the initial stack pointer for
* reporting the thread's UTCB address.
*/
addr_t pd_utcb = Native_config::context_area_virtual_base() +
Native_config::context_area_virtual_size() -
get_page_size();
_sel_exc_base = _pager->exc_pt_sel_client();
addr_t pd_core_sel = Platform_pd::pd_core_sel(); addr_t pd_core_sel = Platform_pd::pd_core_sel();
addr_t pd_utcb = 0;
_sel_exc_base = is_vcpu() ? _pager->exc_pt_vcpu() : _pager->exc_pt_sel_client();
addr_t remap_src[] = { _pd->parent_pt_sel() }; if (!is_vcpu()) {
addr_t remap_dst[] = { PT_SEL_PARENT }; pd_utcb = Native_config::context_area_virtual_base() +
addr_t pd_sel; Native_config::context_area_virtual_size() - get_page_size();
Obj_crd initial_pts(_sel_exc_base, NUM_INITIAL_PT_LOG2); addr_t remap_src[] = { _pd->parent_pt_sel() };
addr_t remap_dst[] = { PT_SEL_PARENT };
uint8_t res; /* remap exception portals for first thread */
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
/* remap exception portals for first thread */ if (map_local((Utcb *)Thread_base::myself()->utcb(),
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) { Obj_crd(remap_src[i], 0),
if (map_local((Utcb *)Thread_base::myself()->utcb(), Obj_crd(_sel_exc_base + remap_dst[i], 0)))
Obj_crd(remap_src[i], 0), return -6;
Obj_crd(_sel_exc_base + remap_dst[i], 0))) }
return -6;
} }
pd_sel = cap_map()->insert(); addr_t pd_sel = cap_map()->insert();
/* create task */ /* create task */
res = create_pd(pd_sel, pd_core_sel, initial_pts); Obj_crd initial_pts(_sel_exc_base, is_vcpu() ?
NUM_INITIAL_VCPU_PT_LOG2 : NUM_INITIAL_PT_LOG2);
uint8_t res = create_pd(pd_sel, pd_core_sel, initial_pts);
if (res != NOVA_OK) { if (res != NOVA_OK) {
PERR("create_pd returned %d", res); PERR("create_pd returned %d", res);
goto cleanup_pd; goto cleanup_pd;
@ -238,9 +232,6 @@ Thread_state Platform_thread::state()
void Platform_thread::state(Thread_state s) void Platform_thread::state(Thread_state s)
{ {
/* not permitted for main thread */
if (is_main_thread()) throw Cpu_session::State_access_failed();
/* you can do it only once */ /* you can do it only once */
if (_sel_exc_base != Native_thread::INVALID_INDEX) if (_sel_exc_base != Native_thread::INVALID_INDEX)
throw Cpu_session::State_access_failed(); throw Cpu_session::State_access_failed();
@ -251,8 +242,16 @@ void Platform_thread::state(Thread_state s)
* s.is_vcpu If true it will run as vCPU, * s.is_vcpu If true it will run as vCPU,
* otherwise it will be a thread. * otherwise it will be a thread.
*/ */
_sel_exc_base = s.sel_exc_base; if (!is_main_thread())
if (s.is_vcpu) _features |= VCPU; _sel_exc_base = s.sel_exc_base;
if (!s.is_vcpu)
return;
_features |= VCPU;
if (is_main_thread() && _pager)
_pager->prepare_vCPU_portals();
} }