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
{
class Native_utcb;
class Platform_thread;
class Platform_pd;
class Tlb;
@ -31,6 +32,7 @@ namespace Kernel
typedef Genode::size_t size_t;
typedef Genode::Platform_thread Platform_thread;
typedef Genode::Platform_pd Platform_pd;
typedef Genode::Native_utcb Native_utcb;
/**
* 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 ip initial instruction pointer
* \param sp initial stack pointer
*
* \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)
* \param thread_id kernel name of targeted thread
* \param cpu_id kernel name of targeted processor
* \param pd_id kernel name of targeted protection domain
* \param utcb core local pointer to userland thread-context
*
* Restricted to core threads.
*/
inline Tlb * start_thread(Platform_thread * const phys_pt, void * const ip,
void * const sp, unsigned const cpu_no)
inline Tlb * start_thread(unsigned const thread_id, unsigned const cpu_id,
unsigned const pd_id, Native_utcb * const utcb)
{
return (Tlb *)call(Call_id::START_THREAD, (Call_arg)phys_pt,
(Call_arg)ip, (Call_arg)sp, cpu_no);
return (Tlb *)call(Call_id::START_THREAD, thread_id, cpu_id, pd_id,
(Call_arg)utcb);
}

View File

@ -517,61 +517,17 @@ namespace Arm
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,
addr_t const tlb,
unsigned const pd_id)
void init_thread(addr_t const tlb, unsigned const pd_id)
{
ip = (addr_t)instr_p;
cidr = pd_id;
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
*

View File

@ -48,8 +48,8 @@ namespace Genode {
Weak_ptr<Address_space> _address_space;
unsigned _id;
Rm_client * _rm_client;
Native_utcb * _phys_utcb;
Native_utcb * _virt_utcb;
Native_utcb * _utcb_phys;
Native_utcb * _utcb_virt;
Tlb * _tlb;
Ram_dataspace_capability _utcb;
char _name[NAME_MAX_LEN];
@ -109,8 +109,12 @@ namespace Genode {
/**
* 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
@ -182,9 +186,9 @@ namespace Genode {
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; }

View File

@ -119,9 +119,9 @@ namespace Kernel
static bool init = 0;
if (!init) {
enum { STACK_SIZE = sizeof(idle_stack)/sizeof(idle_stack[0]) };
void * const ip = (void *)&idle_main;
void * const sp = (void *)&idle_stack[STACK_SIZE];
idle.init(ip, sp, 0, core_id(), 0, 0, 0, 0);
idle.ip = (addr_t)&idle_main;;
idle.sp = (addr_t)&idle_stack[STACK_SIZE];;
idle.init(0, core_id(), 0, 0);
init = 1;
}
/* create CPU scheduler with a permanent idle thread */
@ -231,12 +231,12 @@ extern "C" void kernel()
*(Core_thread_id *)s = 0;
/* 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;
_main_utcb = &utcb;
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 */
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)
{
assert(_state == AWAITS_SIGNAL && size <= _phys_utcb->size());
Genode::memcpy(_phys_utcb->base(), base, size);
assert(_state == AWAITS_SIGNAL && size <= _utcb_phys->size());
Genode::memcpy(_utcb_phys->base(), base, size);
_schedule();
}
@ -191,17 +191,14 @@ Thread::Thread(Platform_thread * const pt)
_platform_thread(pt),
_state(AWAITS_START),
_pd(0),
_phys_utcb(0),
_virt_utcb(0),
_utcb_phys(0),
_signal_receiver(0)
{ }
void
Thread::init(void * const ip, void * const sp, unsigned const cpu_id,
unsigned const pd_id_arg, Native_utcb * const utcb_phys,
Native_utcb * const utcb_virt, bool const main,
bool const start)
Thread::init(unsigned const cpu_id, unsigned const pd_id_arg,
Native_utcb * const utcb_phys, bool const 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"); }
/* store thread parameters */
_phys_utcb = utcb_phys;
_virt_utcb = utcb_virt;
_utcb_phys = utcb_phys;
/* join protection domain */
_pd = Pd::pool()->object(pd_id_arg);
assert(_pd);
addr_t const tlb = _pd->tlb()->base();
/* 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()); }
User_context::init_thread(tlb, pd_id());
/* print log message */
if (START_VERBOSE) {
@ -282,7 +273,7 @@ void Thread::proceed()
char const * Kernel::Thread::label() const
{
if (!platform_thread()) {
if (!_phys_utcb) { return "idle"; }
if (!_utcb_phys) { return "idle"; }
return "core";
}
return platform_thread()->name();
@ -377,24 +368,26 @@ void Thread::_call_delete_thread()
void Thread::_call_start_thread()
{
/* check permissions */
assert(_core());
if (!_core()) {
PERR("not entitled to start thread");
user_arg_0(0);
return;
}
/* dispatch arguments */
Platform_thread * pt = (Platform_thread *)user_arg_1();
void * const ip = (void *)user_arg_2();
void * const sp = (void *)user_arg_3();
unsigned const cpu_id = (unsigned)user_arg_4();
/* get targeted thread */
Thread * const t = Thread::pool()->object(pt->id());
assert(t);
unsigned const thread_id = user_arg_1();
unsigned const cpu_id = user_arg_2();
unsigned const pd_id = user_arg_3();
Native_utcb * const utcb = (Native_utcb *)user_arg_4();
/* lookup targeted thread */
Thread * const t = Thread::pool()->object(thread_id);
if (!t) {
PERR("unknown thread");
user_arg_0(0);
return;
}
/* start thread */
unsigned const pd_id = pt->pd_id();
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);
t->init(cpu_id, pd_id, utcb, 1);
user_arg_0((Call_ret)t->_pd->tlb());
}
@ -475,7 +468,7 @@ void Thread::_call_wait_for_request()
{
void * buf_base;
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);
}
@ -492,7 +485,7 @@ void Thread::_call_request_and_wait()
size_t msg_size;
void * buf_base;
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);
Ipc_node::send_request_await_reply(dst, msg_base, msg_size,
buf_base, buf_size);
@ -503,7 +496,7 @@ void Thread::_call_reply()
{
void * msg_base;
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);
bool const await_request = user_arg_1();
if (await_request) { _call_wait_for_request(); }
@ -590,7 +583,7 @@ void Thread::_call_access_thread_regs()
/* execute read operations */
unsigned const reads = user_arg_2();
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_values = (addr_t *)user_arg_4();
for (unsigned i = 0; i < reads; i++) {

View File

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

View File

@ -46,13 +46,13 @@ Platform_thread::~Platform_thread()
/* the RM client may be destructed before platform thread */
if (_rm_client) {
Rm_session_component * const rm = _rm_client->member_rm_session();
rm->detach(_virt_utcb);
rm->detach(utcb_virt());
}
}
/* free UTCB */
if (_pd_id == Kernel::core_id()) {
Range_allocator * const ram = platform()->ram_alloc();
ram->free((void *)_phys_utcb, sizeof(Native_utcb));
ram->free(utcb_phys(), sizeof(Native_utcb));
} else {
Ram_session_component * const ram =
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)
:
_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),
_main_thread(0)
{
@ -85,13 +85,13 @@ Platform_thread::Platform_thread(const char * name,
/* create UTCB for a core thread */
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())
{
PERR("failed to allocate UTCB");
throw Cpu_session::Out_of_metadata();
}
_virt_utcb = _phys_utcb;
_utcb_virt = _utcb_phys;
/* common constructor parts */
_init();
@ -102,7 +102,7 @@ Platform_thread::Platform_thread(const char * name, unsigned int priority,
addr_t utcb)
:
_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)),
_main_thread(0)
{
@ -121,7 +121,7 @@ Platform_thread::Platform_thread(const char * name, unsigned int priority,
PERR("failed to allocate UTCB");
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 */
_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 */
if (!_attaches_utcb_by_itself())
{
/*
* Declare page aligned virtual UTCB outside the context area.
* Kernel afterwards offers this as bootstrap argument to the thread.
*/
_virt_utcb = (Native_utcb *)((platform()->vm_start()
/* declare page aligned virtual UTCB outside the context area */
_utcb_virt = (Native_utcb *)((platform()->vm_start()
+ platform()->vm_size() - sizeof(Native_utcb))
& ~((1<<MIN_MAPPING_SIZE_LOG2)-1));
@ -179,14 +172,28 @@ int Platform_thread::start(void * ip, void * sp, unsigned int cpu_no)
return -1;
};
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 (...) {
PERR("failed to attach UTCB");
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 */
_tlb = Kernel::start_thread(this, ip, sp, cpu_no);
_tlb = Kernel::start_thread(id(), cpu_id, _pd_id, utcb_phys());
if (!_tlb) {
PERR("failed to start thread");
return -1;

View File

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