mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
nova: create sm of each thread in pager
Mainly simplification of the code and getting rid of reserved (Genode) special cap selectors in the syscall-generic.h file. Issue #478
This commit is contained in:
parent
a903049a1a
commit
c426bac8bb
@ -49,13 +49,9 @@ namespace Genode {
|
||||
*/
|
||||
addr_t _pt_cleanup;
|
||||
|
||||
/**
|
||||
* Semaphore selector to synchronize pause/state/resume operations
|
||||
*/
|
||||
addr_t _sm_state_notify;
|
||||
|
||||
addr_t _initial_esp;
|
||||
addr_t _initial_eip;
|
||||
addr_t _client_exc_pt_sel;
|
||||
|
||||
struct
|
||||
{
|
||||
@ -70,6 +66,11 @@ namespace Genode {
|
||||
|
||||
void _copy_state(Nova::Utcb * utcb);
|
||||
|
||||
/**
|
||||
* Semaphore selector to synchronize pause/state/resume operations
|
||||
*/
|
||||
addr_t sm_state_notify() { return _pt_cleanup + 1; }
|
||||
|
||||
static void _page_fault_handler();
|
||||
static void _startup_handler();
|
||||
static void _invoke_handler();
|
||||
@ -79,6 +80,7 @@ namespace Genode {
|
||||
static void _exception_handler(addr_t portal_id);
|
||||
|
||||
static Nova::Utcb * _check_handler(Thread_base *&, Pager_object *&);
|
||||
|
||||
public:
|
||||
|
||||
Pager_object(unsigned long badge, Affinity::Location location);
|
||||
@ -106,6 +108,7 @@ namespace Genode {
|
||||
* Return base of initial portal window
|
||||
*/
|
||||
addr_t exc_pt_sel() { return _tid.exc_pt_sel; }
|
||||
addr_t exc_pt_sel_client() { return _client_exc_pt_sel; }
|
||||
|
||||
/**
|
||||
* Set initial stack pointer used by the startup handler
|
||||
@ -154,7 +157,7 @@ namespace Genode {
|
||||
if (_state.dead)
|
||||
return Native_capability::invalid_cap();
|
||||
|
||||
return Native_capability(_sm_state_notify);
|
||||
return Native_capability(sm_state_notify());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -560,8 +560,6 @@ namespace Nova {
|
||||
PT_SEL_PARENT = 0x1a, /* convention on Genode */
|
||||
PT_SEL_STARTUP = 0x1e,
|
||||
PT_SEL_RECALL = 0x1f,
|
||||
PD_SEL = 0x1b,
|
||||
SM_SEL_EC_CLIENT = 0x1c, /* convention on Genode */
|
||||
SM_SEL_EC = 0x1d, /* convention on Genode */
|
||||
};
|
||||
|
||||
|
@ -74,7 +74,7 @@ void Pager_object::_page_fault_handler()
|
||||
Native_capability pager_obj = obj->Object_pool<Pager_object>::Entry::cap();
|
||||
revoke(pager_obj.dst(), true);
|
||||
|
||||
revoke(Obj_crd(obj->exc_pt_sel(), NUM_INITIAL_PT_LOG2), false);
|
||||
revoke(Obj_crd(obj->exc_pt_sel_client(), NUM_INITIAL_PT_LOG2), false);
|
||||
|
||||
obj->_state.dead = true;
|
||||
}
|
||||
@ -143,7 +143,7 @@ void Pager_object::_recall_handler()
|
||||
|
||||
obj->_state.valid = true;
|
||||
|
||||
if (sm_ctrl(obj->_sm_state_notify, SEMAPHORE_UP) != NOVA_OK)
|
||||
if (sm_ctrl(obj->sm_state_notify(), SEMAPHORE_UP) != NOVA_OK)
|
||||
PWRN("notify failed");
|
||||
|
||||
if (sm_ctrl(obj->exc_pt_sel() + SM_SEL_EC, SEMAPHORE_DOWNZERO) != NOVA_OK)
|
||||
@ -197,14 +197,7 @@ void Pager_object::_invoke_handler()
|
||||
if (event < PT_SEL_PARENT || event == PT_SEL_STARTUP ||
|
||||
event == SM_SEL_EC || event == PT_SEL_RECALL) {
|
||||
|
||||
/*
|
||||
* Caller is requesting the SM cap of thread
|
||||
* this object is paging - it is stored at SM_SEL_EC_CLIENT
|
||||
*/
|
||||
if (event == SM_SEL_EC) event = SM_SEL_EC_CLIENT;
|
||||
|
||||
bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel() + event,
|
||||
0), 0);
|
||||
bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel_client() + event, 0), 0);
|
||||
/* one item ever fits on the UTCB */
|
||||
(void)res;
|
||||
}
|
||||
@ -218,7 +211,7 @@ void Pager_object::wake_up() { cancel_blocking(); }
|
||||
|
||||
void Pager_object::client_cancel_blocking()
|
||||
{
|
||||
uint8_t res = sm_ctrl(exc_pt_sel() + SM_SEL_EC_CLIENT, SEMAPHORE_UP);
|
||||
uint8_t res = sm_ctrl(exc_pt_sel_client() + SM_SEL_EC, SEMAPHORE_UP);
|
||||
if (res != NOVA_OK)
|
||||
PWRN("cancel blocking failed");
|
||||
}
|
||||
@ -232,11 +225,8 @@ uint8_t Pager_object::client_recall()
|
||||
|
||||
void Pager_object::cleanup_call()
|
||||
{
|
||||
/*
|
||||
* Revoke all portals of Pager_object from others.
|
||||
* The portals will be finally revoked during thread destruction.
|
||||
*/
|
||||
revoke(Obj_crd(exc_pt_sel(), NUM_INITIAL_PT_LOG2), false);
|
||||
/* revoke all portals handling the client. */
|
||||
revoke(Obj_crd(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2));
|
||||
|
||||
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
|
||||
if (reinterpret_cast<Utcb *>(this->utcb()) == utcb) return;
|
||||
@ -262,7 +252,8 @@ 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)
|
||||
: Thread_base("pager:", PF_HANDLER_STACK_SIZE), _badge(badge)
|
||||
: Thread_base("pager:", PF_HANDLER_STACK_SIZE),
|
||||
_badge(reinterpret_cast<unsigned long>(_context->name + 6))
|
||||
{
|
||||
class Create_exception_pt_failed { };
|
||||
uint8_t res;
|
||||
@ -272,13 +263,17 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
|
||||
sizeof(_context->name) - 6);
|
||||
|
||||
addr_t pd_sel = __core_pd_sel;
|
||||
_pt_cleanup = cap_selector_allocator()->alloc();
|
||||
_sm_state_notify = cap_selector_allocator()->alloc();
|
||||
_pt_cleanup = cap_selector_allocator()->alloc(1);
|
||||
_client_exc_pt_sel = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
|
||||
_state.valid = false;
|
||||
_state.dead = false;
|
||||
_state.singlestep = false;
|
||||
_state.sel_client_ec = Native_thread::INVALID_INDEX;
|
||||
|
||||
if (_pt_cleanup == Native_thread::INVALID_INDEX ||
|
||||
_client_exc_pt_sel == Native_thread::INVALID_INDEX)
|
||||
throw Create_exception_pt_failed();
|
||||
|
||||
/* tell thread starting code on which CPU to let run the pager */
|
||||
reinterpret_cast<Affinity::Location *>(stack_top())[-1] = location;
|
||||
|
||||
@ -287,20 +282,16 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
|
||||
|
||||
/* create portal for exception handlers 0x0 - 0xd */
|
||||
for (unsigned i = 0; i < PT_SEL_PAGE_FAULT; i++) {
|
||||
res = create_portal(exc_pt_sel() + i, pd_sel, _tid.ec_sel, Mtd(0),
|
||||
(addr_t)_exception_handler);
|
||||
res = create_portal(exc_pt_sel_client() + i, pd_sel, _tid.ec_sel,
|
||||
Mtd(Mtd::EIP), (addr_t)_exception_handler);
|
||||
if (res) {
|
||||
PERR("could not create exception portal, error = %u\n", res);
|
||||
throw Create_exception_pt_failed();
|
||||
}
|
||||
}
|
||||
|
||||
/* threads in core get default page fault handler assigned, revoke it */
|
||||
if (_tid.ec_sel != Native_thread::INVALID_INDEX)
|
||||
revoke(Obj_crd(exc_pt_sel() + PT_SEL_PAGE_FAULT, 0));
|
||||
|
||||
/* create portal for page-fault handler */
|
||||
res = create_portal(exc_pt_sel() + PT_SEL_PAGE_FAULT, pd_sel, _tid.ec_sel,
|
||||
res = create_portal(exc_pt_sel_client() + PT_SEL_PAGE_FAULT, pd_sel, _tid.ec_sel,
|
||||
Mtd(Mtd::QUAL | Mtd::EIP), (mword_t)_page_fault_handler);
|
||||
if (res) {
|
||||
PERR("could not create page-fault portal, error = %u\n", res);
|
||||
@ -310,8 +301,8 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
|
||||
|
||||
/* create portal for exception handlers 0xf - 0x19 */
|
||||
for (unsigned i = PT_SEL_PAGE_FAULT + 1; i < PT_SEL_PARENT; i++) {
|
||||
res = create_portal(exc_pt_sel() + i, pd_sel, _tid.ec_sel, Mtd(0),
|
||||
(addr_t)_exception_handler);
|
||||
res = create_portal(exc_pt_sel_client() + i, pd_sel, _tid.ec_sel,
|
||||
Mtd(Mtd::EIP), (addr_t)_exception_handler);
|
||||
if (res) {
|
||||
PERR("could not create exception portal, error = %u\n", res);
|
||||
throw Create_exception_pt_failed();
|
||||
@ -319,7 +310,7 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
|
||||
}
|
||||
|
||||
/* create portal for startup handler */
|
||||
res = create_portal(exc_pt_sel() + PT_SEL_STARTUP, pd_sel, _tid.ec_sel,
|
||||
res = create_portal(exc_pt_sel_client() + PT_SEL_STARTUP, pd_sel, _tid.ec_sel,
|
||||
Mtd(Mtd::ESP | Mtd::EIP), (mword_t)_startup_handler);
|
||||
if (res) {
|
||||
PERR("could not create startup portal, error = %u\n",
|
||||
@ -330,7 +321,7 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
|
||||
|
||||
/* create portal for recall handler */
|
||||
Mtd mtd(Mtd::ESP | Mtd::EIP | Mtd::ACDB | Mtd::EFL | Mtd::EBSD | Mtd::FSGS);
|
||||
res = create_portal(exc_pt_sel() + PT_SEL_RECALL, pd_sel, _tid.ec_sel,
|
||||
res = create_portal(exc_pt_sel_client() + PT_SEL_RECALL, pd_sel, _tid.ec_sel,
|
||||
mtd, (addr_t)_recall_handler);
|
||||
if (res) {
|
||||
PERR("could not create recall portal, error = %u\n", res);
|
||||
@ -338,6 +329,16 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
|
||||
throw Create_recall_pt_failed();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create semaphore required for Genode locking. It can be later on
|
||||
* requested by the thread the same way as all exception portals.
|
||||
*/
|
||||
res = Nova::create_sm(exc_pt_sel_client() + SM_SEL_EC, pd_sel, 0);
|
||||
if (res != Nova::NOVA_OK) {
|
||||
class Create_state_notifiy_sm_failed { };
|
||||
throw Create_state_notifiy_sm_failed();
|
||||
}
|
||||
|
||||
/* create portal for final cleanup call used during destruction */
|
||||
res = create_portal(_pt_cleanup, pd_sel, _tid.ec_sel, Mtd(0),
|
||||
reinterpret_cast<addr_t>(_invoke_handler));
|
||||
@ -347,7 +348,7 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
|
||||
throw Create_cleanup_pt_failed();
|
||||
}
|
||||
|
||||
res = Nova::create_sm(_sm_state_notify, pd_sel, 0);
|
||||
res = Nova::create_sm(sm_state_notify(), pd_sel, 0);
|
||||
if (res != Nova::NOVA_OK) {
|
||||
class Create_state_notifiy_sm_failed { };
|
||||
throw Create_state_notifiy_sm_failed();
|
||||
@ -357,13 +358,9 @@ Pager_object::Pager_object(unsigned long badge, Affinity::Location location)
|
||||
|
||||
Pager_object::~Pager_object()
|
||||
{
|
||||
/* revoke semaphore cap to signal valid state after recall */
|
||||
addr_t sm_cap = _sm_state_notify;
|
||||
_sm_state_notify = Native_thread::INVALID_INDEX;
|
||||
|
||||
/* if pager is blocked wake him up */
|
||||
sm_ctrl(sm_cap, SEMAPHORE_UP);
|
||||
revoke(Obj_crd(sm_cap, 0));
|
||||
sm_ctrl(sm_state_notify(), SEMAPHORE_UP);
|
||||
revoke(Obj_crd(sm_state_notify(), 0));
|
||||
|
||||
/* take care nobody is handled anymore by this object */
|
||||
cleanup_call();
|
||||
@ -372,9 +369,9 @@ Pager_object::~Pager_object()
|
||||
revoke(Obj_crd(_pt_cleanup, 0));
|
||||
|
||||
Native_capability pager_obj = ::Object_pool<Pager_object>::Entry::cap();
|
||||
cap_selector_allocator()->free(_pt_cleanup, 0);
|
||||
cap_selector_allocator()->free(sm_cap, 0);
|
||||
cap_selector_allocator()->free(_pt_cleanup, 1);
|
||||
cap_selector_allocator()->free(pager_obj.local_name(), 0);
|
||||
cap_selector_allocator()->free(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2);
|
||||
}
|
||||
|
||||
|
||||
|
@ -75,8 +75,10 @@ void Thread_base::_init_platform_thread()
|
||||
* Allocate capability selectors for the thread's execution context,
|
||||
* running semaphore and exception handler portals.
|
||||
*/
|
||||
_tid.ec_sel = ~0UL;
|
||||
_tid.ec_sel = Native_thread::INVALID_INDEX;
|
||||
_tid.exc_pt_sel = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
|
||||
if (_tid.exc_pt_sel == Native_thread::INVALID_INDEX)
|
||||
throw Cpu_session::Thread_creation_failed();
|
||||
|
||||
/* create thread at core */
|
||||
char buf[48];
|
||||
|
@ -72,28 +72,14 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
return -3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create semaphore required for Genode locking.
|
||||
* It is created at the root pager exception base +
|
||||
* SM_SEL_EC_CLIENT and can be later on requested by the thread
|
||||
* the same way as STARTUP and PAGEFAULT portal.
|
||||
*/
|
||||
addr_t sm = _pager->exc_pt_sel() + SM_SEL_EC_CLIENT;
|
||||
uint8_t res = Nova::create_sm(sm, _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;
|
||||
|
||||
res = create_ec(_sel_ec(), _pd->pd_sel(), _location.xpos(), utcb,
|
||||
initial_sp, _sel_exc_base, thread_global);
|
||||
uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), _location.xpos(),
|
||||
utcb, initial_sp, _sel_exc_base, thread_global);
|
||||
if (res != Nova::NOVA_OK) {
|
||||
revoke(Obj_crd(sm, 0));
|
||||
PERR("creation of new thread failed %u", res);
|
||||
return -5;
|
||||
return -4;
|
||||
}
|
||||
|
||||
_pager->initial_eip((addr_t)ip);
|
||||
@ -105,7 +91,7 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
|
||||
if (_sel_exc_base != Native_thread::INVALID_INDEX) {
|
||||
PERR("thread already started");
|
||||
return -6;
|
||||
return -5;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -116,59 +102,24 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
Native_config::context_area_virtual_size() -
|
||||
get_page_size();
|
||||
|
||||
_sel_exc_base = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2);
|
||||
_sel_exc_base = _pager->exc_pt_sel_client();
|
||||
|
||||
addr_t pd_core_sel = Platform_pd::pd_core_sel();
|
||||
addr_t sm_ec_sel = _pager->exc_pt_sel() + SM_SEL_EC_CLIENT;
|
||||
|
||||
addr_t remap_src[] = { _pd->parent_pt_sel(),
|
||||
_pager->exc_pt_sel() + PT_SEL_STARTUP,
|
||||
_pager->exc_pt_sel() + PT_SEL_RECALL,
|
||||
sm_ec_sel };
|
||||
addr_t remap_dst[] = { PT_SEL_PARENT,
|
||||
PT_SEL_STARTUP,
|
||||
PT_SEL_RECALL,
|
||||
SM_SEL_EC };
|
||||
addr_t remap_src[] = { _pd->parent_pt_sel() };
|
||||
addr_t remap_dst[] = { PT_SEL_PARENT };
|
||||
addr_t pd_sel;
|
||||
|
||||
Obj_crd initial_pts(_sel_exc_base, NUM_INITIAL_PT_LOG2);
|
||||
|
||||
uint8_t res;
|
||||
|
||||
/* create lock for EC used by lock_helper */
|
||||
res = create_sm(sm_ec_sel, pd_core_sel, 0);
|
||||
if (res != NOVA_OK) {
|
||||
PERR("could not create semaphore for new thread");
|
||||
goto cleanup_base;
|
||||
}
|
||||
|
||||
/* remap exception portals for first thread */
|
||||
if (map_local((Utcb *)Thread_base::myself()->utcb(),
|
||||
Obj_crd(_pager->exc_pt_sel(), 4),
|
||||
Obj_crd(_sel_exc_base, 4)))
|
||||
goto cleanup_base;
|
||||
|
||||
if (map_local((Utcb *)Thread_base::myself()->utcb(),
|
||||
Obj_crd(_pager->exc_pt_sel() + 0x10, 3),
|
||||
Obj_crd(_sel_exc_base + 0x10, 3)))
|
||||
goto cleanup_base;
|
||||
|
||||
if (map_local((Utcb *)Thread_base::myself()->utcb(),
|
||||
Obj_crd(_pager->exc_pt_sel() + 0x18, 1),
|
||||
Obj_crd(_sel_exc_base + 0x18, 1)))
|
||||
goto cleanup_base;
|
||||
|
||||
if (PT_SEL_PARENT != 0x1a) {
|
||||
PERR("PT_SEL_PARENT changed !! Adjust remap code !!");
|
||||
goto cleanup_base;
|
||||
}
|
||||
|
||||
/* remap Genode specific, RECALL and STARTUP portals for first thread */
|
||||
for (unsigned i = 0; i < sizeof(remap_dst)/sizeof(remap_dst[0]); i++) {
|
||||
if (map_local((Utcb *)Thread_base::myself()->utcb(),
|
||||
Obj_crd(remap_src[i], 0),
|
||||
Obj_crd(_sel_exc_base + remap_dst[i], 0)))
|
||||
goto cleanup_base;
|
||||
return -6;
|
||||
}
|
||||
|
||||
pd_sel = cap_selector_allocator()->alloc();
|
||||
@ -224,12 +175,6 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
revoke(Obj_crd(pd_sel, 0));
|
||||
cap_selector_allocator()->free(pd_sel, 0);
|
||||
|
||||
cleanup_base:
|
||||
revoke(Obj_crd(sm_ec_sel, 0));
|
||||
revoke(Obj_crd(_sel_exc_base, NUM_INITIAL_PT_LOG2));
|
||||
cap_selector_allocator()->free(_sel_exc_base, NUM_INITIAL_PT_LOG2);
|
||||
_sel_exc_base = Native_thread::INVALID_INDEX;
|
||||
|
||||
return -7;
|
||||
}
|
||||
|
||||
@ -340,11 +285,4 @@ Platform_thread::~Platform_thread()
|
||||
/* free ec and sc caps */
|
||||
revoke(Obj_crd(_id_base, 1));
|
||||
cap_selector_allocator()->free(_id_base, 1);
|
||||
|
||||
/* free exc_base used by main thread */
|
||||
if (_is_main_thread && _sel_exc_base != Native_thread::INVALID_INDEX) {
|
||||
revoke(Obj_crd(_sel_exc_base, NUM_INITIAL_PT_LOG2));
|
||||
cap_selector_allocator()->free(_sel_exc_base,
|
||||
NUM_INITIAL_PT_LOG2);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user