mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 16:35:28 +00:00
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:
parent
197a48a26c
commit
fcd62729d4
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user