hw: simplify Kernel::start_thread

Instead of writing initial thread context to the platform-thread members
and then communicating this core object to kernel, core calls
Kernel::access_thread_regs first to initialize thread context and then
Kernel::start_thread without a platform-thread pointer. This way
the frontend as well as the backend of Kernel::start_thread loose
complexity and it is a first step to remove platform thread from the
vocabulary of the kernel.

ref #953
This commit is contained in:
Martin Stein 2013-11-18 12:47:14 +01:00 committed by Norman Feske
parent 77f55232fd
commit 210216e5e1
8 changed files with 95 additions and 143 deletions

View File

@ -19,6 +19,7 @@
namespace Genode namespace Genode
{ {
class Native_utcb;
class Platform_thread; class Platform_thread;
class Platform_pd; class Platform_pd;
class Tlb; class Tlb;
@ -31,6 +32,7 @@ namespace Kernel
typedef Genode::size_t size_t; typedef Genode::size_t size_t;
typedef Genode::Platform_thread Platform_thread; typedef Genode::Platform_thread Platform_thread;
typedef Genode::Platform_pd Platform_pd; typedef Genode::Platform_pd Platform_pd;
typedef Genode::Native_utcb Native_utcb;
/** /**
* Kernel names of all kernel calls * Kernel names of all kernel calls
@ -232,23 +234,20 @@ namespace Kernel
/** /**
* Start thread with a given context and let it participate in CPU scheduling * Start executing a thread
* *
* \param id ID of targeted thread * \param thread_id kernel name of targeted thread
* \param ip initial instruction pointer * \param cpu_id kernel name of targeted processor
* \param sp initial stack pointer * \param pd_id kernel name of targeted protection domain
* * \param utcb core local pointer to userland thread-context
* \retval >0 success, return value is the TLB of the thread
* \retval 0 the targeted thread wasn't started or was already started
* when this gets called (in both cases it remains untouched)
* *
* Restricted to core threads. * Restricted to core threads.
*/ */
inline Tlb * start_thread(Platform_thread * const phys_pt, void * const ip, inline Tlb * start_thread(unsigned const thread_id, unsigned const cpu_id,
void * const sp, unsigned const cpu_no) unsigned const pd_id, Native_utcb * const utcb)
{ {
return (Tlb *)call(Call_id::START_THREAD, (Call_arg)phys_pt, return (Tlb *)call(Call_id::START_THREAD, thread_id, cpu_id, pd_id,
(Call_arg)ip, (Call_arg)sp, cpu_no); (Call_arg)utcb);
} }

View File

@ -517,61 +517,17 @@ namespace Arm
unsigned user_arg_7() const { return r7; } unsigned user_arg_7() const { return r7; }
/** /**
* Part of context init that is common for all types of threads * Initialize thread context
*
* \param tlb physical base of appropriate page table
* \param pd_id kernel name of appropriate protection domain
*/ */
void init_thread_common(void * const instr_p, void init_thread(addr_t const tlb, unsigned const pd_id)
addr_t const tlb,
unsigned const pd_id)
{ {
ip = (addr_t)instr_p;
cidr = pd_id; cidr = pd_id;
section_table = tlb; section_table = tlb;
} }
/**
* Init context of the first thread of core
*/
void init_core_main_thread(void * const instr_p,
void * const stack_p,
addr_t const tlb,
unsigned const pd_id)
{
sp = (addr_t)stack_p;
init_thread_common(instr_p, tlb, pd_id);
}
/**
* Init context of a thread that isn't first thread of a program
*/
void init_thread(void * const instr_p,
void * const stack_p,
addr_t const tlb,
unsigned const pd_id)
{
sp = (addr_t)stack_p;
init_thread_common(instr_p, tlb, pd_id);
}
/**
* Init context of the first thread of a program other than core
*/
void init_main_thread(void * const instr_p,
void * const utcb_virt,
addr_t const tlb,
unsigned const pd_id)
{
/*
* Normally threads receive their UTCB pointer through their
* 'Thread_base' but the first thread of a program doesn't
* have such object. Thus the kernel hands out the UTCB pointer
* through the main threads initial CPU context. 'crt0.s' then
* can save the received pointer to local mem before polluting
* the CPU context.
*/
sp = (addr_t)utcb_virt;
init_thread_common(instr_p, tlb, pd_id);
}
/** /**
* Return if the context is in a page fault due to a translation miss * Return if the context is in a page fault due to a translation miss
* *

View File

@ -48,8 +48,8 @@ namespace Genode {
Weak_ptr<Address_space> _address_space; Weak_ptr<Address_space> _address_space;
unsigned _id; unsigned _id;
Rm_client * _rm_client; Rm_client * _rm_client;
Native_utcb * _phys_utcb; Native_utcb * _utcb_phys;
Native_utcb * _virt_utcb; Native_utcb * _utcb_virt;
Tlb * _tlb; Tlb * _tlb;
Ram_dataspace_capability _utcb; Ram_dataspace_capability _utcb;
char _name[NAME_MAX_LEN]; char _name[NAME_MAX_LEN];
@ -109,8 +109,12 @@ namespace Genode {
/** /**
* Run this thread * Run this thread
*
* \param ip initial instruction pointer
* \param sp initial stack pointer
* \param cpu_id kernel name of targeted CPU
*/ */
int start(void * ip, void * sp, unsigned int cpu_no = 0); int start(void * const ip, void * const sp, unsigned const cpu_id = 0);
/** /**
* Pause this thread * Pause this thread
@ -182,9 +186,9 @@ namespace Genode {
return _thread_base; return _thread_base;
} }
Native_utcb * phys_utcb() const { return _phys_utcb; } Native_utcb * utcb_phys() const { return _utcb_phys; }
Native_utcb * virt_utcb() const { return _virt_utcb; } Native_utcb * utcb_virt() const { return _utcb_virt; }
Ram_dataspace_capability utcb() const { return _utcb; } Ram_dataspace_capability utcb() const { return _utcb; }

View File

@ -119,9 +119,9 @@ namespace Kernel
static bool init = 0; static bool init = 0;
if (!init) { if (!init) {
enum { STACK_SIZE = sizeof(idle_stack)/sizeof(idle_stack[0]) }; enum { STACK_SIZE = sizeof(idle_stack)/sizeof(idle_stack[0]) };
void * const ip = (void *)&idle_main; idle.ip = (addr_t)&idle_main;;
void * const sp = (void *)&idle_stack[STACK_SIZE]; idle.sp = (addr_t)&idle_stack[STACK_SIZE];;
idle.init(ip, sp, 0, core_id(), 0, 0, 0, 0); idle.init(0, core_id(), 0, 0);
init = 1; init = 1;
} }
/* create CPU scheduler with a permanent idle thread */ /* create CPU scheduler with a permanent idle thread */
@ -231,12 +231,12 @@ extern "C" void kernel()
*(Core_thread_id *)s = 0; *(Core_thread_id *)s = 0;
/* start thread with stack pointer at the top of stack */ /* start thread with stack pointer at the top of stack */
void * const sp = (void *)((addr_t)s + STACK_SIZE);
void * const ip = (void *)CORE_MAIN;
static Native_utcb utcb; static Native_utcb utcb;
_main_utcb = &utcb; _main_utcb = &utcb;
static Thread t((Platform_thread *)0); static Thread t((Platform_thread *)0);
t.init(ip, sp, 0, core_id(), &utcb, &utcb, 1, 1); t.ip = (addr_t)CORE_MAIN;;
t.sp = (addr_t)s + STACK_SIZE;
t.init(0, core_id(), &utcb, 1);
} }
/* kernel initialization finished */ /* kernel initialization finished */
init_platform(); init_platform();

View File

@ -75,8 +75,8 @@ void Thread::_await_signal(Signal_receiver * const receiver)
void Thread::_receive_signal(void * const base, size_t const size) void Thread::_receive_signal(void * const base, size_t const size)
{ {
assert(_state == AWAITS_SIGNAL && size <= _phys_utcb->size()); assert(_state == AWAITS_SIGNAL && size <= _utcb_phys->size());
Genode::memcpy(_phys_utcb->base(), base, size); Genode::memcpy(_utcb_phys->base(), base, size);
_schedule(); _schedule();
} }
@ -191,17 +191,14 @@ Thread::Thread(Platform_thread * const pt)
_platform_thread(pt), _platform_thread(pt),
_state(AWAITS_START), _state(AWAITS_START),
_pd(0), _pd(0),
_phys_utcb(0), _utcb_phys(0),
_virt_utcb(0),
_signal_receiver(0) _signal_receiver(0)
{ } { }
void void
Thread::init(void * const ip, void * const sp, unsigned const cpu_id, Thread::init(unsigned const cpu_id, unsigned const pd_id_arg,
unsigned const pd_id_arg, Native_utcb * const utcb_phys, Native_utcb * const utcb_phys, bool const start)
Native_utcb * const utcb_virt, bool const main,
bool const start)
{ {
assert(_state == AWAITS_START) assert(_state == AWAITS_START)
@ -209,19 +206,13 @@ Thread::init(void * const ip, void * const sp, unsigned const cpu_id,
if (cpu_id) { PERR("multicore processing not supported"); } if (cpu_id) { PERR("multicore processing not supported"); }
/* store thread parameters */ /* store thread parameters */
_phys_utcb = utcb_phys; _utcb_phys = utcb_phys;
_virt_utcb = utcb_virt;
/* join protection domain */ /* join protection domain */
_pd = Pd::pool()->object(pd_id_arg); _pd = Pd::pool()->object(pd_id_arg);
assert(_pd); assert(_pd);
addr_t const tlb = _pd->tlb()->base(); addr_t const tlb = _pd->tlb()->base();
User_context::init_thread(tlb, pd_id());
/* initialize CPU context */
User_context * const c = static_cast<User_context *>(this);
if (!main) { c->init_thread(ip, sp, tlb, pd_id()); }
else if (!_core()) { c->init_main_thread(ip, utcb_virt, tlb, pd_id()); }
else { c->init_core_main_thread(ip, sp, tlb, pd_id()); }
/* print log message */ /* print log message */
if (START_VERBOSE) { if (START_VERBOSE) {
@ -282,7 +273,7 @@ void Thread::proceed()
char const * Kernel::Thread::label() const char const * Kernel::Thread::label() const
{ {
if (!platform_thread()) { if (!platform_thread()) {
if (!_phys_utcb) { return "idle"; } if (!_utcb_phys) { return "idle"; }
return "core"; return "core";
} }
return platform_thread()->name(); return platform_thread()->name();
@ -377,24 +368,26 @@ void Thread::_call_delete_thread()
void Thread::_call_start_thread() void Thread::_call_start_thread()
{ {
/* check permissions */ /* check permissions */
assert(_core()); if (!_core()) {
PERR("not entitled to start thread");
user_arg_0(0);
return;
}
/* dispatch arguments */ /* dispatch arguments */
Platform_thread * pt = (Platform_thread *)user_arg_1(); unsigned const thread_id = user_arg_1();
void * const ip = (void *)user_arg_2(); unsigned const cpu_id = user_arg_2();
void * const sp = (void *)user_arg_3(); unsigned const pd_id = user_arg_3();
unsigned const cpu_id = (unsigned)user_arg_4(); Native_utcb * const utcb = (Native_utcb *)user_arg_4();
/* get targeted thread */
Thread * const t = Thread::pool()->object(pt->id());
assert(t);
/* lookup targeted thread */
Thread * const t = Thread::pool()->object(thread_id);
if (!t) {
PERR("unknown thread");
user_arg_0(0);
return;
}
/* start thread */ /* start thread */
unsigned const pd_id = pt->pd_id(); t->init(cpu_id, pd_id, utcb, 1);
Native_utcb * const utcb_p = pt->phys_utcb();
Native_utcb * const utcb_v = pt->virt_utcb();
bool const main = pt->main_thread();
t->init(ip, sp, cpu_id, pd_id, utcb_p, utcb_v, main, 1);
user_arg_0((Call_ret)t->_pd->tlb()); user_arg_0((Call_ret)t->_pd->tlb());
} }
@ -475,7 +468,7 @@ void Thread::_call_wait_for_request()
{ {
void * buf_base; void * buf_base;
size_t buf_size; size_t buf_size;
_phys_utcb->call_wait_for_request(buf_base, buf_size); _utcb_phys->call_wait_for_request(buf_base, buf_size);
Ipc_node::await_request(buf_base, buf_size); Ipc_node::await_request(buf_base, buf_size);
} }
@ -492,7 +485,7 @@ void Thread::_call_request_and_wait()
size_t msg_size; size_t msg_size;
void * buf_base; void * buf_base;
size_t buf_size; size_t buf_size;
_phys_utcb->call_request_and_wait(msg_base, msg_size, _utcb_phys->call_request_and_wait(msg_base, msg_size,
buf_base, buf_size); buf_base, buf_size);
Ipc_node::send_request_await_reply(dst, msg_base, msg_size, Ipc_node::send_request_await_reply(dst, msg_base, msg_size,
buf_base, buf_size); buf_base, buf_size);
@ -503,7 +496,7 @@ void Thread::_call_reply()
{ {
void * msg_base; void * msg_base;
size_t msg_size; size_t msg_size;
_phys_utcb->call_reply(msg_base, msg_size); _utcb_phys->call_reply(msg_base, msg_size);
Ipc_node::send_reply(msg_base, msg_size); Ipc_node::send_reply(msg_base, msg_size);
bool const await_request = user_arg_1(); bool const await_request = user_arg_1();
if (await_request) { _call_wait_for_request(); } if (await_request) { _call_wait_for_request(); }
@ -590,7 +583,7 @@ void Thread::_call_access_thread_regs()
/* execute read operations */ /* execute read operations */
unsigned const reads = user_arg_2(); unsigned const reads = user_arg_2();
unsigned const writes = user_arg_3(); unsigned const writes = user_arg_3();
addr_t * const utcb = (addr_t *)_phys_utcb->base(); addr_t * const utcb = (addr_t *)_utcb_phys->base();
addr_t * const read_ids = &utcb[0]; addr_t * const read_ids = &utcb[0];
addr_t * const read_values = (addr_t *)user_arg_4(); addr_t * const read_values = (addr_t *)user_arg_4();
for (unsigned i = 0; i < reads; i++) { for (unsigned i = 0; i < reads; i++) {

View File

@ -81,8 +81,7 @@ class Kernel::Thread
Platform_thread * const _platform_thread; Platform_thread * const _platform_thread;
State _state; State _state;
Pd * _pd; Pd * _pd;
Native_utcb * _phys_utcb; Native_utcb * _utcb_phys;
Native_utcb * _virt_utcb;
Signal_receiver * _signal_receiver; Signal_receiver * _signal_receiver;
/** /**
@ -263,19 +262,13 @@ class Kernel::Thread
/** /**
* Prepare thread to get scheduled the first time * Prepare thread to get scheduled the first time
* *
* \param ip initial instruction pointer * \param cpu_id kernel name of targeted processor
* \param sp initial stack pointer * \param pd_id kernel name of target protection domain
* \param cpu_id target cpu * \param utcb core local pointer to userland thread-context
* \param pd_id target protection-domain * \param start wether to start executing the thread
* \param utcb_phys physical UTCB pointer
* \param utcb_virt virtual UTCB pointer
* \param main wether the thread is the first one in its PD
* \param start wether to start execution
*/ */
void init(void * const ip, void * const sp, unsigned const cpu_id, void init(unsigned const cpu_id, unsigned const pd_id,
unsigned const pd_id, Native_utcb * const utcb_phys, Native_utcb * const utcb, bool const start);
Native_utcb * const utcb_virt, bool const main,
bool const start);
/*********************** /***********************

View File

@ -46,13 +46,13 @@ Platform_thread::~Platform_thread()
/* the RM client may be destructed before platform thread */ /* the RM client may be destructed before platform thread */
if (_rm_client) { if (_rm_client) {
Rm_session_component * const rm = _rm_client->member_rm_session(); Rm_session_component * const rm = _rm_client->member_rm_session();
rm->detach(_virt_utcb); rm->detach(utcb_virt());
} }
} }
/* free UTCB */ /* free UTCB */
if (_pd_id == Kernel::core_id()) { if (_pd_id == Kernel::core_id()) {
Range_allocator * const ram = platform()->ram_alloc(); Range_allocator * const ram = platform()->ram_alloc();
ram->free((void *)_phys_utcb, sizeof(Native_utcb)); ram->free(utcb_phys(), sizeof(Native_utcb));
} else { } else {
Ram_session_component * const ram = Ram_session_component * const ram =
dynamic_cast<Ram_session_component *>(core_env()->ram_session()); dynamic_cast<Ram_session_component *>(core_env()->ram_session());
@ -77,7 +77,7 @@ Platform_thread::Platform_thread(const char * name,
size_t const stack_size, unsigned const pd_id) size_t const stack_size, unsigned const pd_id)
: :
_thread_base(thread_base), _stack_size(stack_size), _thread_base(thread_base), _stack_size(stack_size),
_pd_id(pd_id), _rm_client(0), _virt_utcb(0), _pd_id(pd_id), _rm_client(0), _utcb_virt(0),
_priority(Kernel::Priority::MAX), _priority(Kernel::Priority::MAX),
_main_thread(0) _main_thread(0)
{ {
@ -85,13 +85,13 @@ Platform_thread::Platform_thread(const char * name,
/* create UTCB for a core thread */ /* create UTCB for a core thread */
Range_allocator * const ram = platform()->ram_alloc(); Range_allocator * const ram = platform()->ram_alloc();
if (!ram->alloc_aligned(sizeof(Native_utcb), (void **)&_phys_utcb, if (!ram->alloc_aligned(sizeof(Native_utcb), (void **)&_utcb_phys,
MIN_MAPPING_SIZE_LOG2).is_ok()) MIN_MAPPING_SIZE_LOG2).is_ok())
{ {
PERR("failed to allocate UTCB"); PERR("failed to allocate UTCB");
throw Cpu_session::Out_of_metadata(); throw Cpu_session::Out_of_metadata();
} }
_virt_utcb = _phys_utcb; _utcb_virt = _utcb_phys;
/* common constructor parts */ /* common constructor parts */
_init(); _init();
@ -102,7 +102,7 @@ Platform_thread::Platform_thread(const char * name, unsigned int priority,
addr_t utcb) addr_t utcb)
: :
_thread_base(0), _stack_size(0), _pd_id(0), _rm_client(0), _thread_base(0), _stack_size(0), _pd_id(0), _rm_client(0),
_virt_utcb((Native_utcb *)utcb), _utcb_virt((Native_utcb *)utcb),
_priority(Cpu_session::scale_priority(Kernel::Priority::MAX, priority)), _priority(Cpu_session::scale_priority(Kernel::Priority::MAX, priority)),
_main_thread(0) _main_thread(0)
{ {
@ -121,7 +121,7 @@ Platform_thread::Platform_thread(const char * name, unsigned int priority,
PERR("failed to allocate UTCB"); PERR("failed to allocate UTCB");
throw Cpu_session::Out_of_metadata(); throw Cpu_session::Out_of_metadata();
} }
_phys_utcb = (Native_utcb *)ram->phys_addr(_utcb); _utcb_phys = (Native_utcb *)ram->phys_addr(_utcb);
/* common constructor parts */ /* common constructor parts */
_init(); _init();
@ -155,21 +155,14 @@ void Platform_thread::_init()
} }
int Platform_thread::start(void * ip, void * sp, unsigned int cpu_no) int Platform_thread::start(void * const ip, void * const sp,
unsigned int const cpu_id)
{ {
/* must be in a PD to get started */
if (!_pd_id) {
PERR("invalid PD");
return -1;
}
/* attach UTCB if the thread can't do this by itself */ /* attach UTCB if the thread can't do this by itself */
if (!_attaches_utcb_by_itself()) if (!_attaches_utcb_by_itself())
{ {
/* /* declare page aligned virtual UTCB outside the context area */
* Declare page aligned virtual UTCB outside the context area. _utcb_virt = (Native_utcb *)((platform()->vm_start()
* Kernel afterwards offers this as bootstrap argument to the thread.
*/
_virt_utcb = (Native_utcb *)((platform()->vm_start()
+ platform()->vm_size() - sizeof(Native_utcb)) + platform()->vm_size() - sizeof(Native_utcb))
& ~((1<<MIN_MAPPING_SIZE_LOG2)-1)); & ~((1<<MIN_MAPPING_SIZE_LOG2)-1));
@ -179,14 +172,28 @@ int Platform_thread::start(void * ip, void * sp, unsigned int cpu_no)
return -1; return -1;
}; };
Rm_session_component * const rm = _rm_client->member_rm_session(); Rm_session_component * const rm = _rm_client->member_rm_session();
try { rm->attach(_utcb, 0, 0, true, _virt_utcb, 0); } try { rm->attach(_utcb, 0, 0, true, _utcb_virt, 0); }
catch (...) { catch (...) {
PERR("failed to attach UTCB"); PERR("failed to attach UTCB");
return -1; return -1;
} }
} }
/* initialize thread regisers */
typedef Kernel::Thread_reg_id Reg_id;
enum { WRITES = 2 };
addr_t * write_regs = (addr_t *)Thread_base::myself()->utcb()->base();
write_regs[0] = Reg_id::IP;
write_regs[1] = Reg_id::SP;
addr_t write_values[] = {
(addr_t)ip,
main_thread() ? (addr_t)_utcb_virt : (addr_t)sp
};
if (Kernel::access_thread_regs(id(), 0, WRITES, 0, write_values)) {
PERR("failed to initialize thread registers");
return -1;
}
/* let thread participate in CPU scheduling */ /* let thread participate in CPU scheduling */
_tlb = Kernel::start_thread(this, ip, sp, cpu_no); _tlb = Kernel::start_thread(id(), cpu_id, _pd_id, utcb_phys());
if (!_tlb) { if (!_tlb) {
PERR("failed to start thread"); PERR("failed to start thread");
return -1; return -1;

View File

@ -33,7 +33,7 @@ Native_utcb * Thread_base::utcb()
if (!this) { return _main_utcb; } if (!this) { return _main_utcb; }
/* this isn't the main thread */ /* this isn't the main thread */
return _tid.pt->phys_utcb(); return _tid.pt->utcb_phys();
} }