NOVA: create sm solely in core

Any kernel objects are now created solely by core - namely pt, ec, sm and sc.
This commit is contained in:
Alexander Boettcher 2012-08-01 16:16:51 +02:00 committed by Norman Feske
parent 2f84fd0434
commit b6ea5714d7
12 changed files with 164 additions and 105 deletions

View File

@ -1,6 +1,7 @@
/*
* \brief Platform-specific type definitions
* \author Norman Feske
* \author Alexander Boettcher
* \date 2009-10-02
*/
@ -26,8 +27,6 @@ namespace Genode {
struct Native_thread
{
addr_t ec_sel; /* NOVA cap selector for execution context */
addr_t sc_sel; /* NOVA cap selector for scheduling context */
addr_t rs_sel; /* NOVA cap selector for running semaphore */
addr_t pd_sel; /* NOVA cap selector of protection domain */
addr_t exc_pt_sel; /* base of event portal window */
};
@ -36,11 +35,11 @@ namespace Genode {
inline bool operator == (Native_thread_id t1, Native_thread_id t2)
{
return (t1.ec_sel == t2.ec_sel) && (t1.rs_sel == t2.rs_sel);
}
return (t1.ec_sel == t2.ec_sel) && (t1.pd_sel == t2.pd_sel);
}
inline bool operator != (Native_thread_id t1, Native_thread_id t2)
{
return (t1.ec_sel != t2.ec_sel) && (t1.rs_sel != t2.rs_sel);
return (t1.ec_sel != t2.ec_sel) && (t1.pd_sel != t2.pd_sel);
}
class Native_utcb

View File

@ -1,6 +1,7 @@
/*
* \brief Lay back and relax
* \author Norman Feske
* \author Alexander Boettcher
* \date 2010-02-01
*/
@ -15,19 +16,23 @@
#define _INCLUDE__BASE__SLEEP_H_
/* Genode includes */
#include <base/cap_sel_alloc.h>
#include <base/thread.h>
/* NOVA includes */
#include <nova/syscalls.h>
extern int main_thread_running_semaphore();
namespace Genode {
__attribute__((noreturn)) inline void sleep_forever()
{
int sleep_sm_sel = cap_selector_allocator()->alloc();
Nova::create_sm(sleep_sm_sel, Cap_selector_allocator::pd_sel(), 0);
while (1) Nova::sm_ctrl(sleep_sm_sel, Nova::SEMAPHORE_DOWN);
using namespace Nova;
Thread_base *myself = Thread_base::myself();
addr_t sem = myself ? myself->tid().exc_pt_sel + SM_SEL_EC :
main_thread_running_semaphore();
while (1) { Nova::sm_ctrl(sem, Nova::SEMAPHORE_DOWNZERO); }
}
}

View File

@ -2,6 +2,7 @@
* \brief Syscall bindings for the NOVA microhypervisor
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2009-12-27
*/
@ -499,6 +500,9 @@ namespace Nova {
PT_SEL_PARENT = 0x1a, /* convention on Genode */
PT_SEL_STARTUP = 0x1e,
PD_SEL = 0x1b,
PD_SEL_CAP_LOCK = 0x1c, /* convention on Genode */
SM_SEL_EC_MAIN = 0x1c, /* convention on Genode */
SM_SEL_EC = 0x1d, /* convention on Genode */
};
}

View File

@ -2,6 +2,7 @@
* \brief Capability-selector allocator
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2010-01-19
*
* This is a NOVA-specific addition to the process environment.
@ -41,7 +42,7 @@ class Alloc_lock
{
private:
int _sm_cap;
addr_t _sm_cap;
public:
@ -50,10 +51,7 @@ class Alloc_lock
*
* \param sm_cap capability selector for the used semaphore
*/
Alloc_lock(int sm_cap) : _sm_cap(sm_cap)
{
Nova::create_sm(_sm_cap, __local_pd_sel, 1);
}
Alloc_lock() : _sm_cap(Nova::PD_SEL_CAP_LOCK) { }
void lock() { Nova::sm_ctrl(_sm_cap, Nova::SEMAPHORE_DOWN); }
@ -66,7 +64,7 @@ class Alloc_lock
*/
static Alloc_lock *alloc_lock()
{
static Alloc_lock alloc_lock_inst(__first_free_cap_selector);
static Alloc_lock alloc_lock_inst;
return &alloc_lock_inst;
}

View File

@ -1,6 +1,7 @@
/*
* \brief Information about the main thread
* \author Norman Feske
* \author Alexander Boettcher
* \date 2010-01-19
*/
@ -13,8 +14,6 @@
/* Genode includes */
#include <base/native_types.h>
#include <base/cap_sel_alloc.h>
#include <base/printf.h>
/* NOVA includes */
#include <nova/syscalls.h>
@ -30,14 +29,4 @@ Nova::mword_t __main_thread_utcb;
Native_utcb *main_thread_utcb() { return (Native_utcb *)__main_thread_utcb; }
int main_thread_running_semaphore()
{
static int sm;
if (!sm) {
sm = cap_selector_allocator()->alloc();
int res = Nova::create_sm(sm, Cap_selector_allocator::pd_sel(), 0);
if (res)
PERR("create_sm returned %d", res);
}
return sm;
}
addr_t main_thread_running_semaphore() { return Nova::SM_SEL_EC; }

View File

@ -1,6 +1,7 @@
/*
* \brief Helper functions for the Lock implementation
* \author Norman Feske
* \author Alexander Boettcher
* \date 2009-10-02
*
* For documentation about the interface, please revisit the 'base-pistachio'
@ -17,6 +18,7 @@
/* Genode includes */
#include <base/native_types.h>
#include <base/thread.h>
#include <base/stdint.h>
/* NOVA includes */
#include <nova/syscalls.h>
@ -32,7 +34,10 @@ extern int main_thread_running_semaphore();
* use the thread library. If the thread library is not used, 'myself' can only
* be called by the main thread, for which 'myself' is defined as zero.
*/
Genode::Thread_base * __attribute__((weak)) Genode::Thread_base::myself() { return 0; }
Genode::Thread_base * __attribute__((weak)) Genode::Thread_base::myself()
{
return 0;
}
static inline void thread_yield() { }
@ -40,8 +45,9 @@ static inline void thread_yield() { }
static bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
{
int sem = tid.rs_sel == 0 ? main_thread_running_semaphore()
: tid.rs_sel;
Genode::addr_t sem = tid.pd_sel == 0 ?
main_thread_running_semaphore() :
tid.exc_pt_sel + Nova::SM_SEL_EC;
Nova::sm_ctrl(sem, Nova::SEMAPHORE_UP);
return true;
@ -51,13 +57,13 @@ static bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
static inline Genode::Native_thread_id thread_get_my_native_id()
{
/*
* We encode the main thread as tid { 0, 0, 0 } because we cannot
* We encode the main thread as tid { 0, 0 } because we cannot
* call 'main_thread_running_semaphore()' here.
*/
Genode::Thread_base *myself = Genode::Thread_base::myself();
if (myself == 0) {
Genode::Native_thread_id main_tid = { 0, 0, 0 };
Genode::Native_thread_id main_tid = { 0, 0 };
return main_tid;
} else
return myself->tid();
@ -66,14 +72,14 @@ static inline Genode::Native_thread_id thread_get_my_native_id()
static inline Genode::Native_thread_id thread_invalid_id()
{
Genode::Native_thread_id tid = { 0, 0, ~0UL };
Genode::Native_thread_id tid = { 0, ~0UL };
return tid;
}
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return tid.rs_sel != ~0UL;
return tid.pd_sel != ~0UL;
}
@ -82,7 +88,15 @@ static inline void thread_switch_to(Genode::Native_thread_id tid) { }
static inline void thread_stop_myself()
{
Genode::Thread_base *myself = Genode::Thread_base::myself();
int sem = myself ? myself->tid().rs_sel : main_thread_running_semaphore();
Nova::sm_ctrl(sem, Nova::SEMAPHORE_DOWNZERO);
using namespace Genode;
using namespace Nova;
addr_t sem;
Thread_base *myself = Thread_base::myself();
if (myself)
sem = myself->tid().exc_pt_sel + SM_SEL_EC;
else
sem = main_thread_running_semaphore();
sm_ctrl(sem, SEMAPHORE_DOWNZERO);
}

View File

@ -2,6 +2,7 @@
* \brief Pager framework
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2010-01-25
*/
@ -61,9 +62,6 @@ void Pager_object::_startup_handler()
Pager_object *obj = static_cast<Pager_object *>(Thread_base::myself());
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
// printf("start new pager object with EIP=0x%p, ESP=0x%p\n",
// (void *)obj->_initial_eip, (void *)obj->_initial_esp);
utcb->eip = obj->_initial_eip;
utcb->esp = obj->_initial_esp;
utcb->mtd = Mtd::EIP | Mtd::ESP;
@ -78,14 +76,21 @@ void Pager_object::_invoke_handler()
Pager_object *obj = static_cast<Pager_object *>(Thread_base::myself());
/* send single portal as reply */
addr_t event = utcb->msg[0];
addr_t event = utcb->msg_words() != 1 ? 0 : utcb->msg[0];
utcb->mtd = 0;
utcb->set_msg_word(0);
if (event == PT_SEL_STARTUP || event == PT_SEL_PAGE_FAULT) {
if (event == PT_SEL_STARTUP || event == PT_SEL_PAGE_FAULT ||
event == SM_SEL_EC) {
/**
* Caller is requesting the SM cap of main thread
* this object is paging - it is stored at SM_SEL_EC_MAIN
*/
if (event == SM_SEL_EC) event = SM_SEL_EC_MAIN;
bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel() + event,
0), 0);
/* one item ever fits on the UTCB */
/* one item ever fits on the UTCB */
(void)res;
}
@ -127,7 +132,7 @@ Pager_object::Pager_object(unsigned long badge)
reinterpret_cast<addr_t>(_invoke_handler));
if (res)
PERR("could not create pager cleanup portal, error = %u\n",
res);
res);
}
Pager_object::~Pager_object()

View File

@ -2,6 +2,7 @@
* \brief NOVA-specific support code for the server-side RPC API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2010-01-13
*/
@ -92,6 +93,7 @@ void Rpc_entrypoint::_activation_entry()
#else
addr_t id_pt; asm volatile ("" : "=a" (id_pt));
#endif
/* retrieve portal id from eax */
Rpc_entrypoint *ep = static_cast<Rpc_entrypoint *>(Thread_base::myself());
@ -217,6 +219,8 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
Nova::PT_SEL_STARTUP);
request_event_portal(pager_cap, _tid.exc_pt_sel,
Nova::PT_SEL_PAGE_FAULT);
request_event_portal(pager_cap, _tid.exc_pt_sel,
Nova::SM_SEL_EC);
/**
* Request native thread cap, _thread_cap only a token.

View File

@ -2,6 +2,7 @@
* \brief NOVA-specific implementation of the Thread API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2010-01-19
*/
@ -53,7 +54,6 @@ void Thread_base::_init_platform_thread()
* running semaphore and exception handler portals.
*/
_tid.ec_sel = ~0UL;
_tid.rs_sel = cap_selector_allocator()->alloc();
_tid.pd_sel = cap_selector_allocator()->pd_sel();
_tid.exc_pt_sel = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
@ -66,33 +66,29 @@ void Thread_base::_init_platform_thread()
env()->pd_session()->bind_thread(_thread_cap);
/* create new pager object and assign it to the new thread */
Pager_capability pager_cap = env()->rm_session()->add_client(_thread_cap);
Pager_capability pager_cap =
env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, pager_cap);
/* create running semaphore required for locking */
uint8_t res = create_sm(_tid.rs_sel, _tid.pd_sel, 0);
if (res != NOVA_OK) {
PERR("create_sm returned %u", res);
throw Cpu_session::Thread_creation_failed();
}
}
void Thread_base::_deinit_platform_thread()
{
// Nova::revoke(Nova::Obj_crd(_tid.ec_sel, 0));
Nova::revoke(Nova::Obj_crd(_tid.rs_sel, 0));
Nova::revoke(Nova::Obj_crd(_tid.exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2));
using namespace Nova;
// cap_selector_allocator()->free(_tid.ec_sel, 0);
cap_selector_allocator()->free(_tid.rs_sel, 0);
cap_selector_allocator()->free(_tid.exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2);
if (_tid.ec_sel != ~0UL) {
revoke(Obj_crd(_tid.ec_sel, 0));
cap_selector_allocator()->free(_tid.ec_sel, 0);
}
revoke(Obj_crd(_tid.exc_pt_sel, NUM_INITIAL_PT_LOG2));
cap_selector_allocator()->free(_tid.exc_pt_sel, NUM_INITIAL_PT_LOG2);
/* revoke utcb */
Nova::Rights rwx(true, true, true);
Rights rwx(true, true, true);
addr_t utcb = reinterpret_cast<addr_t>(&_context->utcb);
Nova::revoke(Nova::Mem_crd(utcb >> 12, 0, rwx));
revoke(Mem_crd(utcb >> 12, 0, rwx));
/* de-announce thread */
env()->cpu_session()->kill_thread(_thread_cap);
@ -131,6 +127,7 @@ void Thread_base::start()
/* request exception portals */
request_event_portal(pager_cap, _tid.exc_pt_sel, PT_SEL_STARTUP);
request_event_portal(pager_cap, _tid.exc_pt_sel, PT_SEL_PAGE_FAULT);
request_event_portal(pager_cap, _tid.exc_pt_sel, SM_SEL_EC);
/* request creation of SC to let thread run*/
env()->cpu_session()->resume(_thread_cap);
@ -139,5 +136,5 @@ void Thread_base::start()
void Thread_base::cancel_blocking()
{
Nova::sm_ctrl(_tid.rs_sel, Nova::SEMAPHORE_UP);
Nova::sm_ctrl(_tid.exc_pt_sel + Nova::SM_SEL_EC, Nova::SEMAPHORE_UP);
}

View File

@ -2,6 +2,7 @@
* \brief Platform interface implementation
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2009-10-02
*/
@ -16,6 +17,7 @@
#include <base/printf.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <base/cap_sel_alloc.h>
/* core includes */
#include <core_parent.h>
@ -140,7 +142,7 @@ static void page_fault_handler()
static void init_core_page_fault_handler()
{
/* create echo EC */
enum {
enum {
STACK_SIZE = 4*1024,
CPU_NO = 0,
GLOBAL = false,
@ -185,6 +187,10 @@ Platform::Platform() :
/* set core pd selector */
__local_pd_sel = hip->sel_exc;
/* create lock used by capability allocator */
Nova::create_sm(Nova::PD_SEL_CAP_LOCK, __local_pd_sel, 1);
Nova::create_sm(Nova::SM_SEL_EC, __local_pd_sel, 0);
/* locally map the whole I/O port range */
enum { ORDER_64K = 16 };
map_local_one_to_one(__main_thread_utcb, Io_crd(0, ORDER_64K));

View File

@ -2,6 +2,7 @@
* \brief Thread facility
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2009-10-02
*/
@ -65,15 +66,30 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base)
return -3;
}
/**
* Create semaphore required for Genode locking.
* It is created at the root pager exception base +
* SM_SEL_EC_MAIN and can be later on requested by the thread
* the same way as STARTUP and PAGEFAULT portal.
*/
uint8_t res = Nova::create_sm(_pager->exc_pt_sel() +
SM_SEL_EC_MAIN,
_pd->pd_sel(), 0);
if (res != Nova::NOVA_OK) {
PERR("creation of semaphore for new thread failed %u",
res);
return -4;
}
/* ip == 0 means that caller will use the thread as worker */
bool thread_global = ip;
uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), _cpu_no,
utcb, initial_sp,
exc_base, thread_global);
res = create_ec(_sel_ec(), _pd->pd_sel(), _cpu_no, utcb,
initial_sp, exc_base, thread_global);
if (res)
PERR("creation of new thread failed %u", res);
return res ? -4 : 0;
return res ? -5 : 0;
}
/*
@ -82,51 +98,75 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base)
*/
_pager->initial_esp(PD_UTCB + get_page_size());
/* locally map parent portal to initial portal window */
int res = map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
Obj_crd(_pd->parent_pt_sel(), 0),
Obj_crd(_pager->exc_pt_sel() + PT_SEL_PARENT, 0));
if (res) {
PERR("could not locally remap parent portal");
return -5;
addr_t pd_sel = cap_selector_allocator()->pd_sel();
addr_t exc_base_sel = cap_selector_allocator()->alloc(Nova::NUM_INITIAL_PT_LOG2);
addr_t sm_alloc_sel = exc_base_sel + PD_SEL_CAP_LOCK;
addr_t sm_ec_sel = exc_base_sel + SM_SEL_EC;
addr_t remap_src[] = { _pager->exc_pt_sel() + PT_SEL_PAGE_FAULT,
_pd->parent_pt_sel(),
_pager->exc_pt_sel() + PT_SEL_STARTUP };
addr_t remap_dst[] = { PT_SEL_PAGE_FAULT,
PT_SEL_PARENT,
PT_SEL_STARTUP };
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
/* locally map portals to initial portal window */
if (map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
Obj_crd(remap_src[i], 0),
Obj_crd(exc_base_sel + remap_dst[i], 0))) {
PERR("could not remap portal %lx->%lx",
remap_src[i], remap_dst[i]);
return -6;
}
}
Obj_crd initial_pts(_pager->exc_pt_sel(), Nova::NUM_INITIAL_PT_LOG2,
1 << 4);
/* Create lock for cap allocator selector */
uint8_t res = Nova::create_sm(sm_alloc_sel, pd_sel, 1);
if (res != Nova::NOVA_OK) {
PERR("could not create semaphore for capability allocator");
return -7;
}
/* Create lock for EC used by lock_helper */
res = Nova::create_sm(sm_ec_sel, pd_sel, 0);
if (res != Nova::NOVA_OK) {
PERR("could not create semaphore for new thread");
return -8;
}
addr_t pd_sel = cap_selector_allocator()->pd_sel();
addr_t pd0_sel = _pager->exc_pt_sel() + Nova::PD_SEL;
/* Create task */
addr_t pd0_sel = cap_selector_allocator()->alloc();
_pd->assign_pd(pd0_sel);
Obj_crd initial_pts(exc_base_sel, Nova::NUM_INITIAL_PT_LOG2);
res = create_pd(pd0_sel, pd_sel, initial_pts);
if (res) {
PERR("create_pd returned %d", res);
return -6;
return -9;
}
/* Create first thread in task */
enum { THREAD_GLOBAL = true };
res = create_ec(_sel_ec(), pd0_sel, _cpu_no, PD_UTCB, 0, 0,
THREAD_GLOBAL);
if (res) {
PERR("create_ec returned %d", res);
return -7;
return -10;
}
/* Let the thread run */
res = create_sc(_sel_sc(), pd0_sel, _sel_ec(), Qpd());
if (res) {
PERR("create_sc returned %d", res);
return -8;
return -11;
}
return 0;
}
void Platform_thread::pause()
{
PDBG("not implemented");
}
void Platform_thread::pause() { PDBG("not implemented"); }
void Platform_thread::resume()
@ -148,16 +188,11 @@ int Platform_thread::state(Thread_state *state_dst)
void Platform_thread::cancel_blocking() { PWRN("not implemented"); }
unsigned long Platform_thread::pager_object_badge()
const
{
return ~0UL;
}
unsigned long Platform_thread::pager_object_badge() const { return ~0UL; }
Platform_thread::Platform_thread(const char *name, unsigned, int thread_id)
: _pd(0), _id_base(cap_selector_allocator()->alloc(1)),
_cpu_no(0) { }
: _pd(0), _id_base(cap_selector_allocator()->alloc(1)), _cpu_no(0) { }
Platform_thread::~Platform_thread()

View File

@ -2,6 +2,7 @@
* \brief NOVA-specific implementation of the Thread API for core
* \author Norman Feske
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2010-01-19
*/
@ -42,22 +43,23 @@ void Thread_base::_init_platform_thread()
addr_t pd_sel = Platform_pd::pd_core_sel();
/* create running semaphore required for locking */
uint8_t res = Nova::create_sm(_tid.rs_sel, _tid.pd_sel, 0);
if (res)
addr_t rs_sel =_tid.exc_pt_sel + SM_SEL_EC;
uint8_t res = create_sm(rs_sel, _tid.pd_sel, 0);
if (res != NOVA_OK) {
PERR("create_sm returned %u", res);
throw Cpu_session::Thread_creation_failed();
}
addr_t sp = reinterpret_cast<addr_t>(&_context->stack[-4]);
addr_t utcb = reinterpret_cast<addr_t>(&_context->utcb);
/* create local EC */
enum { CPU_NO = 0, GLOBAL = false };
res = Nova::create_ec(_tid.ec_sel, Cap_selector_allocator::pd_sel(),
CPU_NO, utcb, sp,
_tid.exc_pt_sel, GLOBAL);
if (res) {
res = create_ec(_tid.ec_sel, Cap_selector_allocator::pd_sel(), CPU_NO,
utcb, sp, _tid.exc_pt_sel, GLOBAL);
if (res != NOVA_OK) {
PERR("%p - create_ec returned %d", this, res);
PERR("valid thread %x %lx:%lx", _thread_cap.valid(),
_thread_cap.dst()._sel, _thread_cap.local_name());
throw Cpu_session::Thread_creation_failed();
}
}
@ -65,12 +67,11 @@ void Thread_base::_init_platform_thread()
void Thread_base::_deinit_platform_thread()
{
unmap_local(Nova::Obj_crd(_tid.ec_sel, 0));
unmap_local(Nova::Obj_crd(_tid.rs_sel, 0));
unmap_local(Nova::Obj_crd(_tid.exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2));
cap_selector_allocator()->free(_tid.ec_sel, 0);
cap_selector_allocator()->free(_tid.rs_sel, 0);
cap_selector_allocator()->free(_tid.exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2);
cap_selector_allocator()->free(_tid.exc_pt_sel,
Nova::NUM_INITIAL_PT_LOG2);
/* revoke utcb */
Nova::Rights rwx(true, true, true);
@ -88,5 +89,7 @@ void Thread_base::start()
void Thread_base::cancel_blocking()
{
Nova::sm_ctrl(_tid.rs_sel, Nova::SEMAPHORE_UP);
using namespace Nova;
sm_ctrl(_tid.exc_pt_sel + SM_SEL_EC, SEMAPHORE_UP);
}