diff --git a/repos/base-nova/include/base/thread_state.h b/repos/base-nova/include/base/thread_state.h
index 2dde3f60cc..97fea51799 100644
--- a/repos/base-nova/include/base/thread_state.h
+++ b/repos/base-nova/include/base/thread_state.h
@@ -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_ */
diff --git a/repos/base-nova/include/cpu_session/client.h b/repos/base-nova/include/cpu_session/client.h
deleted file mode 100644
index ea198a8a8e..0000000000
--- a/repos/base-nova/include/cpu_session/client.h
+++ /dev/null
@@ -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
-#include
-
-#include
-
-#include
-
-namespace Genode { struct Cpu_session_client; }
-
-
-struct Genode::Cpu_session_client : Rpc_client
-{
- explicit Cpu_session_client(Cpu_session_capability session)
- : Rpc_client(static_cap_cast(session)) { }
-
- Thread_capability
- create_thread(Capability pd, Name const &name,
- Affinity::Location affinity, Weight weight, addr_t utcb = 0) override {
- return call(pd, name, affinity, weight, utcb); }
-
- void kill_thread(Thread_capability thread) override {
- call(thread); }
-
- void exception_sigh(Signal_context_capability handler) override {
- call(handler); }
-
- Affinity::Space affinity_space() const override {
- return call(); }
-
- Dataspace_capability trace_control() override {
- return call(); }
-
- int ref_account(Cpu_session_capability session) override {
- return call(session); }
-
- int transfer_quota(Cpu_session_capability session, size_t amount) override {
- return call(session, amount); }
-
- Quota quota() override { return call(); }
-
- Capability native_cpu() override { return call(); }
-
- 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_ */
diff --git a/repos/base-nova/include/cpu_thread/client.h b/repos/base-nova/include/cpu_thread/client.h
new file mode 100644
index 0000000000..c233c4dd47
--- /dev/null
+++ b/repos/base-nova/include/cpu_thread/client.h
@@ -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
+#include
+
+namespace Genode { struct Cpu_thread_client; }
+
+
+struct Genode::Cpu_thread_client : Rpc_client
+{
+ explicit Cpu_thread_client(Thread_capability cap)
+ : Rpc_client(cap) { }
+
+ Dataspace_capability utcb() override {
+ return call(); }
+
+ void start(addr_t ip, addr_t sp) override {
+ call(ip, sp); }
+
+ void pause() override {
+
+ for (;;) {
+
+ call();
+
+ 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(); }
+
+ void cancel_blocking() override {
+ call(); }
+
+ Thread_state state() override {
+ return call(); }
+
+ void state(Thread_state const &state) override {
+ call(state); }
+
+ void exception_sigh(Signal_context_capability handler) override {
+ call(handler); }
+
+ void single_step(bool enabled) override {
+ call(enabled); }
+
+ void affinity(Affinity::Location location) override {
+ call(location); }
+
+ unsigned trace_control_index() override {
+ return call(); }
+
+ Dataspace_capability trace_buffer() override {
+ return call(); }
+
+ Dataspace_capability trace_policy() override {
+ return call(); }
+};
+
+#endif /* _INCLUDE__CPU_THREAD__CLIENT_H_ */
diff --git a/repos/base-nova/include/nova/native_thread.h b/repos/base-nova/include/nova/native_thread.h
index 3517a76195..83bf684666 100644
--- a/repos/base-nova/include/nova/native_thread.h
+++ b/repos/base-nova/include/nova/native_thread.h
@@ -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_ */
diff --git a/repos/base-nova/include/nova_cpu_session/connection.h b/repos/base-nova/include/nova_cpu_session/connection.h
deleted file mode 100644
index 28b7101477..0000000000
--- a/repos/base-nova/include/nova_cpu_session/connection.h
+++ /dev/null
@@ -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
-#include
-
-namespace Genode {
-
- struct Nova_cpu_connection : Connection, 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(
- session("priority=0x%lx, ram_quota=32K, label=\"%s\"",
- priority, label)),
- Cpu_session_client(cap()) { }
- };
-}
-
-#endif /* _INCLUDE__NOVA_CPU_SESSION__CONNECTION_H_ */
diff --git a/repos/base-nova/include/nova_cpu_session/nova_cpu_session.h b/repos/base-nova/include/nova_cpu_session/nova_cpu_session.h
deleted file mode 100644
index f3cf22d46f..0000000000
--- a/repos/base-nova/include/nova_cpu_session/nova_cpu_session.h
+++ /dev/null
@@ -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
-#include
-
-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_ */
diff --git a/repos/base-nova/ports/nova.hash b/repos/base-nova/ports/nova.hash
index a94fc0dfd0..da0118efec 100644
--- a/repos/base-nova/ports/nova.hash
+++ b/repos/base-nova/ports/nova.hash
@@ -1 +1 @@
-5d57765b0abab82acc9d0725bbd30329905751e2
+b27175ffa51a7e3c19784f2789e5ab0fb37034f3
diff --git a/repos/base-nova/ports/nova.port b/repos/base-nova/ports/nova.port
index be5ab823c8..eeda9d8a0e 100644
--- a/repos/base-nova/ports/nova.port
+++ b/repos/base-nova/ports/nova.port
@@ -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)
diff --git a/repos/base-nova/src/core/cpu_session_extension.cc b/repos/base-nova/src/core/cpu_session_extension.cc
deleted file mode 100644
index af09380ba9..0000000000
--- a/repos/base-nova/src/core/cpu_session_extension.cc
+++ /dev/null
@@ -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
-
-/* core-local includes */
-#include
-
-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);
-}
diff --git a/repos/base-nova/src/core/include/cpu_session_component.h b/repos/base-nova/src/core/include/cpu_session_component.h
index 0038c04370..5802e6aac2 100644
--- a/repos/base-nova/src/core/include/cpu_session_component.h
+++ b/repos/base-nova/src/core/include/cpu_session_component.h
@@ -22,7 +22,6 @@
#include
#include
#include
-#include
/* core includes */
#include
@@ -37,7 +36,7 @@
namespace Genode { class Cpu_session_component; }
-class Genode::Cpu_session_component : public Rpc_object
+class Genode::Cpu_session_component : public Rpc_object
{
public:
@@ -150,14 +149,6 @@ class Genode::Cpu_session_component : public Rpc_object
Quota quota() override;
Capability 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_ */
diff --git a/repos/base-nova/src/core/include/pager.h b/repos/base-nova/src/core/include/pager.h
index 247ffbe8c0..87958f1c5a 100644
--- a/repos/base-nova/src/core/include/pager.h
+++ b/repos/base-nova/src/core/include/pager.h
@@ -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(_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;
}
diff --git a/repos/base-nova/src/core/include/platform_thread.h b/repos/base-nova/src/core/include/platform_thread.h
index a470342395..599ccab876 100644
--- a/repos/base-nova/src/core/include/platform_thread.h
+++ b/repos/base-nova/src/core/include/platform_thread.h
@@ -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'
*/
diff --git a/repos/base-nova/src/core/pager.cc b/repos/base-nova/src/core/pager.cc
index ed7efc4a19..e54898b897 100644
--- a/repos/base-nova/src/core/pager.cc
+++ b/repos/base-nova/src/core/pager.cc
@@ -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(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_obj);
Utcb * utcb = reinterpret_cast(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(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());
}
diff --git a/repos/base-nova/src/core/platform_thread.cc b/repos/base-nova/src/core/platform_thread.cc
index df24a21845..233bf4264c 100644
--- a/repos/base-nova/src/core/platform_thread.cc
+++ b/repos/base-nova/src/core/platform_thread.cc
@@ -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);
}
diff --git a/repos/base-nova/src/core/spec/x86_32/pager.cc b/repos/base-nova/src/core/spec/x86_32/pager.cc
index 13f618532f..2d54fb34a3 100644
--- a/repos/base-nova/src/core/spec/x86_32/pager.cc
+++ b/repos/base-nova/src/core/spec/x86_32/pager.cc
@@ -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;
}
diff --git a/repos/base-nova/src/core/spec/x86_64/pager.cc b/repos/base-nova/src/core/spec/x86_64/pager.cc
index c268660ca0..b954669d25 100644
--- a/repos/base-nova/src/core/spec/x86_64/pager.cc
+++ b/repos/base-nova/src/core/spec/x86_64/pager.cc
@@ -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;
}
diff --git a/repos/base-nova/src/core/target.inc b/repos/base-nova/src/core/target.inc
index 02ddda7186..3b35d62c0b 100644
--- a/repos/base-nova/src/core/target.inc
+++ b/repos/base-nova/src/core/target.inc
@@ -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 \
diff --git a/repos/base-nova/src/lib/base/rpc_entrypoint.cc b/repos/base-nova/src/lib/base/rpc_entrypoint.cc
index ad4f786293..8c79254acd 100644
--- a/repos/base-nova/src/lib/base/rpc_entrypoint.cc
+++ b/repos/base-nova/src/lib/base/rpc_entrypoint.cc
@@ -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();
diff --git a/repos/base-nova/src/lib/base/thread_start.cc b/repos/base-nova/src/lib/base/thread_start.cc
index 31c0703563..ffcb6de30b 100644
--- a/repos/base-nova/src/lib/base/thread_start.cc
+++ b/repos/base-nova/src/lib/base/thread_start.cc
@@ -29,7 +29,6 @@
/* NOVA includes */
#include
#include
-#include
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(_thread_start) : 0;
+ addr_t thread_ip = global ? reinterpret_cast(_thread_start) : native_thread().initial_ip;
Cpu_thread_client cpu_thread(_thread_cap);
try { cpu_thread.state(state); }
diff --git a/repos/base/include/base/thread_state_base.h b/repos/base/include/base/thread_state_base.h
index f863119b39..690a82169c 100644
--- a/repos/base/include/base/thread_state_base.h
+++ b/repos/base/include/base/thread_state_base.h
@@ -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_ */
diff --git a/repos/base/src/lib/ldso/debug.cc b/repos/base/src/lib/ldso/debug.cc
index 7bc6e36d02..8a4e0ec093 100644
--- a/repos/base/src/lib/ldso/debug.cc
+++ b/repos/base/src/lib/ldso/debug.cc
@@ -14,6 +14,12 @@
#include
#include
+/*
+ * 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
*/
diff --git a/repos/base/src/lib/ldso/include/debug.h b/repos/base/src/lib/ldso/include/debug.h
index c315962190..9b3b954e92 100644
--- a/repos/base/src/lib/ldso/include/debug.h
+++ b/repos/base/src/lib/ldso/include/debug.h
@@ -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
diff --git a/repos/base/src/lib/ldso/main.cc b/repos/base/src/lib/ldso/main.cc
index ae9dbc4429..8c799e22bb 100644
--- a/repos/base/src/lib/ldso/main.cc
+++ b/repos/base/src/lib/ldso/main.cc
@@ -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);
}
diff --git a/repos/ports/include/vmm/vcpu_thread.h b/repos/ports/include/vmm/vcpu_thread.h
index a04096d7d2..23d78d5dba 100644
--- a/repos/ports/include/vmm/vcpu_thread.h
+++ b/repos/ports/include/vmm/vcpu_thread.h
@@ -18,7 +18,6 @@
#include
#include
#include
-#include
#include
#include
#include