NOVA: tunnel thread start parameters via state()

The cpu_session interface fails to be virtualized by gdb_monitor because
platform-nova uses an extended nova_cpu_session interface.

The problem was that threads have been created directly at core without
knowledge of gdb_monitor. This lead to the situation that gdb_monitor didn't
know of all threads to be debugged.

Tunnel the additional parameters required on base-nova through the state()
call of the cpu_session interface before the thread actual is started.
This commit is contained in:
Alexander Boettcher 2012-08-22 12:10:04 +02:00 committed by Norman Feske
parent 197a48a26c
commit fcd62729d4
11 changed files with 92 additions and 64 deletions

View File

@ -59,6 +59,7 @@ namespace Genode {
struct {
struct Thread_state thread;
addr_t sel_client_ec;
bool valid;
bool dead;
} _state;
@ -164,7 +165,10 @@ namespace Genode {
* Cancel blocking in a lock so that recall exception can take
* place.
*/
void cancel_blocking_client();
void client_cancel_blocking();
uint8_t client_recall();
void client_set_ec(addr_t ec) { _state.sel_client_ec = ec; }
};

View File

@ -20,7 +20,15 @@
namespace Genode {
struct Thread_state : public Cpu_state { };
struct Thread_state : public Cpu_state
{
bool transfer;
bool is_vcpu;
addr_t sel_exc_base;
Thread_state(bool trans = false) : Cpu_state(), transfer(trans),
is_vcpu(false), sel_exc_base(~0UL) {}
};
}
#endif /* _INCLUDE__BASE__THREAD_STATE_H_ */

View File

@ -80,14 +80,6 @@ namespace Genode {
Native_capability native_cap(Thread_capability cap) {
return call<Rpc_native_cap>(cap); }
int start_exc_base_vcpu(Thread_capability thread, addr_t ip,
addr_t sp, addr_t exc_base,
bool vcpu = false)
{
return call<Rpc_start_exc_base_vcpu>(thread, ip, sp,
exc_base, vcpu);
}
private:
Native_capability pause_sync(Thread_capability target) {

View File

@ -23,9 +23,6 @@ namespace Genode {
{
virtual ~Nova_cpu_session() { }
virtual int
start_exc_base_vcpu(Thread_capability thread, addr_t ip,
addr_t sp, addr_t exc_base, bool vcpu) = 0;
virtual
Native_capability native_cap(Thread_capability cap) = 0;
@ -36,15 +33,13 @@ namespace Genode {
** RPC declaration **
*********************/
GENODE_RPC(Rpc_start_exc_base_vcpu, int, start_exc_base_vcpu,
Thread_capability, addr_t, addr_t, addr_t, bool);
GENODE_RPC(Rpc_native_cap, Native_capability, native_cap,
Thread_capability);
GENODE_RPC(Rpc_pause_sync, Native_capability, pause_sync,
Thread_capability);
GENODE_RPC_INTERFACE_INHERIT(Cpu_session, Rpc_native_cap,
Rpc_start_exc_base_vcpu, Rpc_pause_sync);
Rpc_pause_sync);
};
}

View File

@ -44,18 +44,21 @@ void Pager_object::_page_fault_handler()
int ret = obj->pager(ipc_pager);
if (ret) {
PWRN("unresolvable page-fault at address 0x%lx, ip=0x%lx",
ipc_pager.fault_addr(), ipc_pager.fault_ip());
if (!obj->submit_exception_signal()) {
PWRN("unresolvable page-fault at address 0x%lx, ip=0x%lx",
ipc_pager.fault_addr(), ipc_pager.fault_ip());
/* revoke paging capability, let thread die in kernel */
Nova::revoke(Obj_crd(obj->exc_pt_sel() + PT_SEL_PAGE_FAULT, 0),
true);
obj->_state.dead = true;
}
} else
/* Somebody takes care don't die - just recall and block */
obj->client_recall();
Utcb *utcb = (Utcb *)Thread_base::myself()->utcb();
utcb->set_msg_word(0);
utcb->mtd = 0;
}
ipc_pager.reply_and_wait_for_fault();
@ -133,19 +136,27 @@ void Pager_object::_invoke_handler()
void Pager_object::wake_up() { cancel_blocking(); }
void Pager_object::cancel_blocking_client() {
void Pager_object::client_cancel_blocking() {
uint8_t res = sm_ctrl(exc_pt_sel() + SM_SEL_EC_CLIENT, SEMAPHORE_UP);
if (res != NOVA_OK)
PWRN("cancel blocking failed");
}
uint8_t Pager_object::client_recall() {
return ec_ctrl(_state.sel_client_ec);
}
Pager_object::Pager_object(unsigned long badge)
: Thread_base("pager", PF_HANDLER_STACK_SIZE), _badge(badge)
{
_pt_cleanup = cap_selector_allocator()->alloc();
_sm_state_notify = cap_selector_allocator()->alloc();
_state.valid = false;
_state.dead = false;
_pt_cleanup = cap_selector_allocator()->alloc();
_sm_state_notify = cap_selector_allocator()->alloc();
_state.valid = false;
_state.dead = false;
_state.sel_client_ec = ~0UL;
/* create portal for page-fault handler */
addr_t pd_sel = __core_pd_sel;

View File

@ -214,9 +214,13 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
throw Cpu_session::Thread_creation_failed();
addr_t thread_sp = (addr_t)&_context->stack[-4];
Genode::Nova_cpu_connection cpu;
cpu.start_exc_base_vcpu(_thread_cap, 0, thread_sp,
_tid.exc_pt_sel);
Thread_state state(true);
state.sel_exc_base = _tid.exc_pt_sel;
if (env()->cpu_session()->state(_thread_cap, &state) ||
env()->cpu_session()->start(_thread_cap, 0, thread_sp))
throw Cpu_session::Thread_creation_failed();
request_event_portal(pager_cap, _tid.exc_pt_sel,
Nova::PT_SEL_STARTUP);
@ -232,7 +236,10 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
* The native thread cap is required to attach new rpc objects
* (to create portals bound to the ec)
*/
Genode::Nova_cpu_connection cpu;
Native_capability ec_cap = cpu.native_cap(_thread_cap);
if (!ec_cap.valid())
throw Cpu_session::Thread_creation_failed();
_tid.ec_sel = ec_cap.local_name();
}

View File

@ -116,13 +116,20 @@ void Thread_base::start()
/* create EC at core */
addr_t thread_sp = reinterpret_cast<addr_t>(&_context->stack[-4]);
Genode::Nova_cpu_connection cpu;
if (cpu.start_exc_base_vcpu(_thread_cap, (addr_t)_thread_start,
thread_sp, _tid.exc_pt_sel, _tid.is_vcpu))
Thread_state state(true);
state.sel_exc_base = _tid.exc_pt_sel;
state.is_vcpu = _tid.is_vcpu;
if (env()->cpu_session()->state(_thread_cap, &state) ||
env()->cpu_session()->start(_thread_cap, (addr_t)_thread_start,
thread_sp))
throw Cpu_session::Thread_creation_failed();
/* request native EC thread cap */
Genode::Nova_cpu_connection cpu;
Native_capability ec_cap = cpu.native_cap(_thread_cap);
if (!ec_cap.valid())
throw Cpu_session::Thread_creation_failed();
_tid.ec_sel = ec_cap.local_name();
using namespace Nova;

View File

@ -29,18 +29,6 @@ Cpu_session_component::native_cap(Thread_capability thread_cap)
return thread->platform_thread()->native_cap();
}
int
Cpu_session_component::start_exc_base_vcpu(Thread_capability thread_cap,
addr_t ip, addr_t sp,
addr_t exc_base, bool vcpu)
{
Cpu_thread_component *thread = _lookup_thread(thread_cap);
if (!thread) return -1;
return thread->platform_thread()->start((void *)ip, (void *)sp,
exc_base, vcpu);
}
Native_capability
Cpu_session_component::pause_sync(Thread_capability target_thread_cap)
{

View File

@ -147,8 +147,6 @@ namespace Genode {
** NOVA specific extensions **
***********************************/
int start_exc_base_vcpu(Thread_capability, addr_t,
addr_t, addr_t, bool);
Native_capability native_cap(Thread_capability);
Native_capability pause_sync(Thread_capability);
};

View File

@ -35,6 +35,7 @@ namespace Genode {
addr_t _sel_exc_base;
unsigned _cpu_no;
bool _is_main_thread;
bool _is_vcpu;
addr_t _sel_ec() { return _id_base; }
addr_t _sel_sc() { return _id_base + 1; }
@ -61,16 +62,11 @@ namespace Genode {
*
* \param ip instruction pointer to start at
* \param sp stack pointer to use
* \param exc_base exception base of thread in caller
* protection domain
* \param vcpu If true it will run as vCPU,
* otherwise it will be a thread.
*
* \retval 0 successful
* \retval -1 thread/vCPU could not be started
*/
int start(void *ip, void *sp, addr_t exc_base = ~0UL,
bool vcpu = false);
int start(void *ip, void *sp);
/**
* Pause this thread

View File

@ -41,7 +41,7 @@ void Platform_thread::set_cpu(unsigned int cpu_no)
}
int Platform_thread::start(void *ip, void *sp, addr_t exc_base, bool vcpu)
int Platform_thread::start(void *ip, void *sp)
{
using namespace Nova;
@ -59,10 +59,10 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base, bool vcpu)
_pager->initial_eip((addr_t)ip);
if (!_is_main_thread) {
addr_t initial_sp = reinterpret_cast<addr_t>(sp);
addr_t utcb = vcpu ? 0 : round_page(initial_sp);
addr_t utcb = _is_vcpu ? 0 : round_page(initial_sp);
_pager->initial_esp(initial_sp);
if (exc_base == ~0UL) {
if (_sel_exc_base == ~0UL) {
PERR("exception base not specified");
return -3;
}
@ -86,10 +86,12 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base, bool vcpu)
bool thread_global = ip;
res = create_ec(_sel_ec(), _pd->pd_sel(), _cpu_no, utcb,
initial_sp, exc_base, thread_global);
initial_sp, _sel_exc_base, thread_global);
if (res)
PERR("creation of new thread failed %u", res);
_pager->client_set_ec(_sel_ec());
return res ? -5 : 0;
}
@ -175,13 +177,17 @@ int Platform_thread::start(void *ip, void *sp, addr_t exc_base, bool vcpu)
* becomes running immediately.
*/
_pd->assign_pd(pd_sel);
_pager->client_set_ec(_sel_ec());
/* Let the thread run */
res = create_sc(_sel_sc(), pd_sel, _sel_ec(), Qpd());
if (res) {
/* Reset pd cap since thread got not running and pd cap will
* be revoked during cleanup*/
/**
* Reset pd cap since thread got not running and pd cap will
* be revoked during cleanup.
*/
_pd->assign_pd(~0UL);
_pager->client_set_ec(~0UL);
PERR("create_sc returned %d", res);
goto cleanup_ec;
@ -215,7 +221,7 @@ Native_capability Platform_thread::pause()
Native_capability notify_sm = _pager->notify_sm();
if (!notify_sm.valid()) return notify_sm;
if (Nova::ec_ctrl(_sel_ec()) != Nova::NOVA_OK)
if (_pager->client_recall() != Nova::NOVA_OK)
return Native_capability::invalid_cap();
/* If the thread is blocked in the its own SM, get him out */
@ -233,6 +239,7 @@ void Platform_thread::resume()
if (res == NOVA_OK) return;
if (!_pager) return;
/* Thread was paused beforehand and blocked in pager - wake up pager */
_pager->wake_up();
}
@ -242,9 +249,24 @@ int Platform_thread::state(Thread_state *state_dst)
{
if (!state_dst || !_pager) return -1;
int res = _pager->copy_thread_state(state_dst);
if (state_dst->transfer) {
/* Not permitted for main thread */
if (_is_main_thread) return -2;
/* You can do it only once */
if (_sel_exc_base != ~0UL) return -3;
/**
* _sel_exc_base exception base of thread in caller
* protection domain - not in Core !
* _is_vcpu If true it will run as vCPU,
* otherwise it will be a thread.
*/
_sel_exc_base = state_dst->sel_exc_base;
_is_vcpu = state_dst->is_vcpu;
return res;
return 0;
}
return _pager->copy_thread_state(state_dst);
}
@ -252,7 +274,7 @@ void Platform_thread::cancel_blocking()
{
if (!_pager) return;
_pager->cancel_blocking_client();
_pager->client_cancel_blocking();
}
@ -261,7 +283,7 @@ unsigned long Platform_thread::pager_object_badge() const { return ~0UL; }
Platform_thread::Platform_thread(const char *name, unsigned, int thread_id)
: _pd(0), _pager(0), _id_base(cap_selector_allocator()->alloc(1)),
_sel_exc_base(~0UL), _cpu_no(0), _is_main_thread(false) { }
_sel_exc_base(~0UL), _cpu_no(0), _is_main_thread(false), _is_vcpu(false) { }
Platform_thread::~Platform_thread()
@ -273,7 +295,7 @@ Platform_thread::~Platform_thread()
cap_selector_allocator()->free(_id_base, 1);
/* free exc_base used by main thread */
if (_sel_exc_base != ~0UL) {
if (_is_main_thread && _sel_exc_base != ~0UL) {
revoke(Obj_crd(_sel_exc_base, NUM_INITIAL_PT_LOG2));
cap_selector_allocator()->free(_sel_exc_base,
NUM_INITIAL_PT_LOG2);