nova: use async. map for thread/pd bootstrap

Fixes #2173
This commit is contained in:
Alexander Boettcher 2016-11-30 19:36:32 +01:00 committed by Norman Feske
parent 5a72738def
commit e93ef168a1
14 changed files with 270 additions and 295 deletions

View File

@ -730,7 +730,6 @@ namespace Nova {
enum { enum {
PT_SEL_PAGE_FAULT = 0xe, PT_SEL_PAGE_FAULT = 0xe,
PT_SEL_PARENT = 0x1a, /* convention on Genode */ PT_SEL_PARENT = 0x1a, /* convention on Genode */
PT_SEL_MAIN_PAGER = 0x1b, /* convention on Genode */
PT_SEL_MAIN_EC = 0x1c, /* convention on Genode */ PT_SEL_MAIN_EC = 0x1c, /* convention on Genode */
PT_SEL_STARTUP = 0x1e, PT_SEL_STARTUP = 0x1e,
PT_SEL_RECALL = 0x1f, PT_SEL_RECALL = 0x1f,

View File

@ -29,9 +29,8 @@ inline void nova_die(const char * text = 0)
} }
inline void request_event_portal(Genode::Native_capability const &cap, inline void request_event_portal(Genode::addr_t const cap,
Genode::addr_t sel, Genode::addr_t event, Genode::addr_t const sel, Genode::addr_t event)
unsigned short log2_count = 0)
{ {
Genode::Thread * myself = Genode::Thread::myself(); Genode::Thread * myself = Genode::Thread::myself();
Nova::Utcb *utcb = reinterpret_cast<Nova::Utcb *>(myself->utcb()); Nova::Utcb *utcb = reinterpret_cast<Nova::Utcb *>(myself->utcb());
@ -40,38 +39,36 @@ inline void request_event_portal(Genode::Native_capability const &cap,
Nova::Crd orig_crd = utcb->crd_rcv; Nova::Crd orig_crd = utcb->crd_rcv;
/* request event-handler portal */ /* request event-handler portal */
utcb->crd_rcv = Nova::Obj_crd(sel, log2_count); utcb->crd_rcv = Nova::Obj_crd(sel, 0);
utcb->msg[0] = event; utcb->msg[0] = event;
utcb->msg[1] = log2_count; utcb->set_msg_word(1);
utcb->set_msg_word(2);
Genode::uint8_t res = Nova::call(cap.local_name()); Genode::uint8_t res = Nova::call(cap);
/* restore original receive window */ /* restore original receive window */
utcb->crd_rcv = orig_crd; utcb->crd_rcv = orig_crd;
if (res) if (res)
Genode::error("request of event (", event, ") ", Genode::error("request of event (", Genode::Hex(event), ") ",
"capability selector failed (res=", res, ")"); "capability selector failed (res=", res, ")");
} }
inline void request_native_ec_cap(Genode::Native_capability const &cap, inline void request_native_ec_cap(Genode::addr_t const cap,
Genode::addr_t const sel,
unsigned const no_pager_cap = 0)
{
request_event_portal(cap, sel , ~0UL, no_pager_cap);
}
inline void request_signal_sm_cap(Genode::Native_capability const &cap,
Genode::addr_t const sel) Genode::addr_t const sel)
{ {
request_event_portal(cap, sel, ~0UL - 1, 0); request_event_portal(cap, sel , ~0UL);
} }
inline void translate_remote_pager(Genode::Native_capability const &cap, inline void request_signal_sm_cap(Genode::addr_t const cap,
Genode::addr_t const sel)
{
request_event_portal(cap, sel, ~0UL - 1);
}
inline void translate_remote_pager(Genode::addr_t const cap,
Genode::addr_t const sel) Genode::addr_t const sel)
{ {
Genode::Thread * myself = Genode::Thread::myself(); Genode::Thread * myself = Genode::Thread::myself();
@ -94,7 +91,7 @@ inline void translate_remote_pager(Genode::Native_capability const &cap,
Nova::Obj_crd obj_crd(sel, 0); Nova::Obj_crd obj_crd(sel, 0);
if (utcb->append_item(obj_crd, HOTSPOT, THIS_PD, NON_GUEST, TRANSLATE)) if (utcb->append_item(obj_crd, HOTSPOT, THIS_PD, NON_GUEST, TRANSLATE))
/* trigger the translation */ /* trigger the translation */
res = Nova::call(cap.local_name()); res = Nova::call(cap);
/* restore original receive window */ /* restore original receive window */
utcb->crd_rcv = orig_crd; utcb->crd_rcv = orig_crd;

View File

@ -222,4 +222,69 @@ inline void unmap_local(Nova::Utcb *utcb, Genode::addr_t start,
} }
template <typename FUNC>
inline Nova::uint8_t syscall_retry(Genode::Pager_object &pager, FUNC func)
{
Nova::uint8_t res;
do {
res = func();
} while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == pager.handle_oom());
return res;
}
inline Nova::uint8_t async_map(Genode::Pager_object &pager,
Genode::addr_t const source_pd,
Genode::addr_t const target_pd,
Nova::Obj_crd const &source_initial_caps,
Nova::Obj_crd const &target_initial_caps,
Nova::Utcb *utcb)
{
/* asynchronously map capabilities */
utcb->set_msg_word(0);
/* ignore return value as one item always fits into the utcb */
bool const ok = utcb->append_item(source_initial_caps, 0);
(void)ok;
return syscall_retry(pager,
[&]() {
return Nova::delegate(source_pd, target_pd, target_initial_caps);
});
}
inline Nova::uint8_t map_vcpu_portals(Genode::Pager_object &pager,
Genode::addr_t const source_exc_base,
Genode::addr_t const target_exc_base,
Nova::Utcb *utcb,
Genode::addr_t const source_pd)
{
using Nova::Obj_crd;
using Nova::NUM_INITIAL_VCPU_PT_LOG2;
Obj_crd const source_initial_caps(source_exc_base, NUM_INITIAL_VCPU_PT_LOG2);
Obj_crd const target_initial_caps(target_exc_base, NUM_INITIAL_VCPU_PT_LOG2);
return async_map(pager, source_pd, pager.pd_sel(),
source_initial_caps, target_initial_caps, utcb);
}
inline Nova::uint8_t map_pagefault_portal(Genode::Pager_object &pager,
Genode::addr_t const source_exc_base,
Genode::addr_t const target_exc_base,
Genode::addr_t const target_pd,
Nova::Utcb *utcb)
{
using Nova::Obj_crd;
using Nova::PT_SEL_PAGE_FAULT;
Genode::addr_t const source_pd = Genode::platform_specific()->core_pd_sel();
Obj_crd const source_initial_caps(source_exc_base + PT_SEL_PAGE_FAULT, 0);
Obj_crd const target_initial_caps(target_exc_base + PT_SEL_PAGE_FAULT, 0);
return async_map(pager, source_pd, target_pd,
source_initial_caps, target_initial_caps, utcb);
}
#endif /* _CORE__INCLUDE__NOVA_UTIL_H_ */ #endif /* _CORE__INCLUDE__NOVA_UTIL_H_ */

View File

@ -121,7 +121,6 @@ namespace Genode {
Exception_handlers _exceptions; Exception_handlers _exceptions;
addr_t _pd_target; addr_t _pd_target;
addr_t _pd_source;
void _copy_state_from_utcb(Nova::Utcb * utcb); void _copy_state_from_utcb(Nova::Utcb * utcb);
void _copy_state_to_utcb(Nova::Utcb * utcb); void _copy_state_to_utcb(Nova::Utcb * utcb);
@ -179,15 +178,8 @@ namespace Genode {
/** /**
* Assign PD selector to PD * Assign PD selector to PD
*/ */
void assign_pd(addr_t pd_sel) void assign_pd(addr_t pd_sel) { _pd_target = pd_sel; }
{
if (_pd_target == _pd_source)
_pd_source = pd_sel;
_pd_target = pd_sel;
}
addr_t pd_sel() const { return _pd_target; } addr_t pd_sel() const { return _pd_target; }
addr_t pd_source() const { return _pd_source; }
void exception(uint8_t exit_id); void exception(uint8_t exit_id);
@ -227,14 +219,6 @@ namespace Genode {
return true; return true;
} }
/**
* Return entry point address
*/
addr_t handler_address()
{
return reinterpret_cast<addr_t>(_invoke_handler);
}
/** /**
* Copy thread state of recalled thread. * Copy thread state of recalled thread.
*/ */
@ -403,15 +387,6 @@ namespace Genode {
Pager_activation_base(char const * const name, Pager_activation_base(char const * const name,
size_t const stack_size); size_t const stack_size);
/**
* Set entry point, which the activation serves
*
* This function is only called by the 'Pager_entrypoint'
* constructor.
*/
void ep(Pager_entrypoint *ep) { _ep = ep; }
Pager_entrypoint *ep() { return _ep; }
/** /**
* Thread interface * Thread interface
*/ */
@ -440,11 +415,6 @@ namespace Genode {
*/ */
class Pager_entrypoint : public Object_pool<Pager_object> class Pager_entrypoint : public Object_pool<Pager_object>
{ {
private:
Pager_activation_base *_activation;
Rpc_cap_factory &_cap_factory;
public: public:
/** /**
@ -459,7 +429,8 @@ namespace Genode {
/** /**
* Associate Pager_object with the entry point * Associate Pager_object with the entry point
*/ */
Pager_capability manage(Pager_object *obj); Pager_capability manage(Pager_object *) {
return Pager_capability(); }
/** /**
* Dissolve Pager_object from entry point * Dissolve Pager_object from entry point

View File

@ -28,7 +28,7 @@ namespace Genode {
Native_capability _parent; Native_capability _parent;
int _thread_cnt; int _thread_cnt;
addr_t _pd_sel; addr_t const _pd_sel;
const char * _label; const char * _label;
public: public:
@ -66,11 +66,6 @@ namespace Genode {
*/ */
addr_t parent_pt_sel() { return _parent.local_name(); } addr_t parent_pt_sel() { return _parent.local_name(); }
/**
* Assign PD selector to PD
*/
void assign_pd(addr_t pd_sel) { _pd_sel = pd_sel; }
/** /**
* Capability selector of this task. * Capability selector of this task.
* *

View File

@ -45,6 +45,7 @@ namespace Genode {
VCPU = 0x2U, VCPU = 0x2U,
WORKER = 0x4U, WORKER = 0x4U,
SC_CREATED = 0x8U, SC_CREATED = 0x8U,
REMOTE_PD = 0x10U,
}; };
uint8_t _features; uint8_t _features;
uint8_t _priority; uint8_t _priority;
@ -60,9 +61,19 @@ namespace Genode {
inline bool vcpu() const { return _features & VCPU; } inline bool vcpu() const { return _features & VCPU; }
inline bool worker() const { return _features & WORKER; } inline bool worker() const { return _features & WORKER; }
inline bool sc_created() const { return _features & SC_CREATED; } inline bool sc_created() const { return _features & SC_CREATED; }
inline bool remote_pd() const { return _features & REMOTE_PD; }
public: 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;
}
/* invalid thread number */ /* invalid thread number */
enum { THREAD_INVALID = -1 }; enum { THREAD_INVALID = -1 };
@ -137,7 +148,7 @@ namespace Genode {
/** /**
* Set pager * Set pager
*/ */
void pager(Pager_object *pager) { _pager = pager; } void pager(Pager_object *pager);
/** /**
* Return pager object * Return pager object

View File

@ -25,6 +25,8 @@
#include <platform.h> #include <platform.h>
#include <platform_thread.h> #include <platform_thread.h>
#include <imprint_badge.h> #include <imprint_badge.h>
#include <cpu_thread_component.h>
#include <core_env.h>
/* NOVA includes */ /* NOVA includes */
#include <nova/syscalls.h> #include <nova/syscalls.h>
@ -115,6 +117,10 @@ void Pager_object::_page_fault_handler(addr_t pager_obj)
Pager_activation_base * pager_thread = static_cast<Pager_activation_base *>(myself); Pager_activation_base * pager_thread = static_cast<Pager_activation_base *>(myself);
/* potential request to ask for EC cap or signal SM cap */
if (utcb->msg_words() == 1)
_invoke_handler(pager_obj);
/* lookup fault address and decide what to do */ /* lookup fault address and decide what to do */
int error = obj->pager(ipc_pager); int error = obj->pager(ipc_pager);
@ -298,8 +304,14 @@ void Pager_object::_invoke_handler(addr_t pager_obj)
if (utcb->crd_rcv.value()) if (utcb->crd_rcv.value())
nova_die(); nova_die();
addr_t const event = utcb->msg[0]; /* if protocol is violated ignore request */
addr_t const logcount = utcb->msg[1]; if (utcb->msg_words() != 1) {
utcb->mtd = 0;
utcb->set_msg_word(0);
reply(myself->stack_top());
}
addr_t const event = utcb->msg[0];
/* check for translated pager portals - required for vCPU in remote PDs */ /* check for translated pager portals - required for vCPU in remote PDs */
if (utcb->msg_items() == 1 && utcb->msg_words() == 1 && event == 0xaffe) { if (utcb->msg_items() == 1 && utcb->msg_words() == 1 && event == 0xaffe) {
@ -309,17 +321,27 @@ void Pager_object::_invoke_handler(addr_t pager_obj)
/* valid item which got translated ? */ /* valid item which got translated ? */
if (!cap.is_null() && !item->is_del()) { if (!cap.is_null() && !item->is_del()) {
using Pool = Object_pool<Pager_object>; Rpc_entrypoint *e = core_env()->entrypoint();
pager_threads[0]->ep()->Pool::apply(cap.base(), e->apply(cap.base(),
[&] (Pager_object *source) { [&] (Cpu_thread_component *source) {
/* set source PD (VMM) where vCPU exception portals are */ if (!source)
obj->_pd_source = source->pd_sel(); 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);
});
}
/* if protocol is violated ignore request */
if (utcb->msg_words() != 2) {
utcb->mtd = 0; utcb->mtd = 0;
utcb->set_msg_word(0); utcb->set_msg_word(0);
reply(myself->stack_top()); reply(myself->stack_top());
@ -345,12 +367,7 @@ void Pager_object::_invoke_handler(addr_t pager_obj)
*/ */
bool res = utcb->append_item(Obj_crd(obj->_state.sel_client_ec, 0, bool res = utcb->append_item(Obj_crd(obj->_state.sel_client_ec, 0,
Obj_crd::RIGHT_EC_RECALL), 0); Obj_crd::RIGHT_EC_RECALL), 0);
/* if logcount > 0 then the pager cap should also be mapped */
if (logcount)
res = utcb->append_item(Obj_crd(obj->Object_pool<Pager_object>::Entry::cap().local_name(), 0), 1);
(void)res; (void)res;
reply(myself->stack_top());
} }
/* semaphore for signaling thread is requested, reuse PT_SEL_STARTUP. */ /* semaphore for signaling thread is requested, reuse PT_SEL_STARTUP. */
@ -371,20 +388,8 @@ void Pager_object::_invoke_handler(addr_t pager_obj)
bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel_client() + bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel_client() +
PT_SEL_STARTUP, 0), 0); PT_SEL_STARTUP, 0), 0);
(void)res; (void)res;
reply(myself->stack_top());
} }
/* sanity check, if event is not valid return nothing */
if (logcount > NUM_INITIAL_PT_LOG2 || event > 1UL << NUM_INITIAL_PT_LOG2 ||
event + (1UL << logcount) > (1UL << NUM_INITIAL_PT_LOG2))
reply(myself->stack_top());
/* valid event portal is requested, delegate it to caller */
bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel_client() + event,
logcount), 0);
(void)res;
reply(myself->stack_top()); reply(myself->stack_top());
} }
@ -479,16 +484,14 @@ void Pager_object::print(Output &out) const
static uint8_t create_portal(addr_t pt, addr_t pd, addr_t ec, Mtd mtd, static uint8_t create_portal(addr_t pt, addr_t pd, addr_t ec, Mtd mtd,
addr_t eip, Pager_object * oom_handler) addr_t eip, Pager_object * oom_handler)
{ {
addr_t const badge_localname = reinterpret_cast<addr_t>(oom_handler); uint8_t res = syscall_retry(*oom_handler,
[&]() { return create_pt(pt, pd, ec, mtd, eip); });
uint8_t res;
do {
res = create_pt(pt, pd, ec, mtd, eip);
} while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == oom_handler->handle_oom());
if (res != NOVA_OK) if (res != NOVA_OK)
return res; return res;
addr_t const badge_localname = reinterpret_cast<addr_t>(oom_handler);
res = pt_ctrl(pt, badge_localname); res = pt_ctrl(pt, badge_localname);
if (res == NOVA_OK) if (res == NOVA_OK)
revoke(Obj_crd(pt, 0, Obj_crd::RIGHT_PT_CTRL)); revoke(Obj_crd(pt, 0, Obj_crd::RIGHT_PT_CTRL));
@ -582,8 +585,7 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap,
_cpu_session_cap(cpu_session_cap), _thread_cap(thread_cap), _cpu_session_cap(cpu_session_cap), _thread_cap(thread_cap),
_location(location), _location(location),
_exceptions(this), _exceptions(this),
_pd_target(Native_thread::INVALID_INDEX), _pd_target(Native_thread::INVALID_INDEX)
_pd_source(Native_thread::INVALID_INDEX)
{ {
uint8_t res; uint8_t res;
@ -934,7 +936,6 @@ void Pager_activation_base::entry() { }
Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &cap_factory) Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &cap_factory)
: _cap_factory(cap_factory)
{ {
/* sanity check for pager threads */ /* sanity check for pager threads */
if (kernel_hip()->cpu_max() > PAGER_CPUS) { if (kernel_hip()->cpu_max() > PAGER_CPUS) {
@ -954,56 +955,12 @@ Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &cap_factory)
pager_threads[i] = pager_of_cpu; pager_threads[i] = pager_of_cpu;
construct_at<Pager>(pager_threads[i]); construct_at<Pager>(pager_threads[i]);
pager_threads[i]->ep(this);
} }
} }
Pager_capability Pager_entrypoint::manage(Pager_object *obj)
{
/* let handle pager_object of pager thread on same CPU */
unsigned const genode_cpu_id = obj->location().xpos();
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(genode_cpu_id);
if (!kernel_hip()->is_cpu_enabled(kernel_cpu_id) ||
!pager_threads[genode_cpu_id]) {
warning("invalid CPU parameter used in pager object");
return Pager_capability();
}
Native_capability pager_thread_cap =
Capability_space::import(pager_threads[genode_cpu_id]->native_thread().ec_sel);
/* request creation of portal bind to pager thread */
Native_capability cap_session =
_cap_factory.alloc(pager_thread_cap, obj->handler_address(), 0);
imprint_badge(cap_session.local_name(), reinterpret_cast<mword_t>(obj));
/* disable the feature for security reasons now */
revoke(Obj_crd(cap_session.local_name(), 0, Obj_crd::RIGHT_PT_CTRL));
/* add server object to object pool */
obj->Object_pool<Pager_object>::Entry::cap(cap_session);
insert(obj);
/* return capability that uses the object id as badge */
return reinterpret_cap_cast<Pager_object>(
obj->Object_pool<Pager_object>::Entry::cap());
}
void Pager_entrypoint::dissolve(Pager_object *obj) void Pager_entrypoint::dissolve(Pager_object *obj)
{ {
Native_capability pager_obj = obj->Object_pool<Pager_object>::Entry::cap();
/* cleanup at cap factory */
_cap_factory.free(pager_obj);
/* revoke cap selector locally */
revoke(Capability_space::crd(pager_obj), true);
/* remove object from pool */
remove(obj);
/* take care that no faults are in-flight */ /* take care that no faults are in-flight */
obj->cleanup_call(); obj->cleanup_call();
} }

View File

@ -16,6 +16,7 @@
#include <util/flex_iterator.h> #include <util/flex_iterator.h>
/* core includes */ /* core includes */
#include <platform.h>
#include <platform_pd.h> #include <platform_pd.h>
using namespace Genode; using namespace Genode;
@ -48,7 +49,23 @@ void Platform_pd::assign_parent(Native_capability parent)
Platform_pd::Platform_pd(Allocator * md_alloc, char const *label, Platform_pd::Platform_pd(Allocator * md_alloc, char const *label,
signed pd_id, bool create) signed pd_id, bool create)
: _thread_cnt(0), _pd_sel(Native_thread::INVALID_INDEX), _label(label) { } : _thread_cnt(0), _pd_sel(cap_map()->insert()), _label(label)
{
if (_pd_sel == Native_thread::INVALID_INDEX) {
error("platform pd creation failed ");
return;
}
/* create task */
enum { KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE = 2, UPPER_LIMIT_PAGES = 32 };
uint8_t res = Nova::create_pd(_pd_sel, platform_specific()->core_pd_sel(),
Nova::Obj_crd(),
KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE,
UPPER_LIMIT_PAGES);
if (res != Nova::NOVA_OK)
error("create_pd returned ", res);
}
Platform_pd::~Platform_pd() Platform_pd::~Platform_pd()

View File

@ -34,6 +34,33 @@
using namespace Genode; using namespace Genode;
static uint8_t map_thread_portals(Pager_object &pager,
addr_t const target_exc_base,
Nova::Utcb *utcb)
{
using Nova::Obj_crd;
using Nova::NUM_INITIAL_PT_LOG2;
addr_t const source_pd = platform_specific()->core_pd_sel();
addr_t const source_exc_base = pager.exc_pt_sel_client();
addr_t const target_pd = pager.pd_sel();
/* xxx better map portals with solely pt_call and sm separately ? xxx */
addr_t const rights = Obj_crd::RIGHT_EC_RECALL |
Obj_crd::RIGHT_PT_CTRL | Obj_crd::RIGHT_PT_CALL |
Obj_crd::RIGHT_SM_UP | Obj_crd::RIGHT_SM_DOWN;
Obj_crd const source_initial_caps(source_exc_base, NUM_INITIAL_PT_LOG2,
rights);
Obj_crd const target_initial_caps(target_exc_base, NUM_INITIAL_PT_LOG2,
rights);
return async_map(pager, source_pd, target_pd,
source_initial_caps, target_initial_caps, utcb);
}
/********************* /*********************
** Platform thread ** ** Platform thread **
*********************/ *********************/
@ -62,14 +89,8 @@ int Platform_thread::start(void *ip, void *sp)
return -2; return -2;
} }
if (_pager->pd_sel() != Native_thread::INVALID_INDEX) {
error("thread already started");
return -2;
}
Utcb * const utcb = reinterpret_cast<Utcb *>(Thread::myself()->utcb()); Utcb * const utcb = reinterpret_cast<Utcb *>(Thread::myself()->utcb());
addr_t const pts = vcpu() ? NUM_INITIAL_VCPU_PT_LOG2 unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_location.xpos());
: NUM_INITIAL_PT_LOG2;
addr_t const pt_oom = _pager->get_oom_portal(); addr_t const pt_oom = _pager->get_oom_portal();
if (!pt_oom || map_local(utcb, if (!pt_oom || map_local(utcb,
@ -87,35 +108,30 @@ int Platform_thread::start(void *ip, void *sp)
return -3; return -3;
} }
_pager->assign_pd(_pd->pd_sel()); uint8_t res = syscall_retry(*_pager,
[&]() {
return create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id,
utcb_addr, initial_sp, _sel_exc_base,
!worker());
});
/* second++ vcpu case which runs in other pd than VMM */ if (res != Nova::NOVA_OK) {
if (vcpu() && _pager->pd_sel() != _pager->pd_source()) { error("creation of new thread failed ", res);
Obj_crd const source_initial_caps(_sel_exc_base, pts); return -4;
Obj_crd const target_initial_caps(_sel_exc_base, pts);
/* asynchronously map capabilities */
utcb->set_msg_word(0);
if (!utcb->append_item(source_initial_caps, 0))
return -3;
uint8_t res = Nova::delegate(_pager->pd_source(), _pager->pd_sel(),
target_initial_caps);
if (res != NOVA_OK)
return -3;
} }
uint8_t res; if (vcpu()) {
do { if (!remote_pd())
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_location.xpos()); res = map_pagefault_portal(*_pager, _pager->exc_pt_sel_client(),
res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id, _sel_exc_base, _pd->pd_sel(), utcb);
utcb_addr, initial_sp, _sel_exc_base, !worker()); } else
if (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK != _pager->handle_oom()) { res = map_thread_portals(*_pager, _sel_exc_base, utcb);
_pager->assign_pd(Native_thread::INVALID_INDEX);
error("creation of new thread failed ", res); if (res != NOVA_OK) {
return -4; revoke(Obj_crd(_sel_ec(), 0));
} error("creation of new thread/vcpu failed ", res);
} while (res != Nova::NOVA_OK); return -3;
}
if (worker()) { if (worker()) {
/* local/worker threads do not require a startup portal */ /* local/worker threads do not require a startup portal */
@ -135,21 +151,14 @@ int Platform_thread::start(void *ip, void *sp)
} }
addr_t pd_utcb = 0; addr_t pd_utcb = 0;
Obj_crd initial_pts;
if (!vcpu()) { if (!vcpu()) {
_sel_exc_base = _pager->exc_pt_sel_client(); _sel_exc_base = _pager->exc_pt_sel_client();
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 const rights = Obj_crd::RIGHT_EC_RECALL | addr_t remap_src[] = { _pd->parent_pt_sel() };
Obj_crd::RIGHT_PT_CTRL | Obj_crd::RIGHT_PT_CALL | addr_t remap_dst[] = { PT_SEL_PARENT };
Obj_crd::RIGHT_SM_UP | Obj_crd::RIGHT_SM_DOWN;
initial_pts = Obj_crd(_sel_exc_base, pts, rights);
addr_t remap_src[] = { _pd->parent_pt_sel(),
(unsigned long)_pager->Object_pool<Pager_object>::Entry::cap().local_name() };
addr_t remap_dst[] = { PT_SEL_PARENT, PT_SEL_MAIN_PAGER };
/* remap exception portals for first thread */ /* remap exception portals for first thread */
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) { for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
@ -160,88 +169,49 @@ int Platform_thread::start(void *ip, void *sp)
} }
} }
/* create task */
addr_t const pd_sel = cap_map()->insert();
enum { KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE = 2, UPPER_LIMIT_PAGES = 32 };
uint8_t res = create_pd(pd_sel, platform_specific()->core_pd_sel(),
initial_pts,
KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE,
UPPER_LIMIT_PAGES);
if (res != NOVA_OK) {
error("create_pd returned ", res);
goto cleanup_pd;
}
/* create first thread in task */ /* create first thread in task */
enum { THREAD_GLOBAL = true }; enum { THREAD_GLOBAL = true };
res = create_ec(_sel_ec(), pd_sel, uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id,
platform_specific()->kernel_cpu_id(_location.xpos()), pd_utcb, 0, vcpu() ? _sel_exc_base : 0,
pd_utcb, 0, 0, THREAD_GLOBAL);
THREAD_GLOBAL);
if (res != NOVA_OK) { if (res != NOVA_OK) {
error("create_ec returned ", res); error("create_ec returned ", res);
goto cleanup_pd; return -7;
} }
/*
* We have to assign the pd here, because after create_sc the thread
* becomes running immediately.
*/
_pd->assign_pd(pd_sel);
_pager->client_set_ec(_sel_ec()); _pager->client_set_ec(_sel_ec());
_pager->initial_eip((addr_t)ip); _pager->initial_eip((addr_t)ip);
_pager->initial_esp((addr_t)sp); _pager->initial_esp((addr_t)sp);
_pager->assign_pd(pd_sel);
if (vcpu() && _pager->pd_sel() != _pager->pd_source()) { if (vcpu())
Obj_crd const source_initial_caps(_sel_exc_base, pts); _features |= REMOTE_PD;
Obj_crd const target_initial_caps(0, pts); else
res = map_thread_portals(*_pager, 0, utcb);
/* asynchronously map capabilities */
utcb->set_msg_word(0);
res = utcb->append_item(source_initial_caps, 0);
if (res)
res = Nova::delegate(_pager->pd_source(), _pager->pd_sel(),
target_initial_caps);
}
if (res == NOVA_OK) { if (res == NOVA_OK) {
do { res = syscall_retry(*_pager,
/* let the thread run */ [&]() {
res = create_sc(_sel_sc(), pd_sel, _sel_ec(), /* let the thread run */
Qpd(Qpd::DEFAULT_QUANTUM, _priority)); return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(),
} while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == _pager->handle_oom()); Qpd(Qpd::DEFAULT_QUANTUM, _priority));
});
} }
if (res != NOVA_OK) { if (res != NOVA_OK) {
/*
* Reset pd cap since thread got not running and pd cap will
* be revoked during cleanup.
*/
_pd->assign_pd(Native_thread::INVALID_INDEX);
_pager->client_set_ec(Native_thread::INVALID_INDEX); _pager->client_set_ec(Native_thread::INVALID_INDEX);
_pager->initial_eip(0); _pager->initial_eip(0);
_pager->initial_esp(0); _pager->initial_esp(0);
_pager->assign_pd(Native_thread::INVALID_INDEX);
error("create_sc returned ", res); error("create_sc returned ", res);
goto cleanup_ec;
/* cap_selector free for _sel_ec is done in de-constructor */
revoke(Obj_crd(_sel_ec(), 0));
return -8;
} }
_features |= SC_CREATED; _features |= SC_CREATED;
return 0; return 0;
cleanup_ec:
/* cap_selector free for _sel_ec is done in de-constructor */
revoke(Obj_crd(_sel_ec(), 0));
cleanup_pd:
revoke(Obj_crd(pd_sel, 0));
cap_map()->remove(pd_sel, 0, false);
return -7;
} }
@ -264,15 +234,16 @@ void Platform_thread::resume()
return; return;
} }
uint8_t res; if (!_pd || !_pager) {
do { error("protection domain undefined - resuming thread failed");
if (!_pd) { return;
error("protection domain undefined - resuming thread failed"); }
return;
} uint8_t res = syscall_retry(*_pager,
res = create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), [&]() {
Qpd(Qpd::DEFAULT_QUANTUM, _priority)); return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(),
} while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == _pager->handle_oom()); Qpd(Qpd::DEFAULT_QUANTUM, _priority));
});
if (res == NOVA_OK) if (res == NOVA_OK)
_features |= SC_CREATED; _features |= SC_CREATED;
@ -374,6 +345,13 @@ unsigned long long Platform_thread::execution_time() const
} }
void Platform_thread::pager(Pager_object *pager)
{
_pager = pager;
_pager->assign_pd(_pd->pd_sel());
}
Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, Platform_thread::Platform_thread(size_t, const char *name, unsigned prio,
Affinity::Location affinity, int thread_id) Affinity::Location affinity, int thread_id)
: :

View File

@ -24,8 +24,8 @@
#include <nova/syscalls.h> #include <nova/syscalls.h>
/* core includes */ /* core includes */
#include <nova_util.h>
#include <platform.h> #include <platform.h>
#include <nova_util.h>
using namespace Genode; using namespace Genode;

View File

@ -54,7 +54,7 @@ namespace Genode {
{ {
/* request mapping of semaphore capability selector */ /* request mapping of semaphore capability selector */
Thread * myself = Thread::myself(); Thread * myself = Thread::myself();
request_signal_sm_cap(Capability_space::import(myself->native_thread().ec_sel + 1), request_signal_sm_cap(myself->native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT,
myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP); myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP);
_sem = Capability_space::import(myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP); _sem = Capability_space::import(myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP);
call<Rpc_register_semaphore>(_sem); call<Rpc_register_semaphore>(_sem);

View File

@ -20,7 +20,6 @@
#include <base/env.h> #include <base/env.h>
#include <base/rpc_client.h> #include <base/rpc_client.h>
#include <session/session.h> #include <session/session.h>
#include <nova_native_cpu/client.h>
#include <cpu_thread/client.h> #include <cpu_thread/client.h>
/* base-internal includes */ /* base-internal includes */
@ -82,13 +81,10 @@ void Thread::_init_platform_thread(size_t weight, Type type)
if (type == MAIN || type == REINITIALIZED_MAIN) { if (type == MAIN || type == REINITIALIZED_MAIN) {
_thread_cap = env()->parent()->main_thread_cap(); _thread_cap = env()->parent()->main_thread_cap();
Genode::Native_capability pager_cap =
Capability_space::import(Nova::PT_SEL_MAIN_PAGER);
native_thread().exc_pt_sel = 0; native_thread().exc_pt_sel = 0;
native_thread().ec_sel = Nova::PT_SEL_MAIN_EC; native_thread().ec_sel = Nova::PT_SEL_MAIN_EC;
request_native_ec_cap(pager_cap, native_thread().ec_sel); request_native_ec_cap(PT_SEL_PAGE_FAULT, native_thread().ec_sel);
return; return;
} }
@ -126,8 +122,8 @@ void Thread::_deinit_platform_thread()
using namespace Nova; using namespace Nova;
if (native_thread().ec_sel != Native_thread::INVALID_INDEX) { if (native_thread().ec_sel != Native_thread::INVALID_INDEX) {
revoke(Obj_crd(native_thread().ec_sel, 1)); revoke(Obj_crd(native_thread().ec_sel, 0));
cap_map()->remove(native_thread().ec_sel, 1, false); cap_map()->remove(native_thread().ec_sel, 0, false);
} }
/* de-announce thread */ /* de-announce thread */
@ -151,14 +147,6 @@ void Thread::start()
using namespace Genode; using namespace Genode;
/* 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(_thread_cap);
if (!pager_cap.valid())
throw Cpu_session::Thread_creation_failed();
/* create EC at core */ /* create EC at core */
Thread_state state; Thread_state state;
state.sel_exc_base = native_thread().exc_pt_sel; state.sel_exc_base = native_thread().exc_pt_sel;
@ -175,20 +163,20 @@ void Thread::start()
cpu_thread.start(thread_ip, _stack->top()); cpu_thread.start(thread_ip, _stack->top());
/* request native EC thread cap */ /* request native EC thread cap */
native_thread().ec_sel = cap_map()->insert(1); native_thread().ec_sel = cap_map()->insert();
if (native_thread().ec_sel == Native_thread::INVALID_INDEX) if (native_thread().ec_sel == Native_thread::INVALID_INDEX)
throw Cpu_session::Thread_creation_failed(); throw Cpu_session::Thread_creation_failed();
/* requested pager cap used by request_native_ec_cap in Signal_source_client */ /*
enum { MAP_PAGER_CAP = 1 }; * Requested ec cap that is used for recall and
request_native_ec_cap(pager_cap, native_thread().ec_sel, MAP_PAGER_CAP); * creation of portals (Nova_native_pd::alloc_rpc_cap).
*/
request_native_ec_cap(native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT,
native_thread().ec_sel);
using namespace Nova; using namespace Nova;
/* request exception portals for normal threads */
if (!native_thread().vcpu) { if (!native_thread().vcpu) {
request_event_portal(pager_cap, native_thread().exc_pt_sel, 0, NUM_INITIAL_PT_LOG2);
/* default: we don't accept any mappings or translations */ /* default: we don't accept any mappings or translations */
Utcb * utcb_obj = reinterpret_cast<Utcb *>(utcb()); Utcb * utcb_obj = reinterpret_cast<Utcb *>(utcb());
utcb_obj->crd_rcv = Obj_crd(); utcb_obj->crd_rcv = Obj_crd();

View File

@ -227,8 +227,8 @@ void test_revoke(Genode::Env &env)
* as used before by copy_session_cap * as used before by copy_session_cap
*/ */
Genode::Thread * myself = Genode::Thread::myself(); Genode::Thread * myself = Genode::Thread::myself();
Genode::Native_capability pager_cap = Capability_space::import(myself->native_thread().ec_sel + 1); request_native_ec_cap(myself->native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT,
request_event_portal(pager_cap, copy_session_cap.local_name(), 0, 0); copy_session_cap.local_name());
/* check whether the requested cap before is valid and placed well */ /* check whether the requested cap before is valid and placed well */
crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0); crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0);

View File

@ -20,7 +20,6 @@
#include <cpu_session/connection.h> #include <cpu_session/connection.h>
#include <pd_session/connection.h> #include <pd_session/connection.h>
#include <region_map/client.h> #include <region_map/client.h>
#include <nova_native_cpu/client.h>
#include <cpu_thread/client.h> #include <cpu_thread/client.h>
/* NOVA includes */ /* NOVA includes */
@ -79,21 +78,15 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
state.vcpu = true; state.vcpu = true;
Cpu_thread_client cpu_thread(vcpu_vm); Cpu_thread_client cpu_thread(vcpu_vm);
cpu_thread.state(state); cpu_thread.state(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);
/* /*
* Translate pager cap of current executing thread, which is used * Translate vcpu_vm thread cap via current executing thread,
* to lookup current PD - required during PD creation. * which is used to lookup current PD to delegate VM-exit portals.
*/ */
translate_remote_pager(pager_cap, addr_t const current = Thread::myself()->native_thread().exc_pt_sel
Thread::myself()->native_thread().ec_sel + 1); + Nova::PT_SEL_PAGE_FAULT;
translate_remote_pager(current, vcpu_vm.local_name());
/* start vCPU in separate PD */ /* start vCPU in separate PD */
cpu_thread.start(0, 0); cpu_thread.start(0, 0);
@ -102,7 +95,11 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
* Request native EC thread cap and put it next to the * Request native EC thread cap and put it next to the
* SM cap - see Vcpu_dispatcher->sel_sm_ec description * SM cap - see Vcpu_dispatcher->sel_sm_ec description
*/ */
request_native_ec_cap(pager_cap, sel_ec); 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 */ /* request creation of SC to let vCPU run */
cpu_thread.resume(); cpu_thread.resume();
@ -152,15 +149,15 @@ class Vmm::Vcpu_same_pd : public Vmm::Vcpu_thread, Genode::Thread
{ {
this->Thread::start(); this->Thread::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 * Request native EC thread cap and put it next to the
* SM cap - see Vcpu_dispatcher->sel_sm_ec description * SM cap - see Vcpu_dispatcher->sel_sm_ec description
*/ */
Native_capability pager_cap = native_cpu.pager_cap(_thread_cap); addr_t const pager_pt = exc_base() + Nova::PT_SEL_PAGE_FAULT;
request_native_ec_cap(pager_cap, sel_ec); 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));
} }
void entry() { } void entry() { }