diff --git a/base-hw/include/arm/base/syscall_types.h b/base-hw/include/arm/base/syscall_support.h
similarity index 64%
rename from base-hw/include/arm/base/syscall_types.h
rename to base-hw/include/arm/base/syscall_support.h
index 870082a32a..237501f1f9 100644
--- a/base-hw/include/arm/base/syscall_types.h
+++ b/base-hw/include/arm/base/syscall_support.h
@@ -1,5 +1,5 @@
/*
- * \brief Syscall declarations specific for ARM V7A systems
+ * \brief Syscall declarations specific for ARM systems
* \author Martin Stein
* \date 2011-11-30
*/
@@ -21,6 +21,19 @@ namespace Kernel
{
typedef Genode::uint32_t Syscall_arg;
typedef Genode::uint32_t Syscall_ret;
+
+ /**
+ * Thread registers that can be accessed via Access_thread_regs
+ */
+ struct Access_thread_regs_id
+ {
+ enum {
+ R0, R1, R2, R3, R4,
+ R5, R6, R7, R8, R9,
+ R10, R11, R12, SP, LR,
+ IP, CPSR, CPU_EXCEPTION
+ };
+ };
}
#endif /* _INCLUDE__ARM__BASE__SYSCALL_H_ */
diff --git a/base-hw/include/kernel/syscalls.h b/base-hw/include/kernel/syscalls.h
index 3e6a4fbd8a..b3185001a2 100644
--- a/base-hw/include/kernel/syscalls.h
+++ b/base-hw/include/kernel/syscalls.h
@@ -15,7 +15,7 @@
#define _INCLUDE__KERNEL__SYSCALLS_H_
/* Genode includes */
-#include
+#include
namespace Genode
{
@@ -49,8 +49,7 @@ namespace Kernel
GET_THREAD = 5,
CURRENT_THREAD_ID = 6,
YIELD_THREAD = 7,
- READ_THREAD_STATE = 18,
- WRITE_THREAD_STATE = 19,
+ ACCESS_THREAD_REGS = 37,
/* interprocess communication */
REQUEST_AND_WAIT = 8,
@@ -389,31 +388,47 @@ namespace Kernel
/**
- * Copy the current state of a thread to the callers UTCB
+ * Access plain member variables of a kernel thread-object
*
- * \param thread_id ID of the targeted thread
+ * \param thread_id kernel name of the targeted thread
+ * \param reads amount of read operations
+ * \param writes amount of write operations
+ * \param read_values base of value buffer for read operations
+ * \param write_values base of value buffer for write operations
*
- * Restricted to core threads. One can also read from its own context,
- * or any thread that is active in the meantime. In these cases
- * be aware of the fact, that the result reflects the thread
- * state that were backed at the last kernel entry of the thread.
- * The copy might be incoherent when this function returns because
- * the caller might get scheduled away before then.
+ * \retval 0 all operations done
+ * \retval >0 amount of undone operations
+ * \retval -1 failed to start processing operations
+ *
+ * Restricted to core threads. Operations are processed in order of the
+ * appearance of the register names in the callers UTCB. If reads = 0,
+ * read_values is of no relevance. If writes = 0, write_values is of no
+ * relevance.
+ *
+ * Expected structure at the callers UTCB base:
+ *
+ * 0 * sizeof(addr_t): read register name #1
+ * ... ...
+ * (reads - 1) * sizeof(addr_t): read register name #reads
+ * (reads - 0) * sizeof(addr_t): write register name #1
+ * ... ...
+ * (reads + writes - 1) * sizeof(addr_t): write register name #writes
+ *
+ * Expected structure at write_values:
+ *
+ * 0 * sizeof(addr_t): write value #1
+ * ... ...
+ * (writes - 1) * sizeof(addr_t): write value #writes
*/
- inline void read_thread_state(unsigned const thread_id) {
- syscall(READ_THREAD_STATE, (Syscall_arg)thread_id); }
-
-
- /**
- * Override the state of a thread with the callers UTCB content
- *
- * \param thread_id ID of the targeted thread
- *
- * Restricted to core threads. One can also write to its own context, or
- * to that of a thread that is active in the meantime.
- */
- inline void write_thread_state(unsigned const thread_id) {
- syscall(WRITE_THREAD_STATE, (Syscall_arg)thread_id); }
+ inline int access_thread_regs(unsigned const thread_id,
+ unsigned const reads,
+ unsigned const writes,
+ addr_t * const read_values,
+ addr_t * const write_values)
+ {
+ return syscall(ACCESS_THREAD_REGS, thread_id, reads, writes,
+ (Syscall_arg)read_values, (Syscall_arg)write_values);
+ }
/**
diff --git a/base-hw/src/base/arm/syscall.cc b/base-hw/src/base/arm/syscall.cc
index 33e9cb058d..bdbdef2371 100644
--- a/base-hw/src/base/arm/syscall.cc
+++ b/base-hw/src/base/arm/syscall.cc
@@ -161,3 +161,22 @@ Syscall_ret Kernel::syscall(Syscall_arg arg_0,
return result;
}
+
+/*************************
+ ** CPU-state utilities **
+ *************************/
+
+typedef Access_thread_regs_id Id;
+
+static addr_t const _cpu_state_regs[] = {
+ Id::R0, Id::R1, Id::R2, Id::R3, Id::R4, Id::R5, Id::R6, Id::R7,
+ Id::R8, Id::R9, Id::R10, Id::R11, Id::R12, Id::SP, Id::LR, Id::IP,
+ Id::CPSR, Id::CPU_EXCEPTION };
+
+addr_t const * cpu_state_regs() { return _cpu_state_regs; }
+
+
+size_t cpu_state_regs_length()
+{
+ return sizeof(_cpu_state_regs)/sizeof(_cpu_state_regs[0]);
+}
diff --git a/base-hw/src/core/arm/cpu_support.cc b/base-hw/src/core/arm/cpu_support.cc
new file mode 100644
index 0000000000..895998216d
--- /dev/null
+++ b/base-hw/src/core/arm/cpu_support.cc
@@ -0,0 +1,47 @@
+/*
+ * \brief CPU specific implementations of core
+ * \author Martin Stein
+ * \date 2013-11-11
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+/* core includes */
+#include
+
+using namespace Kernel;
+
+
+/********************
+ ** Kernel::Thread **
+ ********************/
+
+addr_t * Kernel::Thread::_reg(addr_t const id) const
+{
+ static addr_t * const _regs[] = {
+ (addr_t *)&r0,
+ (addr_t *)&r1,
+ (addr_t *)&r2,
+ (addr_t *)&r3,
+ (addr_t *)&r4,
+ (addr_t *)&r5,
+ (addr_t *)&r6,
+ (addr_t *)&r7,
+ (addr_t *)&r8,
+ (addr_t *)&r9,
+ (addr_t *)&r10,
+ (addr_t *)&r11,
+ (addr_t *)&r12,
+ (addr_t *)&sp,
+ (addr_t *)&lr,
+ (addr_t *)&ip,
+ (addr_t *)&cpsr,
+ (addr_t *)&cpu_exception
+ };
+ return id < sizeof(_regs)/sizeof(_regs[0]) ? _regs[id] : 0;
+}
diff --git a/base-hw/src/core/arndale/target.mk b/base-hw/src/core/arndale/target.mk
index aede21aeae..6c03e53921 100644
--- a/base-hw/src/core/arndale/target.mk
+++ b/base-hw/src/core/arndale/target.mk
@@ -13,7 +13,8 @@ INC_DIR += $(REP_DIR)/src/core/arndale
# add C++ sources
SRC_CC += platform_services.cc \
- platform_support.cc
+ platform_support.cc \
+ cpu_support.cc
# add assembly sources
SRC_S += mode_transition.s \
@@ -24,6 +25,7 @@ SRC_S += mode_transition.s \
vpath platform_services.cc $(BASE_DIR)/src/core
vpath platform_support.cc $(REP_DIR)/src/core/arndale
vpath mode_transition.s $(REP_DIR)/src/core/arm_v7
+vpath cpu_support.cc $(REP_DIR)/src/core/arm
vpath crt0.s $(REP_DIR)/src/core/arm
#
diff --git a/base-hw/src/core/cpu/arm.h b/base-hw/src/core/cpu/arm.h
index 128262a8f5..b15d5b078f 100644
--- a/base-hw/src/core/cpu/arm.h
+++ b/base-hw/src/core/cpu/arm.h
@@ -469,52 +469,6 @@ namespace Arm
uint32_t cidr; /* context ID register backup */
uint32_t section_table; /* base address of applied section table */
- /**
- * Copy CPU state data to 'c'
- */
- void read_cpu_state(Cpu_state * const s)
- {
- s->r0 = r0;
- s->r1 = r1;
- s->r2 = r2;
- s->r3 = r3;
- s->r4 = r4;
- s->r5 = r5;
- s->r6 = r6;
- s->r7 = r7;
- s->r8 = r8;
- s->r9 = r9;
- s->r10 = r10;
- s->r11 = r11;
- s->r12 = r12;
- s->sp = sp;
- s->lr = lr;
- s->ip = ip;
- }
-
- /**
- * Override CPU state with data from 'c'
- */
- void write_cpu_state(Cpu_state * const s)
- {
- r0 = s->r0;
- r1 = s->r1;
- r2 = s->r2;
- r3 = s->r3;
- r4 = s->r4;
- r5 = s->r5;
- r6 = s->r6;
- r7 = s->r7;
- r8 = s->r8;
- r9 = s->r9;
- r10 = s->r10;
- r11 = s->r11;
- r12 = s->r12;
- sp = s->sp;
- lr = s->lr;
- ip = s->ip;
- }
-
/**
* Get base of assigned translation lookaside buffer
*/
diff --git a/base-hw/src/core/imx31/target.mk b/base-hw/src/core/imx31/target.mk
index 61b732e5e3..5a2997e7ab 100644
--- a/base-hw/src/core/imx31/target.mk
+++ b/base-hw/src/core/imx31/target.mk
@@ -12,7 +12,8 @@ INC_DIR += $(REP_DIR)/src/core/imx31
# add C++ sources
SRC_CC += platform_services.cc \
- platform_support.cc
+ platform_support.cc \
+ cpu_support.cc
# add assembly sources
SRC_S += mode_transition.s \
@@ -23,6 +24,7 @@ SRC_S += mode_transition.s \
vpath platform_services.cc $(BASE_DIR)/src/core
vpath platform_support.cc $(REP_DIR)/src/core/imx31
vpath mode_transition.s $(REP_DIR)/src/core/arm_v6
+vpath cpu_support.cc $(REP_DIR)/src/core/arm
vpath crt0.s $(REP_DIR)/src/core/arm
#
diff --git a/base-hw/src/core/imx53/target.mk b/base-hw/src/core/imx53/target.mk
index 24629ca07c..31f068ebd6 100644
--- a/base-hw/src/core/imx53/target.mk
+++ b/base-hw/src/core/imx53/target.mk
@@ -13,7 +13,8 @@ INC_DIR += $(REP_DIR)/src/core/imx53
# add C++ sources
SRC_CC += platform_services.cc \
- platform_support.cc
+ platform_support.cc \
+ cpu_support.cc
# add assembly sources
SRC_S += mode_transition.s \
@@ -24,6 +25,7 @@ SRC_S += mode_transition.s \
vpath platform_services.cc $(BASE_DIR)/src/core
vpath platform_support.cc $(REP_DIR)/src/core/imx53
vpath mode_transition.s $(REP_DIR)/src/core/arm_v7
+vpath cpu_support.cc $(REP_DIR)/src/core/arm
vpath crt0.s $(REP_DIR)/src/core/arm
#
diff --git a/base-hw/src/core/include/platform_thread.h b/base-hw/src/core/include/platform_thread.h
index d1300f7eb2..054c73b91b 100644
--- a/base-hw/src/core/include/platform_thread.h
+++ b/base-hw/src/core/include/platform_thread.h
@@ -128,20 +128,12 @@ namespace Genode {
/**
* Get raw thread state
*/
- Thread_state state()
- {
- Kernel::read_thread_state(id());
- return *(Thread_state *)Thread_base::myself()->utcb()->base();
- };
+ Thread_state state();
/**
* Override raw thread state
*/
- void state(Thread_state s)
- {
- *(Thread_state *)Thread_base::myself()->utcb()->base() = s;
- Kernel::write_thread_state(id());
- };
+ void state(Thread_state s);
/**
* Return unique identification of this thread as faulter
diff --git a/base-hw/src/core/kernel/thread.cc b/base-hw/src/core/kernel/thread.cc
index 97b242aebe..7e7d6f8697 100644
--- a/base-hw/src/core/kernel/thread.cc
+++ b/base-hw/src/core/kernel/thread.cc
@@ -680,32 +680,6 @@ void Thread::_syscall_print_char()
}
-/**
- * Do specific syscall for this thread, for details see 'syscall.h'
- */
-void Thread::_syscall_read_thread_state()
-{
- assert(_core());
- Thread * const t = Thread::pool()->object(user_arg_1());
- if (!t) PDBG("Targeted thread unknown");
- Thread_state * const ts = (Thread_state *)_phys_utcb->base();
- t->Cpu::Context::read_cpu_state(ts);
-}
-
-
-/**
- * Do specific syscall for this thread, for details see 'syscall.h'
- */
-void Thread::_syscall_write_thread_state()
-{
- assert(_core());
- Thread * const t = Thread::pool()->object(user_arg_1());
- if (!t) PDBG("Targeted thread unknown");
- Thread_state * const ts = (Thread_state *)_phys_utcb->base();
- t->Cpu::Context::write_cpu_state(ts);
-}
-
-
/**
* Do specific syscall for this thread, for details see 'syscall.h'
*/
@@ -976,8 +950,6 @@ void Thread::_syscall()
case GET_THREAD: _syscall_get_thread(); return;
case CURRENT_THREAD_ID: _syscall_current_thread_id(); return;
case YIELD_THREAD: _syscall_yield_thread(); return;
- case READ_THREAD_STATE: _syscall_read_thread_state(); return;
- case WRITE_THREAD_STATE: _syscall_write_thread_state(); return;
case REQUEST_AND_WAIT: _syscall_request_and_wait(); return;
case REPLY: _syscall_reply(); return;
case WAIT_FOR_REQUEST: _syscall_wait_for_request(); return;
@@ -998,6 +970,7 @@ void Thread::_syscall()
case RUN_VM: _syscall_run_vm(); return;
case PAUSE_VM: _syscall_pause_vm(); return;
case KILL_PD: _syscall_kill_pd(); return;
+ case ACCESS_THREAD_REGS: _syscall_access_thread_regs(); return;
default:
PERR("invalid syscall");
_stop();
diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h
index f55b2d12af..9ff21b40fc 100644
--- a/base-hw/src/core/kernel/thread.h
+++ b/base-hw/src/core/kernel/thread.h
@@ -135,6 +135,38 @@ class Kernel::Thread
*/
void _syscall();
+ /**
+ * Read a thread register
+ *
+ * \param id kernel name of targeted thread register
+ * \param value read-value buffer
+ *
+ * \retval 0 succeeded
+ * \retval -1 failed
+ */
+ int _read_reg(addr_t const id, addr_t & value) const;
+
+ /**
+ * Override a thread register
+ *
+ * \param id kernel name of targeted thread register
+ * \param value write-value buffer
+ *
+ * \retval 0 succeeded
+ * \retval -1 failed
+ */
+ int _write_reg(addr_t const id, addr_t const value);
+
+ /**
+ * Map kernel names of thread registers to the corresponding data
+ *
+ * \param id kernel name of thread register
+ *
+ * \retval 0 failed
+ * \retval >0 pointer to register content
+ */
+ addr_t * _reg(addr_t const id) const;
+
/***************************************************
** Syscall backends, for details see 'syscall.h' **
@@ -158,8 +190,6 @@ class Kernel::Thread
void _syscall_update_pd();
void _syscall_update_region();
void _syscall_print_char();
- void _syscall_read_thread_state();
- void _syscall_write_thread_state();
void _syscall_new_signal_receiver();
void _syscall_new_signal_context();
void _syscall_await_signal();
@@ -171,6 +201,7 @@ class Kernel::Thread
void _syscall_new_vm();
void _syscall_run_vm();
void _syscall_pause_vm();
+ void _syscall_access_thread_regs();
/***************************
diff --git a/base-hw/src/core/panda/target.mk b/base-hw/src/core/panda/target.mk
index f32a7497e1..e68191709d 100644
--- a/base-hw/src/core/panda/target.mk
+++ b/base-hw/src/core/panda/target.mk
@@ -13,7 +13,8 @@ INC_DIR += $(REP_DIR)/src/core/panda
# add C++ sources
SRC_CC += platform_services.cc \
- platform_support.cc
+ platform_support.cc \
+ cpu_support.cc
# add assembly sources
SRC_S += mode_transition.s \
@@ -24,6 +25,7 @@ SRC_S += mode_transition.s \
vpath platform_support.cc $(REP_DIR)/src/core/panda
vpath platform_services.cc $(BASE_DIR)/src/core
vpath mode_transition.s $(REP_DIR)/src/core/arm_v7
+vpath cpu_support.cc $(REP_DIR)/src/core/arm
vpath crt0.s $(REP_DIR)/src/core/arm
#
diff --git a/base-hw/src/core/pbxa9/target.mk b/base-hw/src/core/pbxa9/target.mk
index f624601932..0b3d953f58 100644
--- a/base-hw/src/core/pbxa9/target.mk
+++ b/base-hw/src/core/pbxa9/target.mk
@@ -13,7 +13,8 @@ INC_DIR += $(REP_DIR)/src/core/pbxa9
# add C++ sources
SRC_CC += platform_services.cc \
- platform_support.cc
+ platform_support.cc \
+ cpu_support.cc
# add assembly sources
SRC_S += mode_transition.s \
@@ -24,6 +25,7 @@ SRC_S += mode_transition.s \
vpath platform_services.cc $(BASE_DIR)/src/core
vpath platform_support.cc $(REP_DIR)/src/core/pbxa9
vpath mode_transition.s $(REP_DIR)/src/core/arm_v7
+vpath cpu_support.cc $(REP_DIR)/src/core/arm
vpath crt0.s $(REP_DIR)/src/core/arm
#
diff --git a/base-hw/src/core/platform_thread.cc b/base-hw/src/core/platform_thread.cc
index cb183a6df2..155a3db224 100644
--- a/base-hw/src/core/platform_thread.cc
+++ b/base-hw/src/core/platform_thread.cc
@@ -212,3 +212,38 @@ Genode::Pager_object * Platform_thread::pager()
{
return _rm_client ? static_cast(_rm_client) : 0;
}
+
+
+addr_t const * cpu_state_regs();
+
+size_t cpu_state_regs_length();
+
+
+Thread_state Platform_thread::state()
+{
+ static addr_t const * const src = cpu_state_regs();
+ static size_t const length = cpu_state_regs_length();
+ static size_t const size = length * sizeof(src[0]);
+ void * dst = Thread_base::myself()->utcb()->base();
+ Genode::memcpy(dst, src, size);
+ Thread_state thread_state;
+ Cpu_state * const cpu_state = static_cast(&thread_state);
+ if (Kernel::access_thread_regs(id(), length, 0, (addr_t *)cpu_state, 0)) {
+ throw Cpu_session::State_access_failed();
+ }
+ return thread_state;
+};
+
+
+void Platform_thread::state(Thread_state thread_state)
+{
+ static addr_t const * const src = cpu_state_regs();
+ static size_t const length = cpu_state_regs_length();
+ static size_t const size = length * sizeof(src[0]);
+ void * dst = Thread_base::myself()->utcb()->base();
+ Genode::memcpy(dst, src, size);
+ Cpu_state * const cpu_state = static_cast(&thread_state);
+ if (Kernel::access_thread_regs(id(), 0, length, 0, (addr_t *)cpu_state)) {
+ throw Cpu_session::State_access_failed();
+ }
+};
diff --git a/base-hw/src/core/rpi/target.mk b/base-hw/src/core/rpi/target.mk
index dcb792293b..c788b6c1fe 100644
--- a/base-hw/src/core/rpi/target.mk
+++ b/base-hw/src/core/rpi/target.mk
@@ -12,7 +12,8 @@ INC_DIR += $(REP_DIR)/src/core/rpi
# add C++ sources
SRC_CC += platform_services.cc \
- platform_support.cc
+ platform_support.cc \
+ cpu_support.cc
# add assembly sources
SRC_S += mode_transition.s \
@@ -23,6 +24,7 @@ SRC_S += mode_transition.s \
vpath platform_services.cc $(BASE_DIR)/src/core
vpath platform_support.cc $(REP_DIR)/src/core/rpi
vpath mode_transition.s $(REP_DIR)/src/core/arm_v6
+vpath cpu_support.cc $(REP_DIR)/src/core/arm
vpath crt0.s $(REP_DIR)/src/core/arm
#
diff --git a/base-hw/src/core/vea9x4/target.inc b/base-hw/src/core/vea9x4/target.inc
index 6d9cff86fd..4c9de6f7f4 100644
--- a/base-hw/src/core/vea9x4/target.inc
+++ b/base-hw/src/core/vea9x4/target.inc
@@ -9,8 +9,9 @@
INC_DIR += $(REP_DIR)/src/core/vea9x4
# add C++ sources
-SRC_CC += platform_services.cc \
- platform_support.cc
+SRC_CC += platform_services.cc \
+ platform_support.cc \
+ cpu_support.cc
# add assembly sources
SRC_S += crt0.s \
@@ -31,6 +32,7 @@ endif
# declare source paths
vpath mode_transition.s $(REP_DIR)/src/core/arm_v7
vpath crt0.s $(REP_DIR)/src/core/arm
+vpath cpu_support.cc $(REP_DIR)/src/core/arm
# include less specific target parts
include $(REP_DIR)/src/core/target.inc