hw: provide and use syscall access_thread_regs

ref #935
This commit is contained in:
Martin Stein 2013-11-11 13:03:07 +01:00 committed by Norman Feske
parent 1c6c90fed5
commit 15a56bd682
16 changed files with 213 additions and 120 deletions

View File

@ -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_ */

View File

@ -15,7 +15,7 @@
#define _INCLUDE__KERNEL__SYSCALLS_H_
/* Genode includes */
#include <base/syscall_types.h>
#include <base/syscall_support.h>
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);
}
/**

View File

@ -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]);
}

View File

@ -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 <kernel/thread.h>
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;
}

View File

@ -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
#

View File

@ -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
*/

View File

@ -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
#

View File

@ -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
#

View File

@ -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

View File

@ -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();

View File

@ -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();
/***************************

View File

@ -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
#

View File

@ -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
#

View File

@ -212,3 +212,38 @@ Genode::Pager_object * Platform_thread::pager()
{
return _rm_client ? static_cast<Pager_object *>(_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<Cpu_state *>(&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<Cpu_state *>(&thread_state);
if (Kernel::access_thread_regs(id(), 0, length, 0, (addr_t *)cpu_state)) {
throw Cpu_session::State_access_failed();
}
};

View File

@ -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
#

View File

@ -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