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 870082a32..237501f1f 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 3e6a4fbd8..b3185001a 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 33e9cb058..bdbdef237 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 000000000..895998216 --- /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 aede21aea..6c03e5392 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 128262a8f..b15d5b078 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 61b732e5e..5a2997e7a 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 24629ca07..31f068ebd 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 d1300f7eb..054c73b91 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 97b242aeb..7e7d6f869 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 f55b2d12a..9ff21b40f 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 f32a7497e..e68191709 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 f62460193..0b3d953f5 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 cb183a6df..155a3db22 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 dcb792293..c788b6c1f 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 6d9cff86f..4c9de6f7f 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