base: setup thread object for main thread in CRT0

For a main thread a thread object is created by the CRT0 before _main gets
called so that _main can already run in a generic environment that, e.g.,
catches stack overflows as a page-fault instead of corrupting the BSS.
Additionally dynamic programs have only one CRT0 - the one of the LDSO -
which does the initialization for both LDSO and program.

ref #989
This commit is contained in:
Martin Stein 2014-01-28 14:30:36 +01:00 committed by Norman Feske
parent ba8e61653f
commit 0b64328944
80 changed files with 1299 additions and 823 deletions

View File

@ -6,7 +6,7 @@
LIBS += cxx l4 startup
SRC_CC += cap_copy.cc main_bootstrap.cc
SRC_CC += cap_copy.cc
SRC_CC += ipc/ipc.cc ipc/pager.cc ipc/ipc_marshal_cap.cc
SRC_CC += pager/pager.cc pager/common.cc
SRC_CC += avl_tree/avl_tree.cc
@ -28,7 +28,6 @@ INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/thread
INC_DIR += $(REP_DIR)/include/codezero/dummies
vpath main_bootstrap.cc $(REP_DIR)/src/platform
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base

View File

@ -1,6 +1,7 @@
/*
* \brief Thread bootstrap code
* \author Christian Prochaska
* \author Martin Stein
* \date 2013-02-15
*/
@ -13,13 +14,83 @@
/* Genode includes */
#include <base/thread.h>
#include <base/env.h>
#include <util/string.h>
/* Codezero includes */
#include <codezero/syscalls.h>
Genode::Native_thread_id main_thread_tid;
Codezero::l4_mutex main_thread_running_lock;
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread()
{
/* initialize codezero environment */
Codezero::__l4_init();
/* provide kernel identification of thread through temporary environment */
main_thread_tid = Codezero::thread_myself();
}
void prepare_reinit_main_thread() { prepare_init_main_thread(); }
/****************************
** Codezero libl4 support **
****************************/
/*
* Unfortunately, the function 'exregs_print_registers' in 'exregs.c' refers to
* 'memset'. Because we do not want to link core against a C library, we have to
* resolve this function here.
*/
extern "C" void *memset(void *s, int c, Genode::size_t n) __attribute__((weak));
extern "C" void *memset(void *s, int c, Genode::size_t n)
{
return Genode::memset(s, c, n);
}
/*
* Same problem as for 'memset'. The 'printf' symbol is referenced from
* 'mutex.c' and 'exregs.c' of Codezero's libl4.
*/
extern "C" int printf(const char *format, ...) __attribute__((weak));
extern "C" int printf(const char *format, ...)
{
va_list list;
va_start(list, format);
Genode::vprintf(format, list);
va_end(list);
return 0;
}
/*****************
** Thread_base **
*****************/
void Genode::Thread_base::_thread_bootstrap()
{
Codezero::l4_mutex_init(utcb()->running_lock());
Codezero::l4_mutex_lock(utcb()->running_lock()); /* block on first mutex lock */
}
void Genode::Thread_base::_init_platform_thread(Type type)
{
if (type == NORMAL) { return; }
/* adjust values whose computation differs for a main thread */
_tid.l4id = main_thread_tid;
_thread_cap = Genode::env()->parent()->main_thread_cap();
/* get first mutex lock (normally done by _thread_bootstrap) */
Codezero::l4_mutex_init(utcb()->running_lock());
Codezero::l4_mutex_lock(utcb()->running_lock());
}

View File

@ -39,9 +39,6 @@ void Thread_base::_thread_start()
** Thread base **
*****************/
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()
{
env()->cpu_session()->kill_thread(_thread_cap);

View File

@ -27,10 +27,6 @@ enum { verbose_thread_start = true };
using namespace Genode;
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread() { }

View File

@ -1,81 +0,0 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Norman Feske
* \author Christian Helmuth
* \date 2009-10-02
*/
/*
* Copyright (C) 2009-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.
*/
/* Genode includes */
#include <base/stdint.h>
#include <base/printf.h>
#include <base/thread.h>
#include <util/string.h>
/* Codezero includes */
#include <codezero/syscalls.h>
/****************************
** Codezero libl4 support **
****************************/
/*
* Unfortunately, the function 'exregs_print_registers' in 'exregs.c' refers to
* 'memset'. Because we do not want to link core against a C library, we have to
* resolve this function here.
*/
extern "C" void *memset(void *s, int c, Genode::size_t n) __attribute__((weak));
extern "C" void *memset(void *s, int c, Genode::size_t n)
{
return Genode::memset(s, c, n);
}
/*
* Same problem as for 'memset'. The 'printf' symbol is referenced from
* 'mutex.c' and 'exregs.c' of Codezero's libl4.
*/
extern "C" int printf(const char *format, ...) __attribute__((weak));
extern "C" int printf(const char *format, ...)
{
va_list list;
va_start(list, format);
Genode::vprintf(format, list);
va_end(list);
return 0;
}
/**************************
** Startup-code helpers **
**************************/
namespace Genode { void platform_main_bootstrap(); }
Genode::Native_thread_id main_thread_tid;
Codezero::l4_mutex main_thread_running_lock;
void Genode::platform_main_bootstrap()
{
static struct Bootstrap
{
Bootstrap()
{
Codezero::__l4_init();
main_thread_tid = Codezero::thread_myself();
Codezero::l4_mutex_init(&main_thread_running_lock);
Codezero::l4_mutex_lock(&main_thread_running_lock); /* block on first mutex lock */
}
} bootstrap;
}

View File

@ -6,7 +6,7 @@
LIBS += cxx startup
SRC_CC += cap_copy.cc main_bootstrap.cc
SRC_CC += cap_copy.cc
SRC_CC += ipc/ipc.cc ipc/pager.cc ipc/ipc_marshal_cap.cc
SRC_CC += pager/pager.cc pager/common.cc
SRC_CC += avl_tree/avl_tree.cc
@ -20,12 +20,11 @@ SRC_CC += elf/elf_binary.cc
SRC_CC += lock/lock.cc
SRC_CC += signal/signal.cc signal/common.cc
SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/thread.cc thread/thread_bootstrap_empty.cc thread/trace.cc
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc thread/trace.cc
INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/thread
vpath main_bootstrap.cc $(REP_DIR)/src/platform
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base

View File

@ -0,0 +1,41 @@
/*
* \brief Platform specific thread initialization
* \author Martin Stein
* \date 2014-01-06
*/
/*
* Copyright (C) 2014 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.
*/
/* Genode includes */
#include <base/thread.h>
#include <base/env.h>
using namespace Genode;
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread() { }
void prepare_reinit_main_thread() { }
/*****************
** Thread_base **
*****************/
void Thread_base::_thread_bootstrap() { }
void Thread_base::_init_platform_thread(Type type)
{
if (type == NORMAL) { return; }
_thread_cap = Genode::env()->parent()->main_thread_cap();
}

View File

@ -53,9 +53,6 @@ void Thread_base::cancel_blocking()
}
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()
{
/* destruct platform thread */

View File

@ -1,14 +0,0 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Christian Prochaska
* \date 2009-08-05
*/
/*
* Copyright (C) 2009-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.
*/
namespace Genode { void platform_main_bootstrap() { /* dummy */ } }

View File

@ -17,6 +17,7 @@
#include <base/cap_map.h>
#include <base/native_types.h>
#include <util/assert.h>
#include <util/construct_at.h>
namespace Genode {
@ -124,6 +125,11 @@ namespace Genode {
bool static_idx(Cap_index *idx) {
return ((T*)idx) < &_indices[START_IDX]; }
void reinit()
{
construct_at<Cap_index_allocator_tpl<T, SZ> >(this);
}
};
}

View File

@ -146,6 +146,11 @@ namespace Genode
* \param idx pointer to the Cap_index object in question
*/
virtual bool static_idx(Cap_index *idx) = 0;
/**
* Redo construction of the object
*/
virtual void reinit() = 0;
};
@ -196,7 +201,9 @@ namespace Genode
* to save entries in the capability space, and prevent leaks of
* them.
*/
class Capability_map : Noncopyable
class Capability_map
:
private Noncopyable
{
private:

View File

@ -6,7 +6,6 @@
LIBS += cxx syscall startup
SRC_CC += main_bootstrap.cc
SRC_CC += ipc/ipc.cc ipc/pager.cc
SRC_CC += pager/pager.cc pager/common.cc
SRC_CC += avl_tree/avl_tree.cc
@ -27,8 +26,7 @@ INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/thread
vpath main_bootstrap.cc $(REP_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
# vi: set ft=make :

View File

@ -51,24 +51,35 @@ addr_t Thread_base::Context_allocator::addr_to_base(void *addr)
size_t Thread_base::Context_allocator::base_to_idx(addr_t base)
{
return (base - Native_config::context_area_virtual_base()) /
Native_config::context_virtual_size();
/* the first context isn't managed through the indices */
return ((base - Native_config::context_area_virtual_base()) /
Native_config::context_virtual_size()) - 1;
}
addr_t Thread_base::Context_allocator::idx_to_base(size_t idx)
{
/* the first context isn't managed through the indices */
return Native_config::context_area_virtual_base() +
Native_config::context_virtual_size() +
idx * Native_config::context_virtual_size();
}
Thread_base::Context *Thread_base::Context_allocator::alloc(Thread_base *thread_base)
Thread_base::Context *
Thread_base::Context_allocator::alloc(Thread_base *thread_base, bool main_thread)
{
Lock::Guard _lock_guard(_threads_lock);
try {
return base_to_context(idx_to_base(_alloc.alloc()));
addr_t base;
if (main_thread) {
/* the main-thread context isn't managed by '_alloc' */
base = Native_config::context_area_virtual_base();
} else {
/* contexts besides main-thread context are managed by '_alloc' */
base = idx_to_base(_alloc.alloc());
}
return base_to_context(base);
} catch(Bit_allocator<MAX_THREADS>::Out_of_indices) {
return 0;
}
@ -78,8 +89,13 @@ Thread_base::Context *Thread_base::Context_allocator::alloc(Thread_base *thread_
void Thread_base::Context_allocator::free(Context *context)
{
Lock::Guard _lock_guard(_threads_lock);
addr_t const base = addr_to_base(context);
_alloc.free(base_to_idx(addr_to_base(context)));
/* the main-thread context isn't managed by '_alloc' */
if (base == Native_config::context_area_virtual_base()) { return; }
/* contexts besides main-thread context are managed by '_alloc' */
_alloc.free(base_to_idx(base));
}
@ -94,7 +110,8 @@ Thread_base::Context_allocator *Thread_base::_context_allocator()
}
Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
Thread_base::Context *
Thread_base::_alloc_context(size_t stack_size, bool main_thread)
{
/*
* Synchronize context list when creating new threads from multiple threads
@ -105,7 +122,7 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
Lock::Guard _lock_guard(alloc_lock);
/* allocate thread context */
Context *context = _context_allocator()->alloc(this);
Context *context = _context_allocator()->alloc(this, main_thread);
if (!context)
throw Context_alloc_failed();
@ -201,7 +218,7 @@ void Thread_base::join()
void* Thread_base::alloc_secondary_stack(char const *name, size_t stack_size)
{
Context *context = _alloc_context(stack_size);
Context *context = _alloc_context(stack_size, false);
strncpy(context->name, name, sizeof(context->name));
return (void *)context->stack_top();
}
@ -214,13 +231,14 @@ void Thread_base::free_secondary_stack(void* stack_addr)
}
Thread_base::Thread_base(const char *name, size_t stack_size)
Thread_base::Thread_base(const char *name, size_t stack_size, Type const type)
:
_context(_alloc_context(stack_size)),
_context(type == REINITIALIZED_MAIN ?
_context : _alloc_context(stack_size, type == MAIN)),
_join_lock(Lock::LOCKED)
{
strncpy(_context->name, name, sizeof(_context->name));
_init_platform_thread();
_init_platform_thread(type);
}

View File

@ -1,6 +1,7 @@
/*
* \brief Fiasco.OC specific thread bootstrap code
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2011-01-20
*/
@ -11,9 +12,38 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <util/construct_at.h>
#include <base/thread.h>
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread()
{
using namespace Genode;
enum { THREAD_CAP_ID = 1 };
Cap_index * ci(cap_map()->insert(THREAD_CAP_ID, Fiasco::MAIN_THREAD_CAP));
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE] = (unsigned long)ci;
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_THREAD_OBJ] = 0;
}
void prepare_reinit_main_thread()
{
using namespace Genode;
construct_at<Capability_map>(cap_map());
cap_idx_alloc()->reinit();
prepare_init_main_thread();
}
/*****************
** Thread_base **
*****************/
void Genode::Thread_base::_thread_bootstrap() { }

View File

@ -2,6 +2,7 @@
* \brief Fiasco-specific implementation of the non-core startup Thread API
* \author Norman Feske
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2010-01-19
*/
@ -38,15 +39,26 @@ void Thread_base::_deinit_platform_thread()
}
void Genode::Thread_base::_init_platform_thread()
void Thread_base::_init_platform_thread(Type type)
{
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = env()->cpu_session()->create_thread(buf);
if (type == NORMAL)
{
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = env()->cpu_session()->create_thread(buf);
/* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap);
/* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap);
return;
}
/* adjust values whose computation differs for a main thread */
_tid = Fiasco::MAIN_THREAD_CAP;
_thread_cap = env()->parent()->main_thread_cap();
/* make thread object known to the Fiasco environment */
addr_t const t = (addr_t)this;
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_THREAD_OBJ] = t;
}

View File

@ -35,7 +35,7 @@ void Thread_base::_deinit_platform_thread()
}
void Genode::Thread_base::_init_platform_thread() { }
void Thread_base::_init_platform_thread(Type) { }
void Thread_base::start()

View File

@ -1,41 +0,0 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Christian Prochaska
* \author Christian Helmuth
* \date 2009-08-05
*/
/*
* Copyright (C) 2009-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.
*/
/* Genode includes */
#include <base/stdint.h>
#include <base/native_types.h>
#include <base/cap_map.h>
namespace Fiasco {
#include <l4/sys/utcb.h>
}
namespace Genode { void platform_main_bootstrap(); }
void Genode::platform_main_bootstrap()
{
static struct Bootstrap
{
enum { MAIN_THREAD_CAP_ID = 1 };
Bootstrap()
{
Cap_index *i(cap_map()->insert(MAIN_THREAD_CAP_ID, Fiasco::MAIN_THREAD_CAP));
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE] = (unsigned long) i;
Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_THREAD_OBJ] = 0;
}
} bootstrap;
}

View File

@ -6,7 +6,6 @@
LIBS += cxx kernel_interface
SRC_CC += main_bootstrap.cc
SRC_CC += ipc.cc ipc/ipc_marshal_cap.cc
SRC_CC += avl_tree/avl_tree.cc
SRC_CC += allocator/slab.cc
@ -21,10 +20,9 @@ SRC_CC += signal/signal.cc signal/common.cc
SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/thread_bootstrap.cc thread/trace.cc
INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/thread
vpath main_bootstrap.cc $(REP_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base

View File

@ -1,6 +1,6 @@
/*
* \brief Thread bootstrap code
* \author Christian Prochaska
* \brief Thread initialization
* \author Martin stein
* \date 2013-02-15
*/
@ -13,13 +13,82 @@
/* Genode includes */
#include <base/thread.h>
#include <base/env.h>
/* base-hw includes */
#include <kernel/interface.h>
using namespace Genode;
void Genode::Thread_base::_thread_bootstrap()
Ram_dataspace_capability _main_thread_utcb_ds;
Native_thread_id _main_thread_id;
namespace Genode { Rm_session * env_context_area_rm_session(); }
/**************************
** Native types support **
**************************/
Native_thread_id Genode::thread_get_my_native_id()
{
Thread_base * const t = Thread_base::myself();
return t ? t->tid().thread_id : _main_thread_id;
}
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread()
{
using namespace Genode;
/*
* Make data from the startup info persistantly available by copying it
* before the UTCB gets polluted by the following function calls.
*/
Native_utcb * const utcb = Thread_base::myself()->utcb();
_main_thread_id = utcb->start_info()->thread_id();
_main_thread_utcb_ds =
reinterpret_cap_cast<Ram_dataspace>(utcb->start_info()->utcb_ds());
}
void prepare_reinit_main_thread() { prepare_init_main_thread(); }
/*****************
** Thread_base **
*****************/
void Thread_base::_thread_bootstrap()
{
Native_utcb * const utcb = Thread_base::myself()->utcb();
_tid.thread_id = utcb->start_info()->thread_id();
}
void Thread_base::_init_platform_thread(Type type)
{
/* nothing platform specific to do if this is not a special thread */
if (type == NORMAL) { return; }
/* if we got reinitialized we have to get rid of the old UTCB */
size_t const utcb_size = sizeof(Native_utcb);
addr_t const context_area = Native_config::context_area_virtual_base();
addr_t const utcb_new = (addr_t)&_context->utcb - context_area;
Rm_session * const rm = env_context_area_rm_session();
if (type == REINITIALIZED_MAIN) { rm->detach(utcb_new); }
/* remap initial main-thread UTCB according to context-area spec */
try { rm->attach_at(_main_thread_utcb_ds, utcb_new, utcb_size); }
catch(...) {
PERR("failed to re-map UTCB");
while (1) ;
}
/* adjust initial object state in case of a main thread */
tid().thread_id = _main_thread_id;
}

View File

@ -26,9 +26,6 @@ namespace Genode { Rm_session * env_context_area_rm_session(); }
** Thread_base **
*****************/
void Thread_base::_init_platform_thread() { }
Native_utcb * Thread_base::utcb()
{
if (this) { return &_context->utcb; }

View File

@ -60,11 +60,6 @@
/* catch erroneous kernel return */
3: b 3b
/* handle for dynamic symbol objects */
.align 3
.global __dso_handle
__dso_handle: .long 0
.section .bss
/* kernel stack */

View File

@ -41,6 +41,7 @@ using namespace Kernel;
/* get core configuration */
extern Genode::Native_utcb * _main_thread_utcb;
extern Genode::Native_thread_id _main_thread_id;
extern int _kernel_stack_high;
extern "C" void CORE_MAIN();
@ -249,6 +250,7 @@ extern "C" void kernel()
/* start thread with stack pointer at the top of stack */
static Native_utcb utcb;
static Thread t(Priority::MAX, "core");
_main_thread_id = t.id();
_main_thread_utcb = &utcb;
_main_thread_utcb->start_info()->init(t.id(), Genode::Native_capability());
t.ip = (addr_t)CORE_MAIN;;

View File

@ -53,7 +53,7 @@ void Thread_base::_thread_start()
}
Thread_base::Thread_base(const char * const label, size_t const stack_size)
Thread_base::Thread_base(const char * const label, size_t const stack_size, Type)
{
_tid.platform_thread = new (platform()->core_mem_alloc())
Platform_thread(stack_size, Kernel::core_id(), label);

View File

@ -1,42 +0,0 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Martin Stein
* \author Christian Helmuth
* \date 2010-09-13
*/
/*
* Copyright (C) 2010-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.
*/
/* Genode includes */
#include <base/native_types.h>
#include <base/thread.h>
using namespace Genode;
namespace Genode { void platform_main_bootstrap(); }
Native_thread_id _main_thread_id;
Native_thread_id Genode::thread_get_my_native_id()
{
Thread_base * const t = Thread_base::myself();
return t ? t->tid().thread_id : _main_thread_id;
}
void Genode::platform_main_bootstrap()
{
/* go save against multiple calls e.g. for programs with dynamic linker */
static bool main_thread_id_valid = 0;
if (!main_thread_id_valid) {
Native_utcb * const utcb = Thread_base::myself()->utcb();
_main_thread_id = utcb->start_info()->thread_id();
main_thread_id_valid = 1;
}
}

View File

@ -14,6 +14,7 @@
#ifndef _INCLUDE__RM_SESSION__CLIENT_H_
#define _INCLUDE__RM_SESSION__CLIENT_H_
/* Genode includes */
#include <rm_session/capability.h>
namespace Genode {
@ -22,6 +23,8 @@ namespace Genode {
{
Rm_session_capability const _cap;
typedef Rm_session Rpc_interface;
/**
* Return pointer to locally implemented RM session
*

View File

@ -6,7 +6,6 @@
LIBS += syscall
SRC_CC += main_bootstrap.cc
SRC_CC += ipc/ipc.cc
SRC_CC += avl_tree/avl_tree.cc
SRC_CC += allocator/slab.cc
@ -20,7 +19,7 @@ SRC_CC += lock/lock.cc
SRC_CC += env/rm_session_mmap.cc env/debug.cc
SRC_CC += signal/signal.cc signal/common.cc
SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/trace.cc
SRC_CC += thread/trace.cc thread/thread_env.cc
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
INC_DIR += $(REP_DIR)/src/base/ipc
@ -28,6 +27,5 @@ INC_DIR += $(REP_DIR)/src/base/env $(BASE_DIR)/src/base/env
INC_DIR += $(REP_DIR)/src/platform $(BASE_DIR)/src/platform
INC_DIR += $(BASE_DIR)/src/base/thread
vpath main_bootstrap.cc $(REP_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base

View File

@ -154,6 +154,10 @@ Platform_env::Local_parent &Platform_env::_parent()
}
void Platform_env::reinit(Native_capability::Dst, long) { }
void Platform_env::reinit_main_thread(Rm_session_capability &) { }
Platform_env::Platform_env()
:
Platform_env_base(static_cap_cast<Ram_session>(_parent().session("Env::ram_session", "")),

View File

@ -432,13 +432,15 @@ namespace Genode {
*/
~Platform_env() { _parent().exit(0); }
/**
* Reload parent capability and reinitialize environment resources
/*
* Support functions for implementing fork on Noux.
*
* Not supported on Linux.
*
* See the documentation in 'base/src/base/env/platform_env.h'
*/
void reload_parent_cap(Capability<Parent>::Dst, long)
{
/* not supported on Linux */
}
void reinit(Native_capability::Dst, long);
void reinit_main_thread(Rm_session_capability &);
/*************************************

View File

@ -0,0 +1,49 @@
/*
* \brief Thread-environment support common to all programs
* \author Martin Stein
* \date 2013-12-13
*/
/*
* 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.
*/
/* Genode includes */
#include <base/stdint.h>
#include <base/env.h>
using namespace Genode;
extern addr_t * __initial_sp;
/*
* Define 'lx_environ' pointer.
*/
char **lx_environ;
/**
* Natively aligned memory location used in the lock implementation
*/
int main_thread_futex_counter __attribute__((aligned(sizeof(addr_t))));
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread()
{
/*
* Initialize the 'lx_environ' pointer
*
* environ = &argv[argc + 1]
* __initial_sp[0] = argc (always 1 in Genode)
* __initial_sp[1] = argv[0]
* __initial_sp[2] = NULL
* __initial_sp[3] = environ
*/
lx_environ = (char**)&__initial_sp[3];
}

View File

@ -1,6 +1,7 @@
/*
* \brief Implementation of the Thread API via Linux threads
* \author Norman Feske
* \author Martin Stein
* \date 2006-06-13
*/
@ -23,6 +24,7 @@
using namespace Genode;
extern int main_thread_futex_counter;
static void empty_signal_handler(int) { }
@ -67,9 +69,16 @@ void Thread_base::_thread_start()
}
void Thread_base::_init_platform_thread()
void Thread_base::_init_platform_thread(Type type)
{
_thread_cap = env()->cpu_session()->create_thread(_context->name);
/* for normal threads create an object at the CPU session */
if (type == NORMAL) {
_thread_cap = env()->cpu_session()->create_thread(_context->name);
return;
}
/* adjust initial object state for main threads */
tid().futex_counter = main_thread_futex_counter;
_thread_cap = env()->parent()->main_thread_cap();
}

View File

@ -46,7 +46,7 @@ void Thread_base::_thread_start()
}
void Thread_base::_init_platform_thread() { }
void Thread_base::_init_platform_thread(Type) { }
void Thread_base::_deinit_platform_thread() { }

View File

@ -401,7 +401,7 @@ void Thread_base::join()
}
Thread_base::Thread_base(const char *name, size_t stack_size)
Thread_base::Thread_base(const char *name, size_t stack_size, Type)
{
_tid.meta_data = new (env()->heap()) Thread_meta_data_created(this);

View File

@ -1,61 +0,0 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Christian Prochaska
* \author Christian Helmuth
* \date 2009-08-05
*/
/*
* Copyright (C) 2009-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.
*/
#include <base/thread.h>
#include <linux_syscalls.h>
namespace Genode { void platform_main_bootstrap(); }
/*
* Define 'lx_environ' pointer.
*/
char **lx_environ;
/**
* Natively aligned memory location used in the lock implementation
*/
int main_thread_futex_counter __attribute__((aligned(sizeof(Genode::addr_t))));
/**
* Initial value of SP register (in crt0)
*/
extern Genode::addr_t *__initial_sp;
/**
* Platform-specific bootstrap
*/
void Genode::platform_main_bootstrap()
{
static struct Bootstrap
{
Bootstrap()
{
/*
* Initialize the 'lx_environ' pointer
*
* environ = &argv[argc + 1]
* __initial_sp[0] = argc (always 1 in Genode)
* __initial_sp[1] = argv[0]
* __initial_sp[2] = NULL
* __initial_sp[3] = environ
*/
lx_environ = (char**)&__initial_sp[3];
}
} bootstrap;
}

View File

@ -102,7 +102,7 @@ namespace Genode {
};
class Capability_map : Noncopyable
class Capability_map : private Noncopyable
{
private:

View File

@ -6,7 +6,6 @@
LIBS += cxx startup
SRC_CC += main_bootstrap.cc
SRC_CC += ipc/ipc.cc ipc/pager.cc
SRC_CC += avl_tree/avl_tree.cc
SRC_CC += allocator/slab.cc
@ -26,8 +25,7 @@ INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/thread
vpath main_bootstrap.cc $(REP_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
# vi: set ft=make :

View File

@ -7,8 +7,7 @@
LIBS += base-common
SRC_CC += console/log_console.cc
SRC_CC += env/env.cc env/main_thread.cc \
env/context_area.cc env/reinitialize.cc
SRC_CC += env/env.cc env/context_area.cc env/reinitialize.cc
SRC_CC += thread/thread_nova.cc
INC_DIR += $(BASE_DIR)/src/base/env

View File

@ -1,31 +0,0 @@
/*
* \brief Information about the main thread
* \author Norman Feske
* \author Alexander Boettcher
* \date 2010-01-19
*/
/*
* Copyright (C) 2010-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.
*/
/* Genode includes */
#include <base/native_types.h>
/* NOVA includes */
#include <nova/syscalls.h>
using namespace Genode;
Native_utcb *main_thread_utcb()
{
return reinterpret_cast<Native_utcb *>(
Native_config::context_area_virtual_base() +
Native_config::context_area_virtual_size() - Nova::PAGE_SIZE_BYTE);
}
addr_t main_thread_running_semaphore() { return Nova::SM_SEL_EC; }

View File

@ -1,6 +1,8 @@
/*
* \brief Thread-context specific part of the thread library
* \author Norman Feske
* \author Alexander Boettcher
* \author Martin Stein
* \date 2010-01-19
*
* This part of the thread library is required by the IPC framework
@ -14,13 +16,98 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <util/construct_at.h>
#include <base/env.h>
#include <base/thread.h>
/* base-nova includes */
#include <base/cap_map.h>
using namespace Genode;
extern addr_t __initial_sp;
Native_utcb *main_thread_utcb();
/*******************
** local helpers **
*******************/
Native_utcb * main_thread_utcb()
{
using namespace Genode;
return reinterpret_cast<Native_utcb *>(
Native_config::context_area_virtual_base() +
Native_config::context_virtual_size() - Nova::PAGE_SIZE_BYTE);
}
addr_t main_thread_running_semaphore() { return Nova::SM_SEL_EC; }
class Initial_cap_range : public Cap_range
{
private:
enum { CAP_RANGE_START = 4096 };
public:
Initial_cap_range() : Cap_range(CAP_RANGE_START) { }
};
Initial_cap_range * initial_cap_range()
{
static Initial_cap_range s;
return &s;
}
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread()
{
using namespace Genode;
cap_map()->insert(initial_cap_range());
/* for Core we can't perform the following code so early */
if (!__initial_sp) {
enum { CAP_RANGES = 16 };
unsigned index = initial_cap_range()->base() +
initial_cap_range()->elements();
static char local[CAP_RANGES][sizeof(Cap_range)];
for (unsigned i = 0; i < CAP_RANGES; i++) {
Cap_range * range = reinterpret_cast<Cap_range *>(local[i]);
*range = Cap_range(index);
cap_map()->insert(range);
index = range->base() + range->elements();
}
}
}
void prepare_reinit_main_thread()
{
using namespace Genode;
construct_at<Capability_map>(cap_map());
construct_at<Initial_cap_range>(initial_cap_range());
prepare_init_main_thread();
}
/*****************
** Thread_base **
*****************/
Native_utcb *Thread_base::utcb()
{
@ -34,5 +121,3 @@ Native_utcb *Thread_base::utcb()
return &_context->utcb;
}

View File

@ -66,7 +66,7 @@ void Thread_base::_thread_start()
** Thread base **
*****************/
void Thread_base::_init_platform_thread()
void Thread_base::_init_platform_thread(Type type)
{
using namespace Nova;
@ -74,7 +74,15 @@ void Thread_base::_init_platform_thread()
* Allocate capability selectors for the thread's execution context,
* running semaphore and exception handler portals.
*/
_tid.ec_sel = Native_thread::INVALID_INDEX;
_tid.ec_sel = Native_thread::INVALID_INDEX;
/* for main threads the member initialization differs */
if (type == MAIN || type == REINITIALIZED_MAIN) {
_thread_cap = env()->parent()->main_thread_cap();
_tid.exc_pt_sel = 0;
return;
}
_tid.exc_pt_sel = cap_map()->insert(NUM_INITIAL_PT_LOG2);
if (_tid.exc_pt_sel == Native_thread::INVALID_INDEX)
throw Cpu_session::Thread_creation_failed();

View File

@ -106,7 +106,7 @@ int Platform_thread::start(void *ip, void *sp)
if (!is_vcpu()) {
pd_utcb = Native_config::context_area_virtual_base() +
Native_config::context_area_virtual_size() - get_page_size();
Native_config::context_virtual_size() - get_page_size();
addr_t remap_src[] = { _pd->parent_pt_sel() };
addr_t remap_dst[] = { PT_SEL_PARENT };

View File

@ -27,7 +27,6 @@ SRC_CC = main.cc \
signal_source_component.cc \
trace_session_component.cc \
core_rm_session.cc \
main_thread.cc \
context_area.cc \
echo.cc \
dump_alloc.cc \
@ -59,5 +58,4 @@ vpath platform_services.cc $(GEN_CORE_DIR)/x86
vpath context_area.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/base/console
vpath %.cc $(REP_DIR)/src/core
vpath main_thread.cc $(REP_DIR)/src/base/env
vpath pager.cc $(REP_DIR)/src/base/pager

View File

@ -27,7 +27,7 @@
using namespace Genode;
void Thread_base::_init_platform_thread()
void Thread_base::_init_platform_thread(Type type)
{
/*
* This function is called for constructing server activations and pager
@ -36,6 +36,20 @@ void Thread_base::_init_platform_thread()
*/
using namespace Nova;
if (type == MAIN)
{
/* set EC selector according to NOVA spec */
_tid.ec_sel = Platform_pd::pd_core_sel() + 1;
/*
* Exception base of first thread in core is 0. We have to set
* it here so that Thread_base code finds the semaphore of the
* main thread.
*/
_tid.exc_pt_sel = 0;
return;
}
_tid.ec_sel = cap_map()->insert(1);
_tid.exc_pt_sel = cap_map()->insert(NUM_INITIAL_PT_LOG2);
addr_t pd_sel = Platform_pd::pd_core_sel();

View File

@ -1,71 +0,0 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Norman Feske
* \author Sebastian Sumpf
* \date 2009-12-28
*/
/*
* Copyright (C) 2009-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.
*/
#include <base/cap_map.h>
#include <base/env.h>
#include <base/printf.h>
namespace Genode { void platform_main_bootstrap(); }
enum { CAP_RANGE_START = 4096 };
Genode::Cap_range * initial_range()
{
static Genode::Cap_range range(CAP_RANGE_START);
return &range;
}
extern "C" Genode::addr_t __initial_sp;
void Genode::platform_main_bootstrap()
{
static struct Bootstrap
{
Bootstrap()
{
cap_map()->insert(initial_range());
/* for Core we can't perform the following code so early */
if (__initial_sp)
return;
unsigned index = initial_range()->base() + initial_range()->elements();
/*
printf("initial selector range [0x%8lx:0x%8lx)\n",
initial_range()->base(), initial_range()->base() +
initial_range()->elements());
*/
for (unsigned i = 0; i < 16; i++) {
Ram_dataspace_capability ds = env()->ram_session()->alloc(4096);
addr_t local = env()->rm_session()->attach(ds);
Cap_range * range = reinterpret_cast<Cap_range *>(local);
*range = Cap_range(index);
cap_map()->insert(range);
/*
printf("add cap selector range [0x%8lx:0x%8lx)\n",
range->base(), range->base() + range->elements());
*/
index = range->base() + range->elements();
}
}
} bootstrap;
}

View File

@ -6,7 +6,7 @@
LIBS += cxx startup
SRC_CC += cap_copy.cc main_bootstrap.cc
SRC_CC += cap_copy.cc
SRC_CC += ipc/ipc.cc ipc/pager.cc ipc/ipc_marshal_cap.cc
SRC_CC += pager/pager.cc pager/common.cc
SRC_CC += avl_tree/avl_tree.cc
@ -25,7 +25,6 @@ SRC_CC += thread/thread.cc thread/thread_bootstrap.cc thread/trace.cc
INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/thread
vpath main_bootstrap.cc $(REP_DIR)/src/platform
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base

View File

@ -1,6 +1,7 @@
/*
* \brief Default thread bootstrap code
* \author Norman Feske
* \author Martin Stein
* \date 2009-04-02
*/
@ -11,19 +12,74 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/thread.h>
namespace Okl4 { extern "C" {
#include <l4/utcb.h>
#include <l4/thread.h>
} }
namespace Okl4 {
extern L4_Word_t copy_uregister_to_utcb(void);
/* OKL4 includes */
namespace Okl4
{
extern "C" {
#include <l4/utcb.h>
#include <l4/thread.h>
}
}
Genode::Native_thread_id main_thread_tid;
/*******************
** local helpers **
*******************/
namespace Okl4
{
/*
* Read global thread ID from user-defined handle and store it
* into a designated UTCB entry.
*/
L4_Word_t copy_uregister_to_utcb()
{
using namespace Okl4;
L4_Word_t my_global_id = L4_UserDefinedHandle();
__L4_TCR_Set_ThreadWord(Genode::UTCB_TCR_THREAD_WORD_MYSELF,
my_global_id);
return my_global_id;
}
}
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread()
{
/* copy thread ID to utcb */
main_thread_tid.raw = Okl4::copy_uregister_to_utcb();
/* adjust main-thread ID if this is the main thread of core */
if (main_thread_tid.raw == 0) {
main_thread_tid.raw = Okl4::L4_rootserver.raw;
}
}
void prepare_reinit_main_thread() { prepare_init_main_thread(); }
/*****************
** Thread_base **
*****************/
void Genode::Thread_base::_thread_bootstrap()
{
_tid.l4id.raw = Okl4::copy_uregister_to_utcb();
}
void Genode::Thread_base::_init_platform_thread(Type type)
{
if (type == NORMAL) { return; }
_tid.l4id.raw = main_thread_tid.raw;
}

View File

@ -50,9 +50,6 @@ void Thread_base::cancel_blocking()
}
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()
{
/* destruct platform thread */

View File

@ -1,62 +0,0 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Christian Prochaska
* \author Christian Helmuth
* \date 2009-08-05
*/
/*
* Copyright (C) 2009-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.
*/
/* Genode includes */
#include <base/native_types.h>
/* OKL4-specific includes and definitions */
namespace Okl4 { extern "C" {
#include <l4/utcb.h>
#include <l4/thread.h>
} }
namespace Okl4 {
/*
* Read global thread ID from user-defined handle and store it
* into a designated UTCB entry.
*/
L4_Word_t copy_uregister_to_utcb()
{
using namespace Okl4;
L4_Word_t my_global_id = L4_UserDefinedHandle();
__L4_TCR_Set_ThreadWord(Genode::UTCB_TCR_THREAD_WORD_MYSELF,
my_global_id);
return my_global_id;
}
}
namespace Genode { void platform_main_bootstrap(); }
Genode::Native_thread_id main_thread_tid;
void Genode::platform_main_bootstrap()
{
static struct Bootstrap
{
Bootstrap()
{
/* copy thread ID to utcb */
main_thread_tid.raw = Okl4::copy_uregister_to_utcb();
if (main_thread_tid.raw == 0) /* core */
main_thread_tid.raw = Okl4::L4_rootserver.raw;
}
} bootstrap;
}

View File

@ -6,7 +6,7 @@
LIBS += cxx startup
SRC_CC += cap_copy.cc main_bootstrap.cc
SRC_CC += cap_copy.cc
SRC_CC += ipc/ipc.cc ipc/pager.cc ipc/ipc_marshal_cap.cc
SRC_CC += pager/pager.cc pager/common.cc
SRC_CC += avl_tree/avl_tree.cc
@ -25,7 +25,6 @@ SRC_CC += thread/thread.cc thread/trace.cc thread/thread_bootstrap.cc
INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(BASE_DIR)/src/base/thread
vpath main_bootstrap.cc $(REP_DIR)/src/platform
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base

View File

@ -15,11 +15,38 @@
#include <base/thread.h>
/* Pistachio includes */
namespace Pistachio {
#include <l4/thread.h>
namespace Pistachio
{
#include <l4/thread.h>
}
Genode::Native_thread_id main_thread_tid;
/*****************************
** Startup library support **
*****************************/
void prepare_init_main_thread()
{
main_thread_tid = Pistachio::L4_Myself();
}
void prepare_reinit_main_thread() { prepare_init_main_thread(); }
/*****************
** Thread_base **
*****************/
void Genode::Thread_base::_thread_bootstrap()
{
_tid.l4id = Pistachio::L4_Myself();
}
void Genode::Thread_base::_init_platform_thread(Type type)
{
if (type == NORMAL) { return; }
_tid.l4id = main_thread_tid;
}

View File

@ -53,9 +53,6 @@ void Thread_base::cancel_blocking()
}
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()
{
/* destruct platform thread */

View File

@ -1,36 +0,0 @@
/*
* \brief Platform-specific helper functions for the _main() function
* \author Christian Prochaska
* \author Christian Helmuth
* \date 2009-08-05
*/
/*
* Copyright (C) 2009-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.
*/
/* Genode includes */
#include <base/native_types.h>
/* Pistachio includes */
namespace Pistachio {
#include <l4/thread.h>
}
namespace Genode { void platform_main_bootstrap(); }
Genode::Native_thread_id main_thread_tid;
void Genode::platform_main_bootstrap()
{
static struct Bootstrap
{
Bootstrap() { main_thread_tid = Pistachio::L4_Myself(); }
} bootstrap;
}

View File

@ -73,20 +73,6 @@ namespace Genode {
* Heap backed by the ram_session of the environment.
*/
virtual Allocator *heap() = 0;
/**
* Reload parent capability and reinitialize environment resources
*
* This function is solely used for implementing fork semantics.
* After forking a process, the new child process is executed
* within a copy of the address space of the forking process.
* Thereby, the new process inherits the original 'env' object of
* the forking process, which is meaningless in the context of the
* new process. By calling this function, the new process is able
* to reinitialize its 'env' with meaningful capabilities obtained
* via its updated parent capability.
*/
virtual void reload_parent_cap(Capability<Parent>::Dst, long) = 0;
};
extern Env *env();

View File

@ -185,11 +185,13 @@ namespace Genode {
/**
* Allocate thread context for specified thread
*
* \param thread thread for which to allocate the new context
* \return virtual address of new thread context, or
* 0 if the allocation failed
* \param thread thread for which to allocate the new context
* \param main_thread wether to alloc for the main thread
*
* \return virtual address of new thread context, or
* 0 if the allocation failed
*/
Context *alloc(Thread_base *thread);
Context *alloc(Thread_base *thread, bool main_thread);
/**
* Release thread context
@ -224,8 +226,11 @@ namespace Genode {
/**
* Allocate and locally attach a new thread context
*
* \param stack_size size of this threads stack
* \param main_thread wether this is the main thread
*/
Context *_alloc_context(size_t stack_size);
Context *_alloc_context(size_t stack_size, bool main_thread);
/**
* Detach and release thread context of the thread
@ -246,11 +251,6 @@ namespace Genode {
*/
static void _thread_start();
/**
* Hook for platform-specific constructor supplements
*/
void _init_platform_thread();
/**
* Hook for platform-specific destructor supplements
*/
@ -285,6 +285,14 @@ namespace Genode {
*/
Genode::Lock _join_lock;
/**
* Thread type
*
* Some threads need special treatment at construction. This enum
* is solely used to distinguish them at construction.
*/
enum Type { NORMAL, MAIN, REINITIALIZED_MAIN };
private:
Trace::Logger _trace_logger;
@ -296,6 +304,13 @@ namespace Genode {
*/
static Trace::Logger *_logger();
/**
* Hook for platform-specific constructor supplements
*
* \param main_thread wether this is the main thread
*/
void _init_platform_thread(Type type);
public:
/**
@ -303,6 +318,7 @@ namespace Genode {
*
* \param name thread name for debugging
* \param stack_size stack size
* \param type enables selection of special construction
*
* \throw Stack_too_large
* \throw Stack_alloc_failed
@ -313,8 +329,14 @@ namespace Genode {
* stack size is internally used by the framework for storing
* thread-context information such as the thread's name (see
* 'struct Context').
*
* FIXME: With type = Forked_main_thread the whole
* Context::_alloc_context call gets skipped but we should
* at least set Context::ds_cap in a way that it references
* the dataspace of the already attached stack.
*/
Thread_base(const char *name, size_t stack_size);
Thread_base(const char *name, size_t stack_size,
Type type = NORMAL);
/**
* Destructor
@ -448,9 +470,10 @@ namespace Genode {
* Constructor
*
* \param name thread name (for debugging)
* \param type enables selection of special construction
*/
explicit Thread(const char *name)
: Thread_base(name, STACK_SIZE) { }
explicit Thread(const char *name, Type type = NORMAL)
: Thread_base(name, STACK_SIZE, type) { }
};
}

View File

@ -1,8 +1,10 @@
SRC_S += crt0.s
SRC_CC += _main.cc
SRC_CC += init_main_thread.cc
REP_INC_DIR += src/platform
LIBS += syscall
vpath _main.cc $(BASE_DIR)/src/platform
vpath init_main_thread.cc $(BASE_DIR)/src/platform

View File

@ -84,6 +84,15 @@ LIBS += $(BASE_LIBS)
else
LIBS := $(filter-out $(BASE_LIBS),$(LIBS))
LIBS += $(DYNAMIC_LINKER)
#
# Ensure that startup_dyn is build for the dynamic programs that depend on a
# shared library. They add it to their dependencies as replacement for the
# static-case startup as soon as they recognize that they are dynamic.
# The current library in contrast filters-out startup_dyn from its
# dependencies before they get merged.
#
LIBS += startup_dyn
endif

View File

@ -125,9 +125,15 @@ $(LIB_A): $(OBJECTS)
$(VERBOSE)$(AR) -rc $@ $(OBJECTS)
#
# Prevent linkage of startup code against shared libraries except for ld.lib.so
# Prevent linkage of startup_dyn as we added it only in order that it gets
# build for the dynamic programs.
#
ifdef SHARED_LIB
override DEPS := $(filter-out startup_dyn.lib,$(DEPS))
#
# Prevent linkage of startup code against shared libraries except for ld.lib.so
#
ifneq ($(LIB),ld)
override DEPS := $(filter-out startup.lib,$(DEPS))
endif

View File

@ -120,9 +120,13 @@ LD_CMD += -Wl,--dynamic-linker=$(DYNAMIC_LINKER).lib.so \
-Wl,--eh-frame-hdr
#
# Filter out the base libraries since they will be provided by the ldso.library
# Filter out the base libraries since they will be provided by the LDSO
# library and the startup library as the CRT0 part of program startup is
# done by LDSO already. As replacement for the startup library startup_dyn
# is used. The startup_dyn build is triggered by any shared library without
# merging it to the library.
#
FILTER_DEPS := $(filter-out $(BASE_LIBS),$(DEPS:.lib=))
FILTER_DEPS := $(filter-out $(BASE_LIBS) startup,$(DEPS:.lib=)) startup_dyn
SHARED_LIBS += $(LIB_CACHE_DIR)/$(DYNAMIC_LINKER)/$(DYNAMIC_LINKER).lib.so
#

View File

@ -23,7 +23,7 @@
/* Genode includes */
#include <base/printf.h>
#include <base/env.h>
#include <base/heap.h>
#include <base/heap.h>
/* local includes */
#include <platform_env_common.h>
@ -36,7 +36,9 @@ namespace Genode {
}
struct Genode::Expanding_rm_session_client : Upgradeable_client<Genode::Rm_session_client>
struct Genode::Expanding_rm_session_client
:
Upgradeable_client<Genode::Rm_session_client>
{
Expanding_rm_session_client(Rm_session_capability cap)
: Upgradeable_client<Genode::Rm_session_client>(cap) { }
@ -139,7 +141,29 @@ class Genode::Platform_env : public Genode::Env, public Emergency_ram_reserve
_emergency_ram_ds(_resources.ram.alloc(_emergency_ram_size()))
{ }
void reload_parent_cap(Native_capability::Dst, long);
/**
* Reload parent capability and reinitialize environment resources
*
* This function is solely used for implementing fork semantics.
* After forking a process, the new child process is executed
* within a copy of the address space of the forking process.
* Thereby, the new process inherits the original 'env' object of
* the forking process, which is meaningless in the context of the
* new process. By calling this function, the new process is able
* to reinitialize its 'env' with meaningful capabilities obtained
* via its updated parent capability.
*/
void reinit(Native_capability::Dst, long);
/**
* Reinitialize main-thread object
*
* \param context_area_rm new RM session of the context area
*
* This function is solely used for implementing fork semantics
* as provided by the Noux environment.
*/
void reinit_main_thread(Rm_session_capability &);
/*************************************

View File

@ -1,6 +1,7 @@
/*
* \brief Environment reinitialization
* \author Norman Feske
* \author Martin Stein
* \date 2012-02-16
*/
@ -11,12 +12,28 @@
* under the terms of the GNU General Public License version 2.
*/
/* env includes */
#include <platform_env.h>
/* Genode includes */
#include <util/construct_at.h>
#include <base/crt0.h>
#include <rm_session/connection.h>
void prepare_reinit_main_thread();
void reinit_main_thread();
namespace Genode
{
extern bool inhibit_tracing;
Rm_session * env_context_area_rm_session();
}
void Genode::Platform_env::reload_parent_cap(Native_capability::Dst dst,
long local_name)
void Genode::Platform_env::reinit(Native_capability::Dst dst,
long local_name)
{
/*
* This function is unused during the normal operation of Genode. It is
@ -32,21 +49,26 @@ void Genode::Platform_env::reload_parent_cap(Native_capability::Dst dst,
* provided by the actual parent.
*/
/* avoid RPCs by the tracing framework as long as we have no valid env */
inhibit_tracing = true;
/* do platform specific preparation */
prepare_reinit_main_thread();
/*
* Patch new parent capability into the original location as specified by
* the linker script.
*/
Native_capability::Raw *raw = (Native_capability::Raw *)(&_parent_cap);
raw->dst = dst;
raw->local_name = local_name;
raw->dst = dst;
raw->local_name = local_name;
/*
* Re-initialize 'Platform_env' members
*/
static_cast<Parent_client &>(_parent_client) = Parent_client(Genode::parent_cap());
_resources = Resources(_parent_client);
Expanding_parent_client * const p = &_parent_client;
construct_at<Expanding_parent_client>(p, parent_cap(), *this);
construct_at<Resources>(&_resources, _parent_client);
/*
* Keep information about dynamically allocated memory but use the new
@ -57,3 +79,20 @@ void Genode::Platform_env::reload_parent_cap(Native_capability::Dst dst,
*/
_heap.reassign_resources(&_resources.ram, &_resources.rm);
}
void
Genode::Platform_env::
reinit_main_thread(Rm_session_capability & context_area_rm)
{
/* reinitialize context area RM session */
Rm_session * const rms = env_context_area_rm_session();
Rm_session_client * const rmc = dynamic_cast<Rm_session_client *>(rms);
construct_at<Rm_session_client>(rmc, context_area_rm);
/* re-enable tracing */
inhibit_tracing = false;
/* reinitialize main-thread object */
::reinit_main_thread();
}

View File

@ -51,24 +51,34 @@ addr_t Thread_base::Context_allocator::addr_to_base(void *addr)
size_t Thread_base::Context_allocator::base_to_idx(addr_t base)
{
return (base - Native_config::context_area_virtual_base()) /
Native_config::context_virtual_size();
/* the first context isn't managed through the indices */
return ((base - Native_config::context_area_virtual_base()) /
Native_config::context_virtual_size()) - 1;
}
addr_t Thread_base::Context_allocator::idx_to_base(size_t idx)
{
/* the first context isn't managed through the indices */
return Native_config::context_area_virtual_base() +
idx * Native_config::context_virtual_size();
(idx + 1) * Native_config::context_virtual_size();
}
Thread_base::Context *Thread_base::Context_allocator::alloc(Thread_base *thread_base)
Thread_base::Context *
Thread_base::Context_allocator::alloc(Thread_base *thread_base, bool main_thread)
{
Lock::Guard _lock_guard(_threads_lock);
try {
return base_to_context(idx_to_base(_alloc.alloc()));
addr_t base;
if (main_thread) {
/* the main-thread context isn't managed by '_alloc' */
base = Native_config::context_area_virtual_base();
} else {
/* contexts besides main-thread context are managed by '_alloc' */
base = idx_to_base(_alloc.alloc());
}
return base_to_context(base);
} catch(Bit_allocator<MAX_THREADS>::Out_of_indices) {
return 0;
}
@ -78,8 +88,13 @@ Thread_base::Context *Thread_base::Context_allocator::alloc(Thread_base *thread_
void Thread_base::Context_allocator::free(Context *context)
{
Lock::Guard _lock_guard(_threads_lock);
addr_t const base = addr_to_base(context);
_alloc.free(base_to_idx(addr_to_base(context)));
/* the main-thread context isn't managed by '_alloc' */
if (base == Native_config::context_area_virtual_base()) { return; }
/* contexts besides main-thread context are managed by '_alloc' */
_alloc.free(base_to_idx(base));
}
@ -94,7 +109,8 @@ Thread_base::Context_allocator *Thread_base::_context_allocator()
}
Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
Thread_base::Context *
Thread_base::_alloc_context(size_t stack_size, bool main_thread)
{
/*
* Synchronize context list when creating new threads from multiple threads
@ -105,7 +121,7 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
Lock::Guard _lock_guard(alloc_lock);
/* allocate thread context */
Context *context = _context_allocator()->alloc(this);
Context *context = _context_allocator()->alloc(this, main_thread);
if (!context)
throw Context_alloc_failed();
@ -213,7 +229,7 @@ void Thread_base::join()
void* Thread_base::alloc_secondary_stack(char const *name, size_t stack_size)
{
Context *context = _alloc_context(stack_size);
Context *context = _alloc_context(stack_size, false);
strncpy(context->name, name, sizeof(context->name));
return (void *)context->stack_top();
}
@ -226,13 +242,14 @@ void Thread_base::free_secondary_stack(void* stack_addr)
}
Thread_base::Thread_base(const char *name, size_t stack_size)
Thread_base::Thread_base(const char *name, size_t stack_size, Type type)
:
_context(_alloc_context(stack_size)),
_context(type == REINITIALIZED_MAIN ?
_context : _alloc_context(stack_size, type == MAIN)),
_join_lock(Lock::LOCKED)
{
strncpy(_context->name, name, sizeof(_context->name));
_init_platform_thread();
_init_platform_thread(type);
}

View File

@ -36,9 +36,6 @@ void Thread_base::_thread_start()
** Thread base **
*****************/
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()
{
env()->cpu_session()->kill_thread(_thread_cap);

View File

@ -22,6 +22,7 @@
#include <base/env.h>
#include <base/heap.h>
#include <ram_session/client.h>
#include <rm_session/capability.h>
/* core includes */
#include <platform.h>
@ -174,7 +175,9 @@ namespace Genode {
return 0;
}
void reload_parent_cap(Capability<Parent>::Dst, long) { }
void reinit(Capability<Parent>::Dst, long) { }
void reinit_main_thread(Rm_session_capability &) { }
};

View File

@ -31,13 +31,8 @@
using namespace Genode;
extern int main(int argc, char **argv, char **envp);
extern void init_exception_handling(); /* implemented in base/cxx */
namespace Genode {
Rm_session *env_context_area_rm_session();
void platform_main_bootstrap();
}
namespace Genode { Rm_session *env_context_area_rm_session(); }
enum { ATEXIT_SIZE = 256 };
@ -46,6 +41,8 @@ enum { ATEXIT_SIZE = 256 };
** C++ stuff **
***************/
void * __dso_handle = 0;
enum Atexit_fn_type { ATEXIT_FN_EMPTY, ATEXIT_FN_STD, ATEXIT_FN_CXA };
struct atexit_fn
@ -229,11 +226,6 @@ namespace Genode { extern bool inhibit_tracing; }
*/
extern "C" int _main()
{
platform_main_bootstrap();
/* call env() explicitly to setup the environment */
(void*)env();
/*
* Allow exit handlers to be registered.
*
@ -244,34 +236,6 @@ extern "C" int _main()
*/
atexit_enable();
/* initialize exception handling */
init_exception_handling();
/*
* We create the thread-context area as early as possible to prevent other
* mappings from occupying the predefined virtual-memory region.
*/
env_context_area_rm_session();
/*
* Trigger first exception. This step has two purposes.
* First, it enables us to detect problems related to exception handling as
* early as possible. If there are problems with the C++ support library,
* it is much easier to debug them at this early stage. Otherwise problems
* with half-working exception handling cause subtle failures that are hard
* to interpret.
*
* Second, the C++ support library allocates data structures lazily on the
* first occurrence of an exception. This allocation traverses into
* Genode's heap and, in some corner cases, consumes several KB of stack.
* This is usually not a problem when the first exception is triggered from
* the main thread but it becomes an issue when the first exception is
* thrown from the context of a thread with a specially tailored (and
* otherwise sufficient) stack size. By throwing an exception here, we
* mitigate this issue by eagerly performing those allocations.
*/
try { throw 1; } catch (...) { }
/* call constructors for static objects */
void (**func)();
for (func = &_ctors_end; func != &_ctors_start; (*--func)());

View File

@ -1,6 +1,7 @@
/**
* \brief Startup code for Genode applications on ARM
* \author Norman Feske
* \author Martin Stein
* \date 2007-04-28
*/
@ -11,34 +12,58 @@
* under the terms of the GNU General Public License version 2.
*/
/*--- .text (program code) -------------------------*/
/**************************
** .text (program code) **
**************************/
.section ".text.crt0"
.globl _start
_start:
/* program entry-point */
.global _start
_start:
ldr r4, .initial_sp
/* make initial value of some registers available to higher-level code */
ldr r4, =__initial_sp
str sp, [r4]
ldr sp, .stack_high
b _main
/*
* Install initial temporary environment that is replaced later by the
* environment that init_main_thread creates.
*/
ldr sp, =_stack_high
.initial_sp: .word __initial_sp
.stack_high: .word _stack_high
/* create proper environment for main thread */
bl init_main_thread
.globl __dso_handle
__dso_handle: .long 0
/* apply environment that was created by init_main_thread */
ldr sp, =init_main_thread_result
ldr sp, [sp]
/* jump into init C code instead of calling it as it should never return */
b _main
/*********************************
** .bss (non-initialized data) **
*********************************/
/*--- .bss (non-initialized data) ------------------*/
.section ".bss"
/* stack of the temporary initial environment */
.p2align 4
.globl _stack_low
_stack_low:
.space 128*1024
.globl _stack_high
_stack_high:
.global _stack_low
_stack_low:
.space 128 * 1024
.global _stack_high
_stack_high:
/* initial value of the SP register */
.globl __initial_sp
__initial_sp: .space 4
.global __initial_sp
__initial_sp:
.space 4
/* return value of init_main_thread */
.global init_main_thread_result
init_main_thread_result:
.space 4

View File

@ -0,0 +1,130 @@
/*
* \brief Setup the thread environment of a programs first thread
* \author Christian Helmuth
* \author Christian Prochaska
* \author Martin Stein
* \date 2013-12-04
*/
/*
* 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.
*/
/* Genode includes */
#include <util/construct_at.h>
#include <base/env.h>
#include <base/printf.h>
#include <base/thread.h>
using namespace Genode;
extern addr_t init_main_thread_result;
extern void init_exception_handling();
namespace Genode { Rm_session * env_context_area_rm_session(); }
void prepare_init_main_thread();
enum { MAIN_THREAD_STACK_SIZE = 16UL * 1024 * sizeof(Genode::addr_t) };
/**
* The first thread in a program
*/
class Main_thread : public Thread<MAIN_THREAD_STACK_SIZE>
{
public:
/**
* Constructor
*
* \param reinit wether this is called for reinitialization
*/
Main_thread(bool reinit)
:
Thread("main", reinit ? REINITIALIZED_MAIN : MAIN)
{ }
/**********************
** Thread interface **
**********************/
void entry() { }
};
Main_thread * main_thread()
{
static Main_thread s(false);
return &s;
}
/**
* Create a thread object for the main thread
*
* \return stack pointer of the new environment via init_main_thread_result
*
* This function must be called only once per program and before the _main
* function. It can be called as soon as a temporary environment provides
* some stack space and inter-process communication. At this stage, global
* static objects are not registered for implicit destruction at program exit.
*/
extern "C" void init_main_thread()
{
/* do platform specific preparation */
prepare_init_main_thread();
/*
* Explicitly setup program environment at this point to ensure that its
* destructor won't be registered for the atexit routine.
*/
(void*)env();
/* initialize exception handling */
init_exception_handling();
/*
* We create the thread-context area as early as possible to prevent other
* mappings from occupying the predefined virtual-memory region.
*/
env_context_area_rm_session();
/*
* Trigger first exception. This step has two purposes.
* First, it enables us to detect problems related to exception handling as
* early as possible. If there are problems with the C++ support library,
* it is much easier to debug them at this early stage. Otherwise problems
* with half-working exception handling cause subtle failures that are hard
* to interpret.
*
* Second, the C++ support library allocates data structures lazily on the
* first occurrence of an exception. This allocation traverses into
* Genode's heap and, in some corner cases, consumes several KB of stack.
* This is usually not a problem when the first exception is triggered from
* the main thread but it becomes an issue when the first exception is
* thrown from the context of a thread with a specially tailored (and
* otherwise sufficient) stack size. By throwing an exception here, we
* mitigate this issue by eagerly performing those allocations.
*/
try { throw 1; } catch (...) { }
/* create a thread object for the main thread */
main_thread();
/**
* The new stack pointer enables the caller to switch from its current
* environment to the those that the thread object provides.
*/
addr_t sp = reinterpret_cast<addr_t>(main_thread()->stack_top());
init_main_thread_result = sp;
}
/**
* Reinitialize main-thread object according to a reinitialized environment
*/
void reinit_main_thread() { construct_at<Main_thread>(main_thread(), true); }

View File

@ -1,6 +1,7 @@
/**
* \brief Startup code for Genode applications
* \author Christian Helmuth
* \author Martin Stein
* \date 2009-08-12
*/
@ -11,53 +12,79 @@
* under the terms of the GNU General Public License version 2.
*/
/*--- .text (program code) -------------------------*/
.text
.global _start
_start:
/**************************
** .text (program code) **
**************************/
.text
/* program entry-point */
.global _start
_start:
/* make initial value of some registers available to higher-level code */
mov %esp, __initial_sp
mov %eax, __initial_ax
mov %edi, __initial_di
/* XXX Switch to our own stack. */
/*
* Install initial temporary environment that is replaced later by the
* environment that init_main_thread creates.
*/
leal _stack_high, %esp
/* Clear the base pointer so that stack backtraces will work. */
/* create proper environment for the main thread */
call init_main_thread
/* apply environment that was created by init_main_thread */
movl init_main_thread_result, %esp
/* clear the base pointer in order that stack backtraces will work */
xor %ebp,%ebp
/* Jump into init C code */
call _main
/* jump into init C code instead of calling it as it should never return */
jmp _main
/* We should never get here since _main does not return */
1: int $3
jmp 2f
.ascii "_main() returned."
2: jmp 1b
.globl __dso_handle
__dso_handle: .long 0
/**********************************
** .eh_frame (exception frames) **
**********************************/
/*--- .eh_frame (exception frames) -----------------*/
/*
.section .eh_frame,"aw"
.section .eh_frame,"aw"
.global __EH_FRAME_BEGIN__
__EH_FRAME_BEGIN__:
__EH_FRAME_BEGIN__:
*/
/*--- .bss (non-initialized data) ------------------*/
.bss
/*********************************
** .bss (non-initialized data) **
*********************************/
.bss
/* stack of the temporary initial environment */
.p2align 4
.global _stack_low
_stack_low:
.space 64*1024
_stack_low:
.space 64 * 1024
.global _stack_high
_stack_high:
_stack_high:
/* initial value of the ESP, EAX and EDI register */
.globl __initial_sp
.globl __initial_ax
.globl __initial_di
__initial_sp: .space 4
__initial_ax: .space 4
__initial_di: .space 4
.global __initial_sp
__initial_sp:
.space 4
.global __initial_ax
__initial_ax:
.space 4
.global __initial_di
__initial_di:
.space 4
/* return value of init_main_thread */
.global init_main_thread_result
init_main_thread_result:
.space 4

View File

@ -1,6 +1,7 @@
/**
* \brief Startup code for Genode 64Bit applications
* \author Sebastian Sumpf
* \author Martin Stein
* \date 2011-05-11
*/
@ -11,60 +12,90 @@
* under the terms of the GNU General Public License version 2.
*/
/*--- .text (program code) -------------------------*/
.text
/**************************
** .text (program code) **
**************************/
.text
/* program entry-point */
.global _start
_start:
_start:
/* make initial value of some registers available to higher-level code */
movq __initial_ax@GOTPCREL(%rip), %rbx
movq %rax, (%rbx)
movq __initial_di@GOTPCREL(%rip), %rbx
movq %rdi, (%rbx)
movq __initial_sp@GOTPCREL(%rip), %rax
movq %rsp, (%rax)
/* XXX Switch to our own stack. */
/*
* Install initial temporary environment that is replaced later by the
* environment that init_main_thread creates.
*/
leaq _stack_high@GOTPCREL(%rip),%rax
movq (%rax), %rsp
/* Clear the base pointer so that stack backtraces will work. */
xorq %rbp,%rbp
/* create proper environment for the main thread */
call init_main_thread
/* Jump into init C code */
call _main
/* apply environment that was created by init_main_thread */
movq init_main_thread_result@GOTPCREL(%rip), %rax
movq (%rax), %rsp
/* We should never get here since _main does not return */
1: int $3
jmp 2f
.ascii "_main() returned."
2: jmp 1b
/* clear the base pointer in order that stack backtraces will work */
xorq %rbp, %rbp
.globl __dso_handle
__dso_handle: .quad 0
/*
* We jump into initial C code instead of calling it as it should never
* return on the one hand and because the alignment of the stack pointer
* that init_main_thread returned expects a jump at the other hand. The
* latter matters because GCC expects the initial stack pointer to be
* aligned to 16 byte for at least the handling of floating points.
*/
jmp _main
/**********************************
** .eh_frame (exception frames) **
**********************************/
/*--- .eh_frame (exception frames) -----------------*/
/*
.section .eh_frame,"aw"
.section .eh_frame,"aw"
.global __EH_FRAME_BEGIN__
__EH_FRAME_BEGIN__:
__EH_FRAME_BEGIN__:
*/
/*--- .bss (non-initialized data) ------------------*/
.bss
/*********************************
** .bss (non-initialized data) **
*********************************/
.bss
/* stack of the temporary initial environment */
.p2align 8
.global _stack_low
_stack_low:
.space 64*1024
_stack_low:
.space 64 * 1024
.global _stack_high
_stack_high:
_stack_high:
/* initial value of the RSP, RAX and RDI register */
.globl __initial_sp
__initial_sp:
.space 8
.globl __initial_ax
__initial_ax:
.space 8
.globl __initial_di
__initial_sp: .space 8
__initial_ax: .space 8
__initial_di: .space 8
__initial_di:
.space 8
/* return value of init_main_thread */
.globl init_main_thread_result
init_main_thread_result:
.space 8

View File

@ -7,8 +7,6 @@ INC_DIR += $(REP_DIR)/src/lib/ffat/contrib
SRC_C = ff.c ccsbcs.c
SRC_CC = diskio_block.cc
LIBS = base
vpath % $(REP_DIR)/src/lib/ffat/
vpath % $(REP_DIR)/contrib/ff007e/src
vpath % $(REP_DIR)/contrib/ff007e/src/option

5
os/lib/mk/startup_dyn.mk Normal file
View File

@ -0,0 +1,5 @@
SRC_CC += _main.cc
REP_INC_DIR += src/platform
vpath _main.cc $(BASE_DIR)/src/platform

View File

@ -1,6 +1,7 @@
/**
* \brief Startup code for Genode applications on ARM
* \author Norman Feske
* \author Martin Stein
* \date 2007-04-28
*/
@ -11,19 +12,40 @@
* under the terms of the GNU General Public License version 2.
*/
/*--- .text (program code) -------------------------*/
/**************************
** .text (program code) **
**************************/
.section ".text.crt0"
/* linker entry-point */
.globl _start_ldso
_start_ldso:
_start_ldso:
ldr r2, .initial_sp
/* make initial value of some registers available to higher-level code */
ldr r2, =__initial_sp
str sp, [r2]
ldr sp, .stack_high
/*
* Install initial temporary environment that is replaced later by the
* environment that init_main_thread creates.
*/
ldr sp, =_stack_high
/* let init_rtld relocate linker */
bl init_rtld
b _main
.initial_sp: .word __initial_sp
.stack_high: .word _stack_high
/* create proper environment for the main thread */
bl init_main_thread
/* apply environment that was created by init_main_thread */
ldr sp, =init_main_thread_result
ldr sp, [sp]
/* call init C code */
bl _main
/* this should never be reached since _main should never return */
_catch_main_return:
b _catch_main_return

View File

@ -1,6 +1,7 @@
/*
* \brief Call main function (ARM specific)
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
* \author Martin Stein
* \date 2011-05-05
*/
@ -13,20 +14,32 @@
#ifndef _ARM__CALL_MAIN_H_
#define _ARM__CALL_MAIN_H_
/**
* Restore SP from initial sp and jump to entry function
*/
void call_main(void (*func)(void))
{
extern long __initial_sp;
void * my_stack_top();
void set_program_var(const char *, const void *);
asm volatile ("mov %%sp, %0;"
"bx %1;"
:
: "r" (__initial_sp),
"r" (func)
: "memory"
);
extern void * __initial_sp;
/**
* Call program _main with the environment that its CRT0 would have created
*
* \param _main_fp pointer to _main function of dynamic program
*/
void call_main(void (*_main_fp)(void))
{
/* make initial value of some registers available to dynamic program */
set_program_var("__initial_sp", __initial_sp);
/*
* We could also do a call but that would enable the the program main to
* return to LDSO wich isn't desired. This means also that not resetting
* the SP to stack top as we do would waste stack memory for dead LDSO
* frames.
*/
asm volatile ("mov sp, %[sp];"
"bx %[ip];"
:: [sp] "r" (my_stack_top()),
[ip] "r" (_main_fp)
: "memory");
}
#endif /* _ARM__CALL_MAIN_H_ */

View File

@ -1,6 +1,7 @@
/*
* \brief Call main function (X86 specific)
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
* \author Martin Stein
* \date 2011-05-02
*/
@ -13,20 +14,37 @@
#ifndef _X86_32__CALL_MAIN_H_
#define _X86_32__CALL_MAIN_H_
/**
* Restore SP from initial sp and jump to entry function
*/
void call_main(void (*func)(void))
{
extern long __initial_sp;
void * my_stack_top();
void set_program_var(const char *, const void *);
asm volatile ("mov %0, %%esp;"
"jmp *%1;"
:
: "r" (__initial_sp),
"r" (func)
: "memory"
);
extern void * __initial_sp;
extern void * __initial_ax;
extern void * __initial_di;
/**
* Call program _main with the environment that its CRT0 would have created
*
* \param _main_fp pointer to _main function of dynamic program
*/
void call_main(void (*_main_fp)(void))
{
/* make initial value of some registers available to dynamic program */
set_program_var("__initial_sp", __initial_sp);
set_program_var("__initial_ax", __initial_ax);
set_program_var("__initial_di", __initial_di);
/*
* We could also do a call but that would enable the the program main to
* return to LDSO wich isn't desired. This means also that not resetting
* the SP to stack top as we do would waste stack memory for dead LDSO
* frames.
*/
asm volatile ("mov %[sp], %%esp;"
"xor %%ebp, %%ebp;"
"jmp *%[ip];"
:: [sp] "r" (my_stack_top()),
[ip] "r" (_main_fp)
: "memory");
}
#endif /* _X86_32__CALL_MAIN_H_ */

View File

@ -1,6 +1,7 @@
/*
* \brief Call main function (X86 64 bit specific)
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
* \author Martin Stein
* \date 2011-05-011
*/
@ -13,20 +14,37 @@
#ifndef _X86_64__CALL_MAIN_H_
#define _X86_64__CALL_MAIN_H_
/**
* Restore SP from initial sp and jump to entry function
*/
void call_main(void (*func)(void))
{
extern long __initial_sp;
void * my_stack_top();
void set_program_var(const char *, const void *);
asm volatile ("movq %0, %%rsp;"
"jmpq *%1;"
:
: "r" (__initial_sp),
"r" (func)
: "memory"
);
extern void * __initial_sp;
extern void * __initial_ax;
extern void * __initial_di;
/**
* Call program _main with the environment that its CRT0 would have created
*
* \param _main_fp pointer to _main function of dynamic program
*/
void call_main(void (*_main_fp)(void))
{
/* make initial value of some registers available to dynamic program */
set_program_var("__initial_sp", __initial_sp);
set_program_var("__initial_ax", __initial_ax);
set_program_var("__initial_di", __initial_di);
/*
* We could also do a call but that would enable the the program main to
* return to LDSO wich isn't desired. This means also that not resetting
* the SP to stack top as we do would waste stack memory for dead LDSO
* frames.
*/
asm volatile ("movq %[sp], %%rsp;"
"xorq %%rbp, %%rbp;"
"jmpq *%[ip];"
:: [sp] "r" (my_stack_top()),
[ip] "r" (_main_fp)
: "memory");
}
#endif /* _X86_64__CALL_MAIN_H_ */

View File

@ -7,7 +7,7 @@ SRC_S = rtld_start.S
SRC_C = reloc.c rtld.c map_object.c xmalloc.c debug.c main.c \
ldso_types.c rtld_dummies.c platform.c
SRC_CC = stdio.cc stdlib.cc file.cc err.cc string.cc lock.cc \
test.cc environ.cc
test.cc environ.cc thread.cc
INC_DIR += $(DIR)/ \
$(DIR)/contrib \

24
os/src/lib/ldso/thread.cc Normal file
View File

@ -0,0 +1,24 @@
/*
* \brief Thread related C helpers
* \author Martin Stein
* \date 2013-12-13
*/
/*
* 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.
*/
/* Genode includes */
#include <base/thread.h>
/**
* Return top end of the stack of the calling thread
*/
extern "C" void * my_stack_top()
{
return Genode::Thread_base::myself()->stack_top();
}

View File

@ -2,6 +2,7 @@
* \brief Startup code for ld.lib.so (x86-32)
* \author Christian Helmuth
* \author Sebastian Sumpf
* \author Martin Stein
* \date 2011-05-03
*/
@ -12,39 +13,60 @@
* under the terms of the GNU General Public License version 2.
*/
/*--- .text (program code) -------------------------*/
.text
/**************************
** .text (program code) **
**************************/
.text
/* linker entry-point */
.global _start_ldso
_start_ldso:
_start_ldso:
/* initialize GOT pointer in EBX */
3:
/* The follwing statement causes a text relocation which will be ignored by
* ldso itself, this is necessary since we don't have a valid stack pointer at
* this moment so a 'call' in order to retrieve our IP and thus calculate the
* GOT-position in the traditional manner is not possible on x86
/*
* Initialize GOT pointer in EBX.
*
* The follwing statement causes a text relocation which will be ignored
* by ldso itself, this is necessary since we don't have a valid stack
* pointer at this moment so a 'call' in order to retrieve our IP and thus
* calculate the GOT-position in the traditional manner is not possible on
* x86.
*/
3:
movl $., %ebx
addl $_GLOBAL_OFFSET_TABLE_ + (. - 3b) , %ebx
/* make initial value of some registers available to higher-level code */
movl %esp, __initial_sp@GOTOFF(%ebx)
movl %eax, __initial_ax@GOTOFF(%ebx)
movl %edi, __initial_di@GOTOFF(%ebx)
/* XXX Switch to our own stack. */
/*
* Install initial temporary environment that is replaced later by the
* environment that init_main_thread creates.
*/
leal _stack_high@GOTOFF(%ebx), %esp
/* relocate ldso */
/* let init_rtld relocate LDSO */
call init_rtld
/* Clear the base pointer so that stack backtraces will work. */
/* create proper environment for the main thread */
call init_main_thread
/* apply environment that was created by init_main_thread */
movl init_main_thread_result, %esp
/* clear the base pointer so that stack backtraces will work */
xor %ebp,%ebp
/* Jump into init C code */
/* jump into init C code */
call _main
/* We should never get here since _main does not return */
1: int $3
/* we should never get here since _main does not return */
1:
int $3
jmp 2f
.ascii "_main() returned."
2: jmp 1b
2:
jmp 1b

View File

@ -2,6 +2,7 @@
* \brief Startup code for ldso 64Bit version
* \author Christian Helmuth
* \author Sebastian Sumpf
* \author Martin Stein
* \date 2011-05-10
*/
@ -12,32 +13,55 @@
* under the terms of the GNU General Public License version 2.
*/
/*--- .text (program code) -------------------------*/
.text
/**************************
** .text (program code) **
**************************/
.text
/* linker entry-point */
.globl _start_ldso
_start_ldso:
_start_ldso:
/* initialize GLOBAL OFFSET TABLE */
/* initialize global offset table */
leaq _GLOBAL_OFFSET_TABLE_(%rip),%r15
/* make initial value of some registers available to higher-level code */
movq __initial_ax@GOTPCREL(%rip), %rbx
movq %rax, (%rbx)
movq __initial_di@GOTPCREL(%rip), %rbx
movq %rdi, (%rbx)
movq __initial_sp@GOTPCREL(%rip), %rax
movq %rsp, (%rax)
/* XXX Switch to our own stack. */
/*
* Install initial temporary environment that is replaced later by the
* environment that init_main_thread creates.
*/
leaq _stack_high@GOTPCREL(%rip),%rax
movq (%rax), %rsp
/* let init_rtld relocate LDSO */
call init_rtld
/* Clear the base pointer so that stack backtraces will work. */
/* create proper environment for the main thread */
call init_main_thread
/* apply environment that was created by init_main_thread */
movq init_main_thread_result@GOTPCREL(%rip), %rax
movq (%rax), %rsp
/* clear the base pointer so that stack backtraces will work */
xorq %rbp,%rbp
/* Jump into init C code */
/* jump into init C code */
call _main
/* We should never get here since _main does not return */
1: int $3
/* we should never get here since _main does not return */
1:
int $3
jmp 2f
.ascii "_main() returned."
2: jmp 1b
2:
jmp 1b

View File

@ -11,7 +11,12 @@
* under the terms of the GNU General Public License version 2.
*/
ENTRY(_start)
/*
* Program doesn't need to startup with CRT0 as LDSO has done this
* initialization during its own CRT0 already.
*/
ENTRY(_main)
PHDRS
{

View File

@ -4,6 +4,8 @@ LIBS += libc
REP_INC_DIR += src/lib/libc
INC_DIR += $(BASE_DIR)/src/base/env/
vpath %.cc $(REP_DIR)/src/lib/libc_noux
SHARED_LIB = yes

View File

@ -12,12 +12,14 @@
*/
/* Genode includes */
#include <util/construct_at.h>
#include <util/misc_math.h>
#include <util/arg_string.h>
#include <base/printf.h>
#include <rom_session/connection.h>
#include <base/sleep.h>
#include <dataspace/client.h>
#include <platform_env.h>
/* noux includes */
#include <noux_session/connection.h>
@ -60,9 +62,6 @@ enum { verbose = false };
enum { verbose_signals = false };
void *operator new (size_t, void *ptr) { return ptr; }
class Noux_connection
{
private:
@ -79,13 +78,6 @@ class Noux_connection
Noux_connection() : _sysio(_obtain_sysio()) { }
void reconnect()
{
new (&_connection) Noux_connection;
Genode::env()->rm_session()->detach(_sysio);
_sysio = _obtain_sysio();
}
/**
* Return the capability of the local context-area RM session
*/
@ -495,11 +487,22 @@ extern "C" void stdout_reconnect(); /* provided by 'log_console.cc' */
*/
extern "C" void fork_trampoline()
{
Genode::env()->reload_parent_cap(new_parent.dst, new_parent.local_name);
/* reinitialize environment */
using namespace Genode;
Platform_env * const platform_env = dynamic_cast<Platform_env *>(env());
platform_env->reinit(new_parent.dst, new_parent.local_name);
/* reinitialize standard-output connection */
stdout_reconnect();
noux_connection()->reconnect();
/* reinitialize noux connection */
construct_at<Noux_connection>(noux_connection());
/* reinitialize main-thread object which implies reinit of context area */
auto context_area_rm = noux_connection()->context_area_rm_session();
platform_env->reinit_main_thread(context_area_rm);
/* apply processor state that the forker had when he did the fork */
longjmp(fork_jmp_buf, 1);
}
@ -507,7 +510,7 @@ extern "C" void fork_trampoline()
extern "C" pid_t fork(void)
{
/* stack used for executing 'fork_trampoline' */
enum { STACK_SIZE = 1024 };
enum { STACK_SIZE = 8 * 1024 };
static long stack[STACK_SIZE];
if (setjmp(fork_jmp_buf)) {