base: changes for GDB monitor

- add a new function 'binary_ready_hook_for_gdb()' in ldso. GDB can set a
  breakpoint at this function to know when ldso has loaded the binary
  into memory.
- get the thread state from the NOVA kernel immediately on 'pause()'

Fixes #1968
This commit is contained in:
Christian Prochaska 2016-05-17 16:13:56 +02:00 committed by Christian Helmuth
parent 30e57d4581
commit 2cde1d36c1
24 changed files with 371 additions and 408 deletions

View File

@ -25,11 +25,9 @@ struct Genode::Thread_state : Thread_state_base
{
bool vcpu;
addr_t sel_exc_base;
bool global_thread;
Thread_state() : vcpu(false), sel_exc_base(~0UL) { }
Thread_state(bool vcpu, addr_t sel_exc_base)
: vcpu(vcpu), sel_exc_base(sel_exc_base) { }
Thread_state() : vcpu(false), sel_exc_base(~0UL), global_thread(true) { }
};
#endif /* _INCLUDE__BASE__THREAD_STATE_H_ */

View File

@ -1,68 +0,0 @@
/*
* \brief Client-side cpu session NOVA extension
* \author Alexander Boettcher
* \date 2012-07-27
*/
/*
* Copyright (C) 2012-2013 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.
*/
#ifndef _INCLUDE__CPU_SESSION__CLIENT_H_
#define _INCLUDE__CPU_SESSION__CLIENT_H_
#include <base/rpc_client.h>
#include <base/thread.h>
#include <cpu_session/capability.h>
#include <nova_cpu_session/nova_cpu_session.h>
namespace Genode { struct Cpu_session_client; }
struct Genode::Cpu_session_client : Rpc_client<Nova_cpu_session>
{
explicit Cpu_session_client(Cpu_session_capability session)
: Rpc_client<Nova_cpu_session>(static_cap_cast<Nova_cpu_session>(session)) { }
Thread_capability
create_thread(Capability<Pd_session> pd, Name const &name,
Affinity::Location affinity, Weight weight, addr_t utcb = 0) override {
return call<Rpc_create_thread>(pd, name, affinity, weight, utcb); }
void kill_thread(Thread_capability thread) override {
call<Rpc_kill_thread>(thread); }
void exception_sigh(Signal_context_capability handler) override {
call<Rpc_exception_sigh>(handler); }
Affinity::Space affinity_space() const override {
return call<Rpc_affinity_space>(); }
Dataspace_capability trace_control() override {
return call<Rpc_trace_control>(); }
int ref_account(Cpu_session_capability session) override {
return call<Rpc_ref_account>(session); }
int transfer_quota(Cpu_session_capability session, size_t amount) override {
return call<Rpc_transfer_quota>(session, amount); }
Quota quota() override { return call<Rpc_quota>(); }
Capability<Native_cpu> native_cpu() override { return call<Rpc_native_cpu>(); }
private:
Native_capability pause_sync(Thread_capability) {
return Native_capability(); }
Native_capability single_step_sync(Thread_capability, bool) {
return Native_capability(); }
};
#endif /* _INCLUDE__CPU_SESSION__CLIENT_H_ */

View File

@ -0,0 +1,82 @@
/*
* \brief Client-side CPU thread interface
* \author Norman Feske
* \date 2016-05-10
*/
/*
* Copyright (C) 2016 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.
*/
#ifndef _INCLUDE__CPU_THREAD__CLIENT_H_
#define _INCLUDE__CPU_THREAD__CLIENT_H_
#include <cpu_thread/cpu_thread.h>
#include <base/rpc_client.h>
namespace Genode { struct Cpu_thread_client; }
struct Genode::Cpu_thread_client : Rpc_client<Cpu_thread>
{
explicit Cpu_thread_client(Thread_capability cap)
: Rpc_client<Cpu_thread>(cap) { }
Dataspace_capability utcb() override {
return call<Rpc_utcb>(); }
void start(addr_t ip, addr_t sp) override {
call<Rpc_start>(ip, sp); }
void pause() override {
for (;;) {
call<Rpc_pause>();
try {
/* check if the thread state is valid */
state();
/* the thread is paused */
return;
} catch (State_access_failed) {
/* the thread is (most likely) running on a different CPU */
}
}
}
void resume() override {
call<Rpc_resume>(); }
void cancel_blocking() override {
call<Rpc_cancel_blocking>(); }
Thread_state state() override {
return call<Rpc_get_state>(); }
void state(Thread_state const &state) override {
call<Rpc_set_state>(state); }
void exception_sigh(Signal_context_capability handler) override {
call<Rpc_exception_sigh>(handler); }
void single_step(bool enabled) override {
call<Rpc_single_step>(enabled); }
void affinity(Affinity::Location location) override {
call<Rpc_affinity>(location); }
unsigned trace_control_index() override {
return call<Rpc_trace_control_index>(); }
Dataspace_capability trace_buffer() override {
return call<Rpc_trace_buffer>(); }
Dataspace_capability trace_policy() override {
return call<Rpc_trace_policy>(); }
};
#endif /* _INCLUDE__CPU_THREAD__CLIENT_H_ */

View File

@ -31,6 +31,7 @@ struct Genode::Native_thread
addr_t ec_sel; /* selector for execution context */
addr_t exc_pt_sel; /* base of event portal window */
bool vcpu; /* true if thread is a virtual CPU */
addr_t initial_ip; /* initial IP of local thread */
/* receive window for capability selectors received at the server side */
Receive_window rcv_window;
@ -38,7 +39,9 @@ struct Genode::Native_thread
Native_capability pager_cap;
Native_thread() : ec_sel(INVALID_INDEX),
exc_pt_sel(INVALID_INDEX), vcpu(false) { }
exc_pt_sel(INVALID_INDEX),
vcpu(false),
initial_ip(0) { }
};
#endif /* _INCLUDE__NOVA__NATIVE_THREAD_H_ */

View File

@ -1,40 +0,0 @@
/*
* \brief Connection to NOVA specific CPU service
* \author Alexander Boettcher
* \date 2012-07-27
*/
/*
* Copyright (C) 2012-2013 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.
*/
#ifndef _INCLUDE__NOVA_CPU_SESSION__CONNECTION_H_
#define _INCLUDE__NOVA_CPU_SESSION__CONNECTION_H_
#include <cpu_session/client.h>
#include <base/connection.h>
namespace Genode {
struct Nova_cpu_connection : Connection<Cpu_session>, Cpu_session_client
{
/**
* Constructor
*
* \param label initial session label
* \param priority designated priority of all threads created
* with this CPU session
*/
Nova_cpu_connection(const char *label = "", long priority = DEFAULT_PRIORITY)
:
Connection<Cpu_session>(
session("priority=0x%lx, ram_quota=32K, label=\"%s\"",
priority, label)),
Cpu_session_client(cap()) { }
};
}
#endif /* _INCLUDE__NOVA_CPU_SESSION__CONNECTION_H_ */

View File

@ -1,44 +0,0 @@
/*
* \brief Cpu session interface extension for NOVA
* \author Alexander Boettcher
* \date 2012-07-27
*/
/*
* Copyright (C) 2012-2013 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.
*/
#ifndef _INCLUDE__NOVA_CPU_SESSION__NOVA_CPU_SESSION_H_
#define _INCLUDE__NOVA_CPU_SESSION__NOVA_CPU_SESSION_H_
#include <base/stdint.h>
#include <cpu_session/cpu_session.h>
namespace Genode {
struct Nova_cpu_session : Cpu_session
{
virtual ~Nova_cpu_session() { }
virtual Native_capability pause_sync(Thread_capability) = 0;
virtual Native_capability single_step_sync(Thread_capability, bool) = 0;
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_pause_sync, Native_capability, pause_sync,
Thread_capability);
GENODE_RPC(Rpc_single_step_sync, Native_capability, single_step_sync,
Thread_capability, bool);
GENODE_RPC_INTERFACE_INHERIT(Cpu_session, Rpc_pause_sync,
Rpc_single_step_sync);
};
}
#endif /* _INCLUDE__NOVA_CPU_SESSION__NOVA_CPU_SESSION_H_ */

View File

@ -1 +1 @@
5d57765b0abab82acc9d0725bbd30329905751e2
b27175ffa51a7e3c19784f2789e5ab0fb37034f3

View File

@ -4,7 +4,7 @@ DOWNLOADS := nova.git
# r9 branch - use r9_debug for more verbose kernel messages
URL(nova) := https://github.com/alex-ab/NOVA.git
REV(nova) := 886e0d94053ab8d45320eecc85213f9a3b797baf
REV(nova) := 7b1209d02d69adaf93adc312f291997f3a98ba81
DIR(nova) := src/kernel/nova
PATCHES := $(wildcard $(REP_DIR)/patches/*.patch)

View File

@ -1,48 +0,0 @@
/**
* \brief Core implementation of the CPU session interface extension
* \author Alexander Boettcher
* \date 2012-07-27
*/
/*
* Copyright (C) 2012-2013 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/stdint.h>
/* core-local includes */
#include <cpu_session_component.h>
using namespace Genode;
Native_capability
Cpu_session_component::pause_sync(Thread_capability thread_cap)
{
auto lambda = [] (Cpu_thread_component *thread) {
if (!thread)
return Native_capability();
return thread->platform_thread().pause();
};
return _thread_ep->apply(thread_cap, lambda);
}
Native_capability
Cpu_session_component::single_step_sync(Thread_capability thread_cap, bool enable)
{
using namespace Genode;
auto lambda = [enable] (Cpu_thread_component *thread) {
if (!thread)
return Native_capability();
return thread->platform_thread().single_step_sync(enable);
};
return _thread_ep->apply(thread_cap, lambda);
}

View File

@ -22,7 +22,6 @@
#include <base/tslab.h>
#include <base/lock.h>
#include <base/rpc_server.h>
#include <nova_cpu_session/nova_cpu_session.h>
/* core includes */
#include <pager.h>
@ -37,7 +36,7 @@
namespace Genode { class Cpu_session_component; }
class Genode::Cpu_session_component : public Rpc_object<Nova_cpu_session>
class Genode::Cpu_session_component : public Rpc_object<Cpu_session>
{
public:
@ -150,14 +149,6 @@ class Genode::Cpu_session_component : public Rpc_object<Nova_cpu_session>
Quota quota() override;
Capability<Native_cpu> native_cpu() { return _native_cpu.cap(); }
/******************************
** NOVA specific extensions **
******************************/
Native_capability pause_sync(Thread_capability) override;
Native_capability single_step_sync(Thread_capability, bool) override;
};
#endif /* _CORE__INCLUDE__CPU_SESSION_COMPONENT_H_ */

View File

@ -73,21 +73,22 @@ namespace Genode {
addr_t _client_exc_pt_sel;
addr_t _client_exc_vcpu;
Lock _state_lock;
struct
{
struct Thread_state thread;
addr_t sel_client_ec;
enum {
BLOCKED = 0x1U,
DEAD = 0x2U,
SINGLESTEP = 0x4U,
NOTIFY_REQUEST = 0x8U,
SIGNAL_SM = 0x10U,
DISSOLVED = 0x20U,
SUBMIT_SIGNAL = 0x40U,
SKIP_EXCEPTION = 0x80U,
BLOCKED = 0x1U,
DEAD = 0x2U,
SINGLESTEP = 0x4U,
SIGNAL_SM = 0x8U,
DISSOLVED = 0x10U,
SUBMIT_SIGNAL = 0x20U,
};
uint8_t _status;
bool modified;
/* convenience function to access pause/recall state */
inline bool blocked() { return _status & BLOCKED;}
@ -99,10 +100,6 @@ namespace Genode {
inline bool singlestep() { return _status & SINGLESTEP; }
inline void notify_request() { _status |= NOTIFY_REQUEST; }
inline bool notify_requested() { return _status & NOTIFY_REQUEST; }
inline void notify_cancel() { _status &= ~NOTIFY_REQUEST; }
inline void mark_signal_sm() { _status |= SIGNAL_SM; }
inline bool has_signal_sm() { return _status & SIGNAL_SM; }
@ -113,9 +110,6 @@ namespace Genode {
inline void submit_signal() { _status |= SUBMIT_SIGNAL; }
inline void reset_submit() { _status &= ~SUBMIT_SIGNAL; }
inline bool skip_requested() { return _status & SKIP_EXCEPTION; }
inline void skip_request() { _status |= SKIP_EXCEPTION; }
inline void skip_reset() { _status &= ~SKIP_EXCEPTION; }
} _state;
Cpu_session_capability _cpu_session_cap;
@ -124,12 +118,15 @@ namespace Genode {
addr_t _pd;
void _copy_state(Nova::Utcb * utcb);
void _copy_state_from_utcb(Nova::Utcb * utcb);
void _copy_state_to_utcb(Nova::Utcb * utcb);
addr_t sel_pt_cleanup() const { return _selectors; }
addr_t sel_sm_notify() const { return _selectors + 1; }
addr_t sel_sm_block() const { return _selectors + 2; }
addr_t sel_oom_portal() const { return _selectors + 3; }
uint8_t _unsynchronized_client_recall(bool get_state_and_block);
addr_t sel_pt_cleanup() const { return _selectors; }
addr_t sel_sm_block_pause() const { return _selectors + 1; }
addr_t sel_sm_block_oom() const { return _selectors + 2; }
addr_t sel_oom_portal() const { return _selectors + 3; }
__attribute__((regparm(1)))
static void _page_fault_handler(addr_t pager_obj);
@ -222,25 +219,13 @@ namespace Genode {
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.blocked() || _state.is_dead())
return Native_capability();
_state.notify_request();
return Native_capability(sel_sm_notify());
}
/**
* Copy thread state of recalled thread.
*/
bool copy_thread_state(Thread_state * state_dst)
{
Lock::Guard _state_lock_guard(_state_lock);
if (!state_dst || !_state.blocked())
return false;
@ -249,40 +234,51 @@ namespace Genode {
return true;
}
/*
* Copy thread state to recalled thread.
*/
bool copy_thread_state(Thread_state state_src)
{
Lock::Guard _state_lock_guard(_state_lock);
if (!_state.blocked())
return false;
_state.thread = state_src;
_state.modified = true;
return true;
}
/**
* Cancel blocking in a lock so that recall exception can take
* place.
*/
void client_cancel_blocking();
uint8_t client_recall();
void client_set_ec(addr_t ec) { _state.sel_client_ec = ec; }
uint8_t client_recall(bool get_state_and_block);
void client_set_ec(addr_t ec) { _state.sel_client_ec = ec; }
inline Native_capability single_step(bool on)
inline void single_step(bool on)
{
if (_state.is_dead() ||
_state_lock.lock();
if (_state.is_dead() || !_state.blocked() ||
(on && (_state._status & _state.SINGLESTEP)) ||
(!on && !(_state._status & _state.SINGLESTEP)))
return Native_capability();
(!on && !(_state._status & _state.SINGLESTEP))) {
_state_lock.unlock();
return;
}
if (on)
_state._status |= _state.SINGLESTEP;
else
_state._status &= ~_state.SINGLESTEP;
/* we want to be notified if state change is done */
_state.notify_request();
/* the first single step exit ignore when switching it on */
if (on && _state.blocked())
_state.skip_request();
_state_lock.unlock();
/* force client in exit and thereby apply single_step change */
client_recall();
/* single_step mode changes don't apply if blocked - wake up */
if (_state.blocked())
wake_up();
return Native_capability(sel_sm_notify());
client_recall(false);
}
/**
@ -304,6 +300,8 @@ namespace Genode {
*/
void unresolved_page_fault_occurred()
{
Lock::Guard _state_lock_guard(_state_lock);
_state.thread.unresolved_page_fault = true;
}

View File

@ -92,12 +92,12 @@ namespace Genode {
/**
* Pause this thread
*/
Native_capability pause();
void pause();
/**
* Enable/disable single stepping
*/
void single_step(bool) { }
void single_step(bool);
/**
* Resume this thread
@ -173,8 +173,6 @@ namespace Genode {
if (main_thread) _features |= MAIN_THREAD;
}
Native_capability single_step_sync(bool on);
/**
* Set CPU quota of the thread to 'quota'
*/

View File

@ -90,12 +90,16 @@ void Pager_object::_page_fault_handler(addr_t pager_obj)
if (!ret)
ipc_pager.reply_and_wait_for_fault();
obj->_state_lock.lock();
obj->_state.thread.ip = ipc_pager.fault_ip();
obj->_state.thread.sp = 0;
obj->_state.thread.trapno = PT_SEL_PAGE_FAULT;
obj->_state.block();
obj->_state_lock.unlock();
char const * client = reinterpret_cast<char const *>(obj->_badge);
/* region manager fault - to be handled */
if (ret == 1) {
@ -107,7 +111,7 @@ void Pager_object::_page_fault_handler(addr_t pager_obj)
utcb->mtd = 0;
/* block the faulting thread until region manager is done */
ipc_pager.reply_and_wait_for_fault(obj->sel_sm_block());
ipc_pager.reply_and_wait_for_fault(obj->sel_sm_block_pause());
}
/* unhandled case */
@ -141,21 +145,14 @@ void Pager_object::exception(uint8_t exit_id)
uint8_t res = 0xFF;
addr_t mtd = 0;
if (_state.skip_requested()) {
_state.skip_reset();
utcb->set_msg_word(0);
utcb->mtd = 0;
reply(myself->stack_top());
}
_state_lock.lock();
/* remember exception type for cpu_session()->state() calls */
_state.thread.trapno = exit_id;
_state.thread.ip = fault_ip;
if (_exception_sigh.valid()) {
_state.submit_signal();
res = client_recall();
res = _unsynchronized_client_recall(true);
}
if (res != NOVA_OK) {
@ -178,6 +175,8 @@ void Pager_object::exception(uint8_t exit_id)
}
}
_state_lock.unlock();
utcb->set_msg_word(0);
utcb->mtd = mtd;
@ -191,44 +190,36 @@ void Pager_object::_recall_handler(addr_t pager_obj)
Pager_object * obj = reinterpret_cast<Pager_object *>(pager_obj);
Utcb * utcb = reinterpret_cast<Utcb *>(myself->utcb());
/* save state - can be requested via cpu_session->state */
obj->_copy_state(utcb);
obj->_state_lock.lock();
obj->_state.thread.ip = utcb->ip;
obj->_state.thread.sp = utcb->sp;
if (obj->_state.modified) {
obj->_copy_state_to_utcb(utcb);
obj->_state.modified = false;
} else
utcb->mtd = 0;
obj->_state.thread.eflags = utcb->flags;
/* thread becomes blocked */
obj->_state.block();
/* switch on/off single step */
bool singlestep_state = obj->_state.thread.eflags & 0x100UL;
if (obj->_state.singlestep() && !singlestep_state) {
utcb->flags |= 0x100UL;
utcb->mtd |= Mtd::EFL;
} else if (!obj->_state.singlestep() && singlestep_state) {
utcb->flags &= ~0x100UL;
utcb->mtd |= Mtd::EFL;
}
/* deliver signal if it was requested */
if (obj->_state.to_submit())
obj->submit_exception_signal();
/* notify callers of cpu_session()->pause that the state is now valid */
if (obj->_state.notify_requested()) {
obj->_state.notify_cancel();
if (sm_ctrl(obj->sel_sm_notify(), SEMAPHORE_UP) != NOVA_OK)
PWRN("paused notification failed");
}
/* switch on/off single step */
bool singlestep_state = obj->_state.thread.eflags & 0x100UL;
if (obj->_state.singlestep() && !singlestep_state) {
utcb->flags = obj->_state.thread.eflags | 0x100UL;
utcb->mtd = Nova::Mtd(Mtd::EFL).value();
} else {
if (!obj->_state.singlestep() && singlestep_state) {
utcb->flags = obj->_state.thread.eflags & ~0x100UL;
utcb->mtd = Nova::Mtd(Mtd::EFL).value();
} else
utcb->mtd = 0;
}
/* block until cpu_session()->resume() respectively wake_up() call */
unsigned long sm = obj->_state.blocked() ? obj->sel_sm_block_pause() : 0;
obj->_state_lock.unlock();
utcb->set_msg_word(0);
reply(myself->stack_top(), obj->sel_sm_block());
reply(myself->stack_top(), sm);
}
@ -242,6 +233,14 @@ void Pager_object::_startup_handler(addr_t pager_obj)
utcb->sp = obj->_initial_esp;
utcb->mtd = Mtd::EIP | Mtd::ESP;
if (obj->_state.singlestep()) {
utcb->flags = 0x100UL;
utcb->mtd |= Mtd::EFL;
}
obj->_state.unblock();
utcb->set_msg_word(0);
reply(myself->stack_top());
@ -363,12 +362,16 @@ void Pager_object::_invoke_handler(addr_t pager_obj)
void Pager_object::wake_up()
{
Lock::Guard _state_lock_guard(_state_lock);
if (!_state.blocked())
return;
_state.thread.exception = false;
_state.unblock();
uint8_t res = sm_ctrl(sel_sm_block(), SEMAPHORE_UP);
uint8_t res = sm_ctrl(sel_sm_block_pause(), SEMAPHORE_UP);
if (res != NOVA_OK)
PWRN("canceling blocked client failed (thread sm)");
}
@ -389,9 +392,30 @@ void Pager_object::client_cancel_blocking()
}
uint8_t Pager_object::client_recall()
uint8_t Pager_object::client_recall(bool get_state_and_block)
{
return ec_ctrl(EC_RECALL, _state.sel_client_ec);
Lock::Guard _state_lock_guard(_state_lock);
return _unsynchronized_client_recall(get_state_and_block);
}
uint8_t Pager_object::_unsynchronized_client_recall(bool get_state_and_block)
{
enum { STATE_REQUESTED = 1 };
uint8_t res = ec_ctrl(EC_RECALL, _state.sel_client_ec,
get_state_and_block ? STATE_REQUESTED : ~0UL);
if (res != NOVA_OK)
return res;
if (get_state_and_block) {
Utcb *utcb = reinterpret_cast<Utcb *>(Thread::myself()->utcb());
_copy_state_from_utcb(utcb);
_state.block();
}
return res;
}
@ -522,7 +546,9 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap,
addr_t pd_sel = __core_pd_sel;
_state._status = 0;
_state.modified = false;
_state.sel_client_ec = Native_thread::INVALID_INDEX;
_state.block();
if (Native_thread::INVALID_INDEX == _selectors ||
Native_thread::INVALID_INDEX == _client_exc_pt_sel)
@ -575,14 +601,14 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap,
throw Region_map::Invalid_thread();
}
/* used to notify caller of as soon as pause succeeded */
res = Nova::create_sm(sel_sm_notify(), pd_sel, 0);
/* semaphore used to block paged thread during recall */
res = Nova::create_sm(sel_sm_block_pause(), pd_sel, 0);
if (res != Nova::NOVA_OK) {
throw Region_map::Invalid_thread();
}
/* semaphore used to block paged thread during page fault or recall */
res = Nova::create_sm(sel_sm_block(), pd_sel, 0);
/* semaphore used to block paged thread during OOM memory revoke */
res = Nova::create_sm(sel_sm_block_oom(), pd_sel, 0);
if (res != Nova::NOVA_OK) {
throw Region_map::Invalid_thread();
}
@ -662,7 +688,7 @@ uint8_t Pager_object::handle_oom(addr_t transfer_from,
/* if nothing helps try to revoke memory */
enum { REMOTE_REVOKE = true, PD_SELF = true };
Mem_crd crd_all(0, ~0U, Rights(true, true, true));
Nova::revoke(crd_all, PD_SELF, REMOTE_REVOKE, pd_sel(), sel_sm_block());
Nova::revoke(crd_all, PD_SELF, REMOTE_REVOKE, pd_sel(), sel_sm_block_oom());
/* re-request current kernel quota usage of target pd */
addr_t limit_after = 0, usage_after = 0;
@ -737,7 +763,7 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src,
if (policy == STOP) {
PERR("PD has insufficient kernel memory left - stop thread");
utcb->set_msg_word(0);
reply(myself->stack_top(), obj_dst->sel_sm_block());
reply(myself->stack_top(), obj_dst->sel_sm_block_pause());
}
char const * src_pd = "core";
@ -792,7 +818,7 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src,
/* else: caller will get blocked until RCU period is over */
/* block caller in semaphore */
reply(myself->stack_top(), obj_dst->sel_sm_block());
reply(myself->stack_top(), obj_dst->sel_sm_block_oom());
}

View File

@ -79,13 +79,10 @@ int Platform_thread::start(void *ip, void *sp)
_pager->assign_pd(_pd->pd_sel());
/* ip == 0 means that caller will use the thread as worker */
bool thread_global = ip;
uint8_t res;
do {
res = create_ec(_sel_ec(), _pd->pd_sel(), _location.xpos(),
utcb, initial_sp, _sel_exc_base, thread_global);
utcb, initial_sp, _sel_exc_base, !worker());
if (res == Nova::NOVA_PD_OOM && Nova::NOVA_OK != _pager->handle_oom()) {
_pager->assign_pd(Native_thread::INVALID_INDEX);
PERR("creation of new thread failed %u", res);
@ -93,9 +90,7 @@ int Platform_thread::start(void *ip, void *sp)
}
} while (res != Nova::NOVA_OK);
if (!thread_global) {
_features |= WORKER;
if (worker()) {
/* local/worker threads do not require a startup portal */
revoke(Obj_crd(_pager->exc_pt_sel_client() + PT_SEL_STARTUP, 0));
}
@ -201,23 +196,12 @@ int Platform_thread::start(void *ip, void *sp)
}
Native_capability Platform_thread::pause()
void Platform_thread::pause()
{
if (!_pager) return Native_capability();
if (!_pager)
return;
Native_capability notify_sm = _pager->notify_sm();
if (!notify_sm.valid()) return notify_sm;
if (_pager->client_recall() != Nova::NOVA_OK)
return Native_capability();
/* If the thread is blocked in its own SM, get him out */
cancel_blocking();
/* local thread may never get be canceled if it doesn't receive an IPC */
if (worker()) return Native_capability();
return notify_sm;
_pager->client_recall(true);
}
@ -256,37 +240,46 @@ Thread_state Platform_thread::state()
if (_pager->copy_thread_state(&s))
return s;
if (worker()) {
s.sp = _pager->initial_esp();
return s;
}
throw Cpu_thread::State_access_failed();
}
void Platform_thread::state(Thread_state s)
{
/* you can do it only once */
if (_sel_exc_base != Native_thread::INVALID_INDEX)
throw Cpu_thread::State_access_failed();
if (_sel_exc_base == Native_thread::INVALID_INDEX) {
/*
* s.sel_exc_base exception base of thread in caller
* protection domain - not in Core !
* s.vcpu If true it will run as vCPU,
* otherwise it will be a thread.
*/
if (!main_thread())
_sel_exc_base = s.sel_exc_base;
/* you can do it only once */
if (!s.vcpu)
return;
/*
* s.sel_exc_base exception base of thread in caller
* protection domain - not in Core !
* s.is_vcpu If true it will run as vCPU,
* otherwise it will be a thread.
*/
if (!main_thread())
_sel_exc_base = s.sel_exc_base;
_features |= VCPU;
if (!s.global_thread)
_features |= WORKER;
if (main_thread() && _pager)
_pager->prepare_vCPU_portals();
if (!s.vcpu)
return;
_features |= VCPU;
if (main_thread() && _pager)
_pager->prepare_vCPU_portals();
} else {
if (!_pager) throw Cpu_thread::State_access_failed();
if (!_pager->copy_thread_state(s))
throw Cpu_thread::State_access_failed();
/* the new state is transferred to the kernel by the recall handler */
_pager->client_recall(false);
}
}
@ -298,15 +291,11 @@ void Platform_thread::cancel_blocking()
}
Native_capability Platform_thread::single_step_sync(bool on)
void Platform_thread::single_step(bool on)
{
if (!_pager) return Native_capability();
if (!_pager) return;
Native_capability cap = _pager->single_step(on);
if (worker()) return Native_capability();
return cap;
_pager->single_step(on);
}

View File

@ -19,16 +19,42 @@
using namespace Genode;
void Pager_object::_copy_state(Nova::Utcb * utcb)
void Pager_object::_copy_state_from_utcb(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.eax = utcb->ax;
_state.thread.ecx = utcb->cx;
_state.thread.edx = utcb->dx;
_state.thread.ebx = utcb->bx;
_state.thread.gs = utcb->gs.sel;
_state.thread.fs = utcb->fs.sel;
_state.thread.ebp = utcb->bp;
_state.thread.esi = utcb->si;
_state.thread.edi = utcb->di;
_state.thread.sp = utcb->sp;
_state.thread.ip = utcb->ip;
_state.thread.eflags = utcb->flags;
_state.thread.exception = utcb->qual[0];
}
void Pager_object::_copy_state_to_utcb(Nova::Utcb * utcb)
{
utcb->ax = _state.thread.eax;
utcb->cx = _state.thread.ecx;
utcb->dx = _state.thread.edx;
utcb->bx = _state.thread.ebx;
utcb->bp = _state.thread.ebp;
utcb->si = _state.thread.esi;
utcb->di = _state.thread.edi;
utcb->sp = _state.thread.sp;
utcb->ip = _state.thread.ip;
utcb->flags = _state.thread.eflags;
utcb->mtd = Nova::Mtd::ACDB |
Nova::Mtd::EBSD |
Nova::Mtd::ESP |
Nova::Mtd::EIP |
Nova::Mtd::EFL;
}

View File

@ -19,24 +19,62 @@
using namespace Genode;
void Pager_object::_copy_state(Nova::Utcb * utcb)
void Pager_object::_copy_state_from_utcb(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.rax = utcb->ax;
_state.thread.rcx = utcb->cx;
_state.thread.rdx = utcb->dx;
_state.thread.rbx = utcb->bx;
_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.rbp = utcb->bp;
_state.thread.rsi = utcb->si;
_state.thread.rdi = utcb->di;
_state.thread.ss = utcb->ss.sel;
_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.sp = utcb->sp;
_state.thread.ip = utcb->ip;
_state.thread.eflags = utcb->flags;
_state.thread.exception = utcb->qual[0];
}
void Pager_object::_copy_state_to_utcb(Nova::Utcb * utcb)
{
utcb->ax = _state.thread.rax;
utcb->cx = _state.thread.rcx;
utcb->dx = _state.thread.rdx;
utcb->bx = _state.thread.rbx;
utcb->bp = _state.thread.rbp;
utcb->si = _state.thread.rsi;
utcb->di = _state.thread.rdi;
utcb->r8 = _state.thread.r8;
utcb->r9 = _state.thread.r9;
utcb->r10 = _state.thread.r10;
utcb->r11 = _state.thread.r11;
utcb->r12 = _state.thread.r12;
utcb->r13 = _state.thread.r13;
utcb->r14 = _state.thread.r14;
utcb->r15 = _state.thread.r15;
utcb->sp = _state.thread.sp;
utcb->ip = _state.thread.ip;
utcb->flags = _state.thread.eflags;
utcb->mtd = Nova::Mtd::ACDB |
Nova::Mtd::EBSD |
Nova::Mtd::R8_R15 |
Nova::Mtd::EIP |
Nova::Mtd::ESP |
Nova::Mtd::EFL;
}

View File

@ -9,7 +9,6 @@ SRC_CC = stack_area.cc \
core_region_map.cc \
core_rpc_cap_alloc.cc \
cpu_session_component.cc \
cpu_session_extension.cc \
cpu_session_support.cc \
cpu_thread_component.cc \
dataspace_component.cc \

View File

@ -215,8 +215,10 @@ Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size,
_pd_session(*pd_session)
{
/* set magic value evaluated by thread_nova.cc to start a local thread */
if (native_thread().ec_sel == Native_thread::INVALID_INDEX)
if (native_thread().ec_sel == Native_thread::INVALID_INDEX) {
native_thread().ec_sel = Native_thread::INVALID_INDEX - 1;
native_thread().initial_ip = (addr_t)&_activation_entry;
}
/* required to create a 'local' EC */
Thread::start();

View File

@ -29,7 +29,6 @@
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
#include <nova_cpu_session/connection.h>
using namespace Genode;
@ -159,11 +158,12 @@ void Thread::start()
/* create EC at core */
Thread_state state;
state.sel_exc_base = native_thread().exc_pt_sel;
state.vcpu = native_thread().vcpu;
state.sel_exc_base = native_thread().exc_pt_sel;
state.vcpu = native_thread().vcpu;
state.global_thread = global;
/* local thread have no start instruction pointer - set via portal entry */
addr_t thread_ip = global ? reinterpret_cast<addr_t>(_thread_start) : 0;
addr_t thread_ip = global ? reinterpret_cast<addr_t>(_thread_start) : native_thread().initial_ip;
Cpu_thread_client cpu_thread(_thread_cap);
try { cpu_thread.state(state); }

View File

@ -22,10 +22,11 @@ namespace Genode { struct Thread_state_base; }
struct Genode::Thread_state_base : Cpu_state
{
bool unresolved_page_fault;
bool unresolved_page_fault = false;
bool exception = false;
Thread_state_base() : unresolved_page_fault(false) { };
Thread_state_base(Cpu_state &c) : Cpu_state(c), unresolved_page_fault(false) { };
Thread_state_base() { };
Thread_state_base(Cpu_state &c) : Cpu_state(c) { };
};
#endif /* _INCLUDE__BASE__THREAD_STATE_BASE_H_ */

View File

@ -14,6 +14,12 @@
#include <debug.h>
#include <linker.h>
/*
* GDB can set a breakpoint at this function to find out when ldso has loaded
* the binary into memory.
*/
void binary_ready_hook_for_gdb() { }
/**
* C-break function for GDB
*/

View File

@ -27,6 +27,11 @@ namespace Linker {
void dump_link_map(Object *o);
}
/*
* GDB can set a breakpoint at this function to find out when ldso has loaded
* the binary into memory.
*/
void binary_ready_hook_for_gdb();
/**
* LIBC debug support

View File

@ -580,6 +580,8 @@ void Component::construct(Genode::Env &env)
Link_map::dump();
binary_ready_hook_for_gdb();
/* start binary */
binary->call_entry_point(env);
}

View File

@ -18,7 +18,6 @@
#include <base/cap_map.h>
#include <base/thread.h>
#include <cap_session/connection.h>
#include <nova_cpu_session/connection.h>
#include <cpu_session/connection.h>
#include <pd_session/connection.h>
#include <region_map/client.h>