NOVA: implement pause using recall kernel feature

This commit is contained in:
Alexander Boettcher 2012-08-24 10:25:24 +02:00 committed by Norman Feske
parent 841a1fd579
commit 197a48a26c
13 changed files with 318 additions and 60 deletions

View File

@ -44,14 +44,31 @@ namespace Genode {
*/ */
Signal_context_capability _exception_sigh; Signal_context_capability _exception_sigh;
addr_t _pt_cleanup; /* portal selector for object cleanup/destruction */ /**
* Portal selector for object cleanup/destruction
*/
addr_t _pt_cleanup;
/**
* Semaphore selector to synchronize pause/state/resume operations
*/
addr_t _sm_state_notify;
addr_t _initial_esp; addr_t _initial_esp;
addr_t _initial_eip; addr_t _initial_eip;
struct {
struct Thread_state thread;
bool valid;
bool dead;
} _state;
void _copy_state(Nova::Utcb * utcb);
static void _page_fault_handler(); static void _page_fault_handler();
static void _startup_handler(); static void _startup_handler();
static void _invoke_handler(); static void _invoke_handler();
static void _recall_handler();
public: public:
@ -99,12 +116,14 @@ namespace Genode {
/** /**
* Notify exception handler about the occurrence of an exception * Notify exception handler about the occurrence of an exception
*/ */
void submit_exception_signal() bool submit_exception_signal()
{ {
if (!_exception_sigh.valid()) return; if (!_exception_sigh.valid()) return false;
Signal_transmitter transmitter(_exception_sigh); Signal_transmitter transmitter(_exception_sigh);
transmitter.submit(); transmitter.submit();
return true;
} }
/** /**
@ -112,8 +131,40 @@ namespace Genode {
*/ */
addr_t handler_address() addr_t handler_address()
{ {
return reinterpret_cast<addr_t>(_invoke_handler); return reinterpret_cast<addr_t>(_invoke_handler);
} }
/**
* Return semaphore to block on until state of a recall is
* available.
*/
Native_capability notify_sm()
{
if (_state.valid)
return Native_capability::invalid_cap();
if (_state.dead)
return Native_capability::invalid_cap();
return Native_capability(_sm_state_notify);
}
/**
* Copy thread state of recalled thread.
*/
int copy_thread_state(Thread_state * state_dst)
{
if (!state_dst || !_state.valid) return -1;
*state_dst = _state.thread;
return 0;
}
/**
* Cancel blocking in a lock so that recall exception can take
* place.
*/
void cancel_blocking_client();
}; };

View File

@ -172,9 +172,12 @@ namespace Nova {
enum { enum {
ACDB = 1 << 0, /* eax, ecx, edx, ebx */ ACDB = 1 << 0, /* eax, ecx, edx, ebx */
EBSD = 1 << 1, /* ebp, esi, edi */
ESP = 1 << 2, ESP = 1 << 2,
EIP = 1 << 3, EIP = 1 << 3,
EFL = 1 << 4, /* eflags */ EFL = 1 << 4, /* eflags */
FSGS = 1 << 6,
CSSS = 1 << 7,
QUAL = 1 << 15, /* exit qualification */ QUAL = 1 << 15, /* exit qualification */
CTRL = 1 << 16, /* execution controls */ CTRL = 1 << 16, /* execution controls */
INJ = 1 << 17, /* injection info */ INJ = 1 << 17, /* injection info */
@ -384,9 +387,13 @@ namespace Nova {
*/ */
struct Utcb struct Utcb
{ {
mword_t items; /* number of untyped items uses lowest 16 bit, number of typed items uses bit 16-31, bit 32+ are ignored on 64bit */ /**
Crd crd_xlt; /* receive capability-range descriptor for translation */ * Number of untyped items uses lowest 16 bit, number of typed items
Crd crd_rcv; /* receive capability-range descriptor for delegation */ * uses bit 16-31, bit 32+ are ignored on 64bit
*/
mword_t items;
Crd crd_xlt; /* receive capability-range descriptor for translation */
Crd crd_rcv; /* receive capability-range descriptor for delegation */
mword_t tls; mword_t tls;
/** /**
@ -402,19 +409,39 @@ namespace Nova {
/* exception state */ /* exception state */
struct { struct {
mword_t mtd, instr_len, eip, eflags; mword_t mtd, instr_len, ip, flags;
unsigned misc[4]; unsigned intr_state, actv_state, inj_info, inj_error;
mword_t eax, ecx, edx, ebx; mword_t ax, cx, dx, bx;
mword_t esp, ebp, esi, edi; mword_t sp, bp, si, di;
#ifdef __x86_64__ #ifdef __x86_64__
mword_t rxx[8]; mword_t r8, r9, r10, r11, r12, r13, r14, r15;
#endif #endif
unsigned long long qual[2]; /* exit qualification */ unsigned long long qual[2]; /* exit qualification */
unsigned ctrl[2]; unsigned ctrl[2];
unsigned long long tsc; unsigned long long tsc;
mword_t cr0, cr2, cr3, cr4; mword_t cr0, cr2, cr3, cr4;
// unsigned misc3[44]; #ifdef __x86_64__
}; mword_t cr8, reserved;
#endif
mword_t dr7, sysenter_cs, sysenter_sp, sysenter_ip;
struct {
unsigned short sel, ar;
unsigned limit;
mword_t base;
#ifdef __x86_32__
mword_t reserved;
#endif
} es, cs, ss, ds, fs, gs, ldtr, tr;
struct {
unsigned reserved0;
unsigned limit;
mword_t base;
#ifdef __x86_32__
mword_t reserved1;
#endif
} gdtr, idtr;
} __attribute__((packed));
}; };
struct Item { struct Item {
@ -499,9 +526,10 @@ namespace Nova {
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_STARTUP = 0x1e, PT_SEL_STARTUP = 0x1e,
PT_SEL_RECALL = 0x1f,
PD_SEL = 0x1b, PD_SEL = 0x1b,
PD_SEL_CAP_LOCK = 0x1c, /* convention on Genode */ PD_SEL_CAP_LOCK = 0x1c, /* convention on Genode */
SM_SEL_EC_MAIN = 0x1c, /* convention on Genode */ SM_SEL_EC_CLIENT = 0x1c, /* convention on Genode */
SM_SEL_EC = 0x1d, /* convention on Genode */ SM_SEL_EC = 0x1d, /* convention on Genode */
}; };

View File

@ -1,3 +0,0 @@
SRC_CC = pager.cc
vpath pager.cc $(REP_DIR)/src/base/pager

View File

@ -0,0 +1,3 @@
SRC_CC = pager.cc x86_32/pager.cc
vpath %.cc $(REP_DIR)/src/base/pager

View File

@ -0,0 +1,3 @@
SRC_CC = pager.cc x86_64/pager.cc
vpath %.cc $(REP_DIR)/src/base/pager

View File

@ -46,7 +46,7 @@ void Ipc_pager::wait_for_fault()
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb(); Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
_fault_type = (Pf_type)utcb->qual[0]; _fault_type = (Pf_type)utcb->qual[0];
_fault_addr = utcb->qual[1]; _fault_addr = utcb->qual[1];
_fault_ip = utcb->eip; _fault_ip = utcb->ip;
if (verbose_page_fault) if (verbose_page_fault)
print_page_fault(_fault_type, _fault_addr, _fault_ip); print_page_fault(_fault_type, _fault_addr, _fault_ip);

View File

@ -47,9 +47,13 @@ void Pager_object::_page_fault_handler()
PWRN("unresolvable page-fault at address 0x%lx, ip=0x%lx", PWRN("unresolvable page-fault at address 0x%lx, ip=0x%lx",
ipc_pager.fault_addr(), ipc_pager.fault_ip()); ipc_pager.fault_addr(), ipc_pager.fault_ip());
/* revoke paging capability, let thread die in kernel */ if (!obj->submit_exception_signal()) {
Nova::revoke(Obj_crd(obj->exc_pt_sel() + PT_SEL_PAGE_FAULT, 0), /* revoke paging capability, let thread die in kernel */
true); Nova::revoke(Obj_crd(obj->exc_pt_sel() + PT_SEL_PAGE_FAULT, 0),
true);
obj->_state.dead = true;
}
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb(); Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
utcb->set_msg_word(0); utcb->set_msg_word(0);
} }
@ -57,14 +61,41 @@ void Pager_object::_page_fault_handler()
ipc_pager.reply_and_wait_for_fault(); ipc_pager.reply_and_wait_for_fault();
} }
void Pager_object::_recall_handler()
{
Pager_object *obj = static_cast<Pager_object *>(Thread_base::myself());
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
obj->_copy_state(utcb);
obj->_state.thread.ip = utcb->ip;
obj->_state.thread.sp = utcb->sp;
obj->_state.thread.eflags = utcb->flags;
obj->_state.thread.trapno = PT_SEL_RECALL;
obj->_state.valid = true;
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)
PWRN("blocking recall handler failed");
obj->_state.valid = false;
utcb->set_msg_word(0);
utcb->mtd = 0;
reply(Thread_base::myself()->stack_top());
}
void Pager_object::_startup_handler() void Pager_object::_startup_handler()
{ {
Pager_object *obj = static_cast<Pager_object *>(Thread_base::myself()); Pager_object *obj = static_cast<Pager_object *>(Thread_base::myself());
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb(); Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
utcb->eip = obj->_initial_eip; utcb->ip = obj->_initial_eip;
utcb->esp = obj->_initial_esp; utcb->sp = obj->_initial_esp;
utcb->mtd = Mtd::EIP | Mtd::ESP; utcb->mtd = Mtd::EIP | Mtd::ESP;
utcb->set_msg_word(0); utcb->set_msg_word(0);
reply(Thread_base::myself()->stack_top()); reply(Thread_base::myself()->stack_top());
@ -82,12 +113,13 @@ void Pager_object::_invoke_handler()
utcb->set_msg_word(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) { event == SM_SEL_EC || event == PT_SEL_RECALL) {
/** /**
* Caller is requesting the SM cap of main thread * Caller is requesting the SM cap of thread
* this object is paging - it is stored at SM_SEL_EC_MAIN * this object is paging - it is stored at SM_SEL_EC_CLIENT
*/ */
if (event == SM_SEL_EC) event = SM_SEL_EC_MAIN; if (event == SM_SEL_EC) event = SM_SEL_EC_CLIENT;
bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel() + event, bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel() + event,
0), 0); 0), 0);
@ -99,13 +131,21 @@ void Pager_object::_invoke_handler()
} }
void Pager_object::wake_up() { PDBG("not yet implemented"); } void Pager_object::wake_up() { cancel_blocking(); }
void Pager_object::cancel_blocking_client() {
uint8_t res = sm_ctrl(exc_pt_sel() + SM_SEL_EC_CLIENT, SEMAPHORE_UP);
if (res != NOVA_OK)
PWRN("cancel blocking failed");
}
Pager_object::Pager_object(unsigned long badge) Pager_object::Pager_object(unsigned long badge)
: Thread_base("pager", PF_HANDLER_STACK_SIZE), _badge(badge) : Thread_base("pager", PF_HANDLER_STACK_SIZE), _badge(badge)
{ {
_pt_cleanup = cap_selector_allocator()->alloc(); _pt_cleanup = cap_selector_allocator()->alloc();
_sm_state_notify = cap_selector_allocator()->alloc();
_state.valid = false;
_state.dead = false;
/* create portal for page-fault handler */ /* create portal for page-fault handler */
addr_t pd_sel = __core_pd_sel; addr_t pd_sel = __core_pd_sel;
@ -129,19 +169,46 @@ Pager_object::Pager_object(unsigned long badge)
throw Create_startup_pt_failed(); throw Create_startup_pt_failed();
} }
/* Create portal for recall handler */
Mtd mtd(Mtd::ESP | Mtd::EIP | Mtd::ACDB | Mtd::EFL | Mtd::EBSD | Mtd::FSGS);
res = create_pt(exc_pt_sel() + 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);
class Create_recall_pt_failed { };
throw Create_recall_pt_failed();
}
/* Create portal for final cleanup call used during destruction */
res = create_pt(_pt_cleanup, pd_sel, _tid.ec_sel, Mtd(0), res = create_pt(_pt_cleanup, pd_sel, _tid.ec_sel, Mtd(0),
reinterpret_cast<addr_t>(_invoke_handler)); reinterpret_cast<addr_t>(_invoke_handler));
if (res) if (res) {
PERR("could not create pager cleanup portal, error = %u\n", PERR("could not create pager cleanup portal, error = %u\n", res);
res); class Create_cleanup_pt_failed { };
throw Create_cleanup_pt_failed();
}
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();
}
} }
Pager_object::~Pager_object() Pager_object::~Pager_object()
{ {
/* Revoke portals of Pager_object */ /* Revoke portals of Pager_object */
revoke(Obj_crd(exc_pt_sel() + PT_SEL_STARTUP, 0), true); revoke(Obj_crd(exc_pt_sel() + PT_SEL_STARTUP, 0), true);
revoke(Obj_crd(exc_pt_sel() + PT_SEL_RECALL, 0), true);
revoke(Obj_crd(exc_pt_sel() + PT_SEL_PAGE_FAULT, 0), true); revoke(Obj_crd(exc_pt_sel() + PT_SEL_PAGE_FAULT, 0), true);
/* 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), true);
/* Make sure nobody is in the handler anymore by doing an IPC to a /* Make sure nobody is in the handler anymore by doing an IPC to a
* local cap pointing to same serving thread (if not running in the * local cap pointing to same serving thread (if not running in the
* context of the serving thread). When the call returns * context of the serving thread). When the call returns
@ -158,7 +225,7 @@ Pager_object::~Pager_object()
/* Revoke portal used for the cleanup call */ /* Revoke portal used for the cleanup call */
revoke(Obj_crd(_pt_cleanup, 0), true); revoke(Obj_crd(_pt_cleanup, 0), true);
cap_selector_allocator()->free(_pt_cleanup, 0); cap_selector_allocator()->free(_pt_cleanup, 0);
cap_selector_allocator()->free(sm_cap, 0);
} }

View File

@ -0,0 +1,34 @@
/*
* \brief Copy thread state - x86_32
* \author Alexander Boettcher
* \date 2012-08-23
*/
/*
* Copyright (C) 2012-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/pager.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
void Pager_object::_copy_state(Nova::Utcb * utcb)
{
_state.thread.ebp = utcb->bp;
_state.thread.eax = utcb->ax;
_state.thread.ebx = utcb->bx;
_state.thread.ecx = utcb->cx;
_state.thread.edx = utcb->dx;
_state.thread.esi = utcb->si;
_state.thread.edi = utcb->di;
_state.thread.gs = utcb->gs.sel;
_state.thread.fs = utcb->fs.sel;
}

View File

@ -0,0 +1,42 @@
/*
* \brief Copy thread state - x86_64
* \author Alexander Boettcher
* \date 2012-08-23
*/
/*
* Copyright (C) 2012-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/pager.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
void Pager_object::_copy_state(Nova::Utcb * utcb)
{
_state.thread.rbp = utcb->bp;
_state.thread.rax = utcb->ax;
_state.thread.rbx = utcb->bx;
_state.thread.rcx = utcb->cx;
_state.thread.rdx = utcb->dx;
_state.thread.rsi = utcb->si;
_state.thread.rdi = utcb->di;
_state.thread.r8 = utcb->r8;
_state.thread.r9 = utcb->r9;
_state.thread.r10 = utcb->r10;
_state.thread.r11 = utcb->r11;
_state.thread.r12 = utcb->r12;
_state.thread.r13 = utcb->r13;
_state.thread.r14 = utcb->r14;
_state.thread.r15 = utcb->r15;
_state.thread.ss = utcb->ss.sel;
}

View File

@ -224,6 +224,8 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
Nova::PT_SEL_PAGE_FAULT); Nova::PT_SEL_PAGE_FAULT);
request_event_portal(pager_cap, _tid.exc_pt_sel, request_event_portal(pager_cap, _tid.exc_pt_sel,
Nova::SM_SEL_EC); Nova::SM_SEL_EC);
request_event_portal(pager_cap, _tid.exc_pt_sel,
Nova::PT_SEL_RECALL);
/** /**
* Request native thread cap, _thread_cap only a token. * Request native thread cap, _thread_cap only a token.

View File

@ -132,6 +132,7 @@ void Thread_base::start()
request_event_portal(pager_cap, _tid.exc_pt_sel, PT_SEL_STARTUP); 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, PT_SEL_PAGE_FAULT);
request_event_portal(pager_cap, _tid.exc_pt_sel, SM_SEL_EC); request_event_portal(pager_cap, _tid.exc_pt_sel, SM_SEL_EC);
request_event_portal(pager_cap, _tid.exc_pt_sel, PT_SEL_RECALL);
} }
/* request creation of SC to let thread run*/ /* request creation of SC to let thread run*/

View File

@ -98,11 +98,11 @@ static void page_fault_handler()
Utcb *utcb = (Utcb *)CORE_PAGER_UTCB_ADDR; Utcb *utcb = (Utcb *)CORE_PAGER_UTCB_ADDR;
addr_t pf_addr = utcb->qual[1]; addr_t pf_addr = utcb->qual[1];
addr_t pf_eip = utcb->eip; addr_t pf_ip = utcb->ip;
addr_t pf_esp = utcb->esp; addr_t pf_sp = utcb->sp;
printf("\nPAGE-FAULT IN CORE: ADDR %lx IP %lx SP %lx stack trace follows...\n", printf("\nPAGE-FAULT IN CORE: ADDR %lx IP %lx SP %lx stack trace follows...\n",
pf_addr, pf_eip, pf_esp); pf_addr, pf_ip, pf_sp);
/* dump stack trace */ /* dump stack trace */
struct Core_img struct Core_img
@ -127,9 +127,9 @@ static void page_fault_handler()
}; };
int count = 1; int count = 1;
printf(" #%d %08lx %08lx\n", count++, pf_esp, pf_eip); printf(" #%d %08lx %08lx\n", count++, pf_sp, pf_ip);
Core_img dump(pf_esp); Core_img dump(pf_sp);
while (dump.ip_valid()) { while (dump.ip_valid()) {
printf(" #%d %p %08lx\n", count++, dump.ip(), *dump.ip()); printf(" #%d %p %08lx\n", count++, dump.ip(), *dump.ip());
dump.next_ip(); dump.next_ip();

View File

@ -26,6 +26,7 @@
/* NOVA includes */ /* NOVA includes */
#include <nova/syscalls.h> #include <nova/syscalls.h>
#include <nova/util.h>
using namespace Genode; using namespace Genode;
@ -69,11 +70,11 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base, bool vcpu)
/** /**
* Create semaphore required for Genode locking. * Create semaphore required for Genode locking.
* It is created at the root pager exception base + * It is created at the root pager exception base +
* SM_SEL_EC_MAIN and can be later on requested by the thread * SM_SEL_EC_CLIENT and can be later on requested by the thread
* the same way as STARTUP and PAGEFAULT portal. * the same way as STARTUP and PAGEFAULT portal.
*/ */
uint8_t res = Nova::create_sm(_pager->exc_pt_sel() + uint8_t res = Nova::create_sm(_pager->exc_pt_sel() +
SM_SEL_EC_MAIN, SM_SEL_EC_CLIENT,
_pd->pd_sel(), 0); _pd->pd_sel(), 0);
if (res != Nova::NOVA_OK) { if (res != Nova::NOVA_OK) {
PERR("creation of semaphore for new thread failed %u", PERR("creation of semaphore for new thread failed %u",
@ -107,20 +108,32 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base, bool vcpu)
addr_t pd_core_sel = Platform_pd::pd_core_sel(); addr_t pd_core_sel = Platform_pd::pd_core_sel();
addr_t sm_alloc_sel = _sel_exc_base + PD_SEL_CAP_LOCK; addr_t sm_alloc_sel = _sel_exc_base + PD_SEL_CAP_LOCK;
addr_t sm_ec_sel = _sel_exc_base + SM_SEL_EC; addr_t sm_ec_sel = _pager->exc_pt_sel() + SM_SEL_EC_CLIENT;
addr_t remap_src[] = { _pager->exc_pt_sel() + PT_SEL_PAGE_FAULT, addr_t remap_src[] = { _pager->exc_pt_sel() + PT_SEL_PAGE_FAULT,
_pd->parent_pt_sel(), _pd->parent_pt_sel(),
_pager->exc_pt_sel() + PT_SEL_STARTUP }; _pager->exc_pt_sel() + PT_SEL_STARTUP,
_pager->exc_pt_sel() + PT_SEL_RECALL,
sm_ec_sel };
addr_t remap_dst[] = { PT_SEL_PAGE_FAULT, addr_t remap_dst[] = { PT_SEL_PAGE_FAULT,
PT_SEL_PARENT, PT_SEL_PARENT,
PT_SEL_STARTUP }; PT_SEL_STARTUP,
PT_SEL_RECALL,
SM_SEL_EC };
addr_t pd_sel; addr_t pd_sel;
Obj_crd initial_pts(_sel_exc_base, NUM_INITIAL_PT_LOG2); Obj_crd initial_pts(_sel_exc_base, NUM_INITIAL_PT_LOG2);
uint8_t res; 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 portals to exception base window of 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++) {
/* locally map portals to initial portal window */ /* locally map portals to initial portal window */
if (map_local((Utcb *)Thread_base::myself()->utcb(), if (map_local((Utcb *)Thread_base::myself()->utcb(),
@ -139,13 +152,6 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base, bool vcpu)
goto cleanup_base; goto cleanup_base;
} }
/* 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;
}
pd_sel = cap_selector_allocator()->alloc(); pd_sel = cap_selector_allocator()->alloc();
/* create task */ /* create task */
@ -192,6 +198,7 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base, bool vcpu)
cap_selector_allocator()->free(pd_sel, 0); cap_selector_allocator()->free(pd_sel, 0);
cleanup_base: cleanup_base:
revoke(Obj_crd(sm_ec_sel, 0));
revoke(Obj_crd(_sel_exc_base, NUM_INITIAL_PT_LOG2)); revoke(Obj_crd(_sel_exc_base, NUM_INITIAL_PT_LOG2));
cap_selector_allocator()->free(_sel_exc_base, NUM_INITIAL_PT_LOG2); cap_selector_allocator()->free(_sel_exc_base, NUM_INITIAL_PT_LOG2);
_sel_exc_base = ~0UL; _sel_exc_base = ~0UL;
@ -202,28 +209,51 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base, bool vcpu)
Native_capability Platform_thread::pause() Native_capability Platform_thread::pause()
{ {
PDBG("not implemented"); if (!_pager)
return Native_capability::invalid_cap(); return Native_capability::invalid_cap();
Native_capability notify_sm = _pager->notify_sm();
if (!notify_sm.valid()) return notify_sm;
if (Nova::ec_ctrl(_sel_ec()) != Nova::NOVA_OK)
return Native_capability::invalid_cap();
/* If the thread is blocked in the its own SM, get him out */
cancel_blocking();
return notify_sm;
} }
void Platform_thread::resume() void Platform_thread::resume()
{ {
uint8_t res = Nova::create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), using namespace Nova;
Nova::Qpd());
if (res) uint8_t res = create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), Qpd());
PDBG("create_sc returned %u", res); if (res == NOVA_OK) return;
if (!_pager) return;
/* Thread was paused beforehand and blocked in pager - wake up pager */
_pager->wake_up();
} }
int Platform_thread::state(Thread_state *state_dst) int Platform_thread::state(Thread_state *state_dst)
{ {
PWRN("not implemented"); if (!state_dst || !_pager) return -1;
return -1;
int res = _pager->copy_thread_state(state_dst);
return res;
} }
void Platform_thread::cancel_blocking() { PWRN("not implemented"); } void Platform_thread::cancel_blocking()
{
if (!_pager) return;
_pager->cancel_blocking_client();
}
unsigned long Platform_thread::pager_object_badge() const { return ~0UL; } unsigned long Platform_thread::pager_object_badge() const { return ~0UL; }