mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 15:32:25 +00:00
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:
parent
77f55232fd
commit
210216e5e1
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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++) {
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/***********************
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user