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:
parent
1df48b8331
commit
67c1ad4cdd
|
@ -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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue