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 {
PT_SEL_PAGE_FAULT = 0xe,
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_STARTUP = 0x1e,
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,
Genode::addr_t sel, Genode::addr_t event,
unsigned short log2_count = 0)
inline void request_event_portal(Genode::addr_t const cap,
Genode::addr_t const sel, Genode::addr_t event)
{
Genode::Thread * myself = Genode::Thread::myself();
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;
/* 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[1] = log2_count;
utcb->set_msg_word(2);
utcb->set_msg_word(1);
Genode::uint8_t res = Nova::call(cap.local_name());
Genode::uint8_t res = Nova::call(cap);
/* restore original receive window */
utcb->crd_rcv = orig_crd;
if (res)
Genode::error("request of event (", event, ") ",
Genode::error("request of event (", Genode::Hex(event), ") ",
"capability selector failed (res=", res, ")");
}
inline void request_native_ec_cap(Genode::Native_capability 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,
inline void request_native_ec_cap(Genode::addr_t const cap,
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::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);
if (utcb->append_item(obj_crd, HOTSPOT, THIS_PD, NON_GUEST, TRANSLATE))
/* trigger the translation */
res = Nova::call(cap.local_name());
res = Nova::call(cap);
/* restore original receive window */
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_ */

View File

@ -121,7 +121,6 @@ namespace Genode {
Exception_handlers _exceptions;
addr_t _pd_target;
addr_t _pd_source;
void _copy_state_from_utcb(Nova::Utcb * utcb);
void _copy_state_to_utcb(Nova::Utcb * utcb);
@ -179,15 +178,8 @@ namespace Genode {
/**
* Assign PD selector to PD
*/
void assign_pd(addr_t pd_sel)
{
if (_pd_target == _pd_source)
_pd_source = pd_sel;
_pd_target = pd_sel;
}
void assign_pd(addr_t pd_sel) { _pd_target = pd_sel; }
addr_t pd_sel() const { return _pd_target; }
addr_t pd_source() const { return _pd_source; }
void exception(uint8_t exit_id);
@ -227,14 +219,6 @@ namespace Genode {
return true;
}
/**
* Return entry point address
*/
addr_t handler_address()
{
return reinterpret_cast<addr_t>(_invoke_handler);
}
/**
* Copy thread state of recalled thread.
*/
@ -403,15 +387,6 @@ namespace Genode {
Pager_activation_base(char const * const name,
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
*/
@ -440,11 +415,6 @@ namespace Genode {
*/
class Pager_entrypoint : public Object_pool<Pager_object>
{
private:
Pager_activation_base *_activation;
Rpc_cap_factory &_cap_factory;
public:
/**
@ -459,7 +429,8 @@ namespace Genode {
/**
* 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

View File

@ -28,7 +28,7 @@ namespace Genode {
Native_capability _parent;
int _thread_cnt;
addr_t _pd_sel;
addr_t const _pd_sel;
const char * _label;
public:
@ -66,11 +66,6 @@ namespace Genode {
*/
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.
*

View File

@ -45,6 +45,7 @@ namespace Genode {
VCPU = 0x2U,
WORKER = 0x4U,
SC_CREATED = 0x8U,
REMOTE_PD = 0x10U,
};
uint8_t _features;
uint8_t _priority;
@ -60,9 +61,19 @@ namespace Genode {
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; }
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 */
enum { THREAD_INVALID = -1 };
@ -137,7 +148,7 @@ namespace Genode {
/**
* Set pager
*/
void pager(Pager_object *pager) { _pager = pager; }
void pager(Pager_object *pager);
/**
* Return pager object

View File

@ -25,6 +25,8 @@
#include <platform.h>
#include <platform_thread.h>
#include <imprint_badge.h>
#include <cpu_thread_component.h>
#include <core_env.h>
/* NOVA includes */
#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);
/* 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 */
int error = obj->pager(ipc_pager);
@ -298,8 +304,14 @@ void Pager_object::_invoke_handler(addr_t pager_obj)
if (utcb->crd_rcv.value())
nova_die();
addr_t const event = utcb->msg[0];
addr_t const logcount = utcb->msg[1];
/* if protocol is violated ignore request */
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 */
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 ? */
if (!cap.is_null() && !item->is_del()) {
using Pool = Object_pool<Pager_object>;
pager_threads[0]->ep()->Pool::apply(cap.base(),
[&] (Pager_object *source) {
/* set source PD (VMM) where vCPU exception portals are */
obj->_pd_source = source->pd_sel();
});
}
}
Rpc_entrypoint *e = core_env()->entrypoint();
e->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);
});
}
/* if protocol is violated ignore request */
if (utcb->msg_words() != 2) {
utcb->mtd = 0;
utcb->set_msg_word(0);
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,
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;
reply(myself->stack_top());
}
/* 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() +
PT_SEL_STARTUP, 0), 0);
(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());
}
@ -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,
addr_t eip, Pager_object * oom_handler)
{
addr_t const badge_localname = reinterpret_cast<addr_t>(oom_handler);
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());
uint8_t res = syscall_retry(*oom_handler,
[&]() { return create_pt(pt, pd, ec, mtd, eip); });
if (res != NOVA_OK)
return res;
addr_t const badge_localname = reinterpret_cast<addr_t>(oom_handler);
res = pt_ctrl(pt, badge_localname);
if (res == NOVA_OK)
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),
_location(location),
_exceptions(this),
_pd_target(Native_thread::INVALID_INDEX),
_pd_source(Native_thread::INVALID_INDEX)
_pd_target(Native_thread::INVALID_INDEX)
{
uint8_t res;
@ -934,7 +936,6 @@ void Pager_activation_base::entry() { }
Pager_entrypoint::Pager_entrypoint(Rpc_cap_factory &cap_factory)
: _cap_factory(cap_factory)
{
/* sanity check for pager threads */
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;
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)
{
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 */
obj->cleanup_call();
}

View File

@ -16,6 +16,7 @@
#include <util/flex_iterator.h>
/* core includes */
#include <platform.h>
#include <platform_pd.h>
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,
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()

View File

@ -34,6 +34,33 @@
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 **
*********************/
@ -62,14 +89,8 @@ int Platform_thread::start(void *ip, void *sp)
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());
addr_t const pts = vcpu() ? NUM_INITIAL_VCPU_PT_LOG2
: NUM_INITIAL_PT_LOG2;
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_location.xpos());
addr_t const pt_oom = _pager->get_oom_portal();
if (!pt_oom || map_local(utcb,
@ -87,35 +108,30 @@ int Platform_thread::start(void *ip, void *sp)
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 (vcpu() && _pager->pd_sel() != _pager->pd_source()) {
Obj_crd const source_initial_caps(_sel_exc_base, pts);
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;
if (res != Nova::NOVA_OK) {
error("creation of new thread failed ", res);
return -4;
}
uint8_t res;
do {
unsigned const kernel_cpu_id = platform_specific()->kernel_cpu_id(_location.xpos());
res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id,
utcb_addr, initial_sp, _sel_exc_base, !worker());
if (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK != _pager->handle_oom()) {
_pager->assign_pd(Native_thread::INVALID_INDEX);
error("creation of new thread failed ", res);
return -4;
}
} while (res != Nova::NOVA_OK);
if (vcpu()) {
if (!remote_pd())
res = map_pagefault_portal(*_pager, _pager->exc_pt_sel_client(),
_sel_exc_base, _pd->pd_sel(), utcb);
} else
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);
return -3;
}
if (worker()) {
/* 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;
Obj_crd initial_pts;
if (!vcpu()) {
_sel_exc_base = _pager->exc_pt_sel_client();
pd_utcb = stack_area_virtual_base() + stack_virtual_size() - get_page_size();
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;
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 };
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++) {
@ -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 */
enum { THREAD_GLOBAL = true };
res = create_ec(_sel_ec(), pd_sel,
platform_specific()->kernel_cpu_id(_location.xpos()),
pd_utcb, 0, 0,
THREAD_GLOBAL);
uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id,
pd_utcb, 0, vcpu() ? _sel_exc_base : 0,
THREAD_GLOBAL);
if (res != NOVA_OK) {
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->initial_eip((addr_t)ip);
_pager->initial_esp((addr_t)sp);
_pager->assign_pd(pd_sel);
if (vcpu() && _pager->pd_sel() != _pager->pd_source()) {
Obj_crd const source_initial_caps(_sel_exc_base, pts);
Obj_crd const target_initial_caps(0, pts);
/* 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 (vcpu())
_features |= REMOTE_PD;
else
res = map_thread_portals(*_pager, 0, utcb);
if (res == NOVA_OK) {
do {
/* let the thread run */
res = create_sc(_sel_sc(), pd_sel, _sel_ec(),
Qpd(Qpd::DEFAULT_QUANTUM, _priority));
} while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == _pager->handle_oom());
res = syscall_retry(*_pager,
[&]() {
/* let the thread run */
return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(),
Qpd(Qpd::DEFAULT_QUANTUM, _priority));
});
}
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->initial_eip(0);
_pager->initial_esp(0);
_pager->assign_pd(Native_thread::INVALID_INDEX);
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;
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;
}
uint8_t res;
do {
if (!_pd) {
error("protection domain undefined - resuming thread failed");
return;
}
res = create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(),
Qpd(Qpd::DEFAULT_QUANTUM, _priority));
} while (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK == _pager->handle_oom());
if (!_pd || !_pager) {
error("protection domain undefined - resuming thread failed");
return;
}
uint8_t res = syscall_retry(*_pager,
[&]() {
return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(),
Qpd(Qpd::DEFAULT_QUANTUM, _priority));
});
if (res == NOVA_OK)
_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,
Affinity::Location affinity, int thread_id)
:

View File

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

View File

@ -54,7 +54,7 @@ namespace Genode {
{
/* request mapping of semaphore capability selector */
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);
_sem = Capability_space::import(myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP);
call<Rpc_register_semaphore>(_sem);

View File

@ -20,7 +20,6 @@
#include <base/env.h>
#include <base/rpc_client.h>
#include <session/session.h>
#include <nova_native_cpu/client.h>
#include <cpu_thread/client.h>
/* base-internal includes */
@ -82,13 +81,10 @@ void Thread::_init_platform_thread(size_t weight, Type type)
if (type == MAIN || type == REINITIALIZED_MAIN) {
_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().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;
}
@ -126,8 +122,8 @@ void Thread::_deinit_platform_thread()
using namespace Nova;
if (native_thread().ec_sel != Native_thread::INVALID_INDEX) {
revoke(Obj_crd(native_thread().ec_sel, 1));
cap_map()->remove(native_thread().ec_sel, 1, false);
revoke(Obj_crd(native_thread().ec_sel, 0));
cap_map()->remove(native_thread().ec_sel, 0, false);
}
/* de-announce thread */
@ -151,14 +147,6 @@ void Thread::start()
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 */
Thread_state state;
state.sel_exc_base = native_thread().exc_pt_sel;
@ -175,20 +163,20 @@ void Thread::start()
cpu_thread.start(thread_ip, _stack->top());
/* 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)
throw Cpu_session::Thread_creation_failed();
/* requested pager cap used by request_native_ec_cap in Signal_source_client */
enum { MAP_PAGER_CAP = 1 };
request_native_ec_cap(pager_cap, native_thread().ec_sel, MAP_PAGER_CAP);
/*
* Requested ec cap that is used for recall and
* 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;
/* request exception portals for normal threads */
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 */
Utcb * utcb_obj = reinterpret_cast<Utcb *>(utcb());
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
*/
Genode::Thread * myself = Genode::Thread::myself();
Genode::Native_capability pager_cap = Capability_space::import(myself->native_thread().ec_sel + 1);
request_event_portal(pager_cap, copy_session_cap.local_name(), 0, 0);
request_native_ec_cap(myself->native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT,
copy_session_cap.local_name());
/* check whether the requested cap before is valid and placed well */
crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0);

View File

@ -20,7 +20,6 @@
#include <cpu_session/connection.h>
#include <pd_session/connection.h>
#include <region_map/client.h>
#include <nova_native_cpu/client.h>
#include <cpu_thread/client.h>
/* NOVA includes */
@ -79,21 +78,15 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
state.vcpu = true;
Cpu_thread_client cpu_thread(vcpu_vm);
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
* to lookup current PD - required during PD creation.
* Translate vcpu_vm thread cap via current executing thread,
* which is used to lookup current PD to delegate VM-exit portals.
*/
translate_remote_pager(pager_cap,
Thread::myself()->native_thread().ec_sel + 1);
addr_t const current = Thread::myself()->native_thread().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);
@ -102,7 +95,11 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
* 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);
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();
@ -152,15 +149,15 @@ class Vmm::Vcpu_same_pd : public Vmm::Vcpu_thread, Genode::Thread
{
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
* 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);
addr_t const pager_pt = exc_base() + 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));
}
void entry() { }