diff --git a/base-hw/src/base/console.cc b/base-hw/src/base/console.cc index 046a5e61d8..ddb8636758 100644 --- a/base-hw/src/base/console.cc +++ b/base-hw/src/base/console.cc @@ -1,4 +1,4 @@ -/** +/* * \brief Genode-console backend * \author Martin Stein * \date 2011-10-17 @@ -16,6 +16,9 @@ #include #include +/* base-hw includes */ +#include "singleton.h" + namespace Genode { /** @@ -63,8 +66,7 @@ using namespace Genode; */ static Platform_console * platform_console() { - static Platform_console static_platform_console; - return &static_platform_console; + return unsynchronized_singleton(); } diff --git a/base-hw/src/base/singleton.h b/base-hw/src/base/singleton.h new file mode 100644 index 0000000000..c1fb05487b --- /dev/null +++ b/base-hw/src/base/singleton.h @@ -0,0 +1,53 @@ +/* + * \brief Helper for creating singleton objects + * \author Norman Feske + * \date 2013-05-14 + * + * Before enabling the MMU on ARM, the 'cmpxchg' implementation is not always + * guaranteed to work. For example, on the Raspberry Pi, the 'ldrex' as used by + * 'cmpxchg' causes the machine to reboot. After enabling the MMU, everything + * is fine. Hence, we need to avoid executing 'cmpxchg' prior this point. + * Unfortunately, 'cmpxchg' is implicitly called each time when creating a + * singleton object via a local-static object pattern. In this case, the + * compiler generates code that calls the '__cxa_guard_acquire' function of the + * C++ runtime, which, in turn, relies 'cmpxchg' for synchronization. + * + * The utility provided herein is an alternative way to create single object + * instances without implicitly calling 'cmpxchg'. Because object creation is + * not synchronized via a spin lock, it must not be used in scenarios where + * multiple threads may contend. + */ + +/* + * 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. + */ + +#ifndef _SINGLETON_H_ +#define _SINGLETON_H_ + +inline void *operator new(Genode::size_t, void *at) { return at; } + + +template +static inline T *unsynchronized_singleton(Args... args) +{ + /* + * Each instantiation of the function template with a different type 'T' + * yields a dedicated instance of the local static variables, thereby + * creating the living space for the singleton objects. + */ + static bool initialized; + static int inst[sizeof(T)/sizeof(int) + 1] __attribute__((aligned(ALIGN))); + + /* execute constructor on first call */ + if (!initialized) { + initialized = true; + new (&inst) T(args...); + } + return reinterpret_cast(inst); +} + +#endif /* _SINGLETON_H_ */ diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc index 6e6e219779..372aeeecc9 100644 --- a/base-hw/src/core/kernel.cc +++ b/base-hw/src/core/kernel.cc @@ -33,6 +33,9 @@ #include #include +/* base-hw includes */ +#include + using namespace Kernel; /* get core configuration */ @@ -262,7 +265,7 @@ namespace Kernel * Static mode transition control */ static Mode_transition_control * mtc() - { static Mode_transition_control _object; return &_object; } + { return unsynchronized_singleton(); } /** * Kernel object that represents a Genode PD @@ -333,7 +336,7 @@ namespace Kernel /** * Access to static interrupt-controller */ - static Pic * pic() { static Pic _object; return &_object; } + static Pic * pic() { return unsynchronized_singleton(); } } @@ -407,9 +410,11 @@ namespace Kernel */ static Pd * core() { - static Core_tlb tlb; - static Pd _pd(&tlb, 0); - return &_pd; + constexpr int tlb_align = 1 << Core_tlb::ALIGNM_LOG2; + + Core_tlb *core_tlb = unsynchronized_singleton(); + Pd *pd = unsynchronized_singleton(core_tlb, nullptr); + return pd; } @@ -1421,6 +1426,12 @@ extern "C" void kernel() /* switch to core address space */ Cpu::init_virt_kernel(core()->tlb()->base(), core_id()); + /* + * From this point on, it is safe to use 'cmpxchg', i.e., to create + * singleton objects via the static-local object pattern. See + * the comment in 'src/base/singleton.h'. + */ + /* create the core main thread */ static Native_utcb cm_utcb; static char cm_stack[DEFAULT_STACK_SIZE] diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h index 1ef64829bf..e3c7e8e700 100644 --- a/base-hw/src/core/kernel/thread.h +++ b/base-hw/src/core/kernel/thread.h @@ -25,6 +25,9 @@ #include #include +/* base-hw includes */ +#include + namespace Genode { class Platform_thread; @@ -211,8 +214,7 @@ namespace Kernel */ static Id_alloc * _id_alloc() { - static Id_alloc _id_alloc; - return &_id_alloc; + return unsynchronized_singleton(); } public: @@ -224,8 +226,7 @@ namespace Kernel */ static Pool * pool() { - static Pool _pool; - return &_pool; + return unsynchronized_singleton(); } /** diff --git a/base-hw/src/core/target.inc b/base-hw/src/core/target.inc index fea0b9649d..b10dd597bb 100644 --- a/base-hw/src/core/target.inc +++ b/base-hw/src/core/target.inc @@ -13,11 +13,15 @@ CC_OPT += -DCORE_MAIN=_main # add library dependencies LIBS += base-common +# enable C++11 support +CC_CXX_OPT += -std=gnu++11 + # add include paths INC_DIR += $(REP_DIR)/src/core \ $(REP_DIR)/src/core/include \ $(REP_DIR)/include \ $(REP_DIR)/src/platform \ + $(REP_DIR)/src/base \ $(BASE_DIR)/src/core/include \ $(BASE_DIR)/include \ $(BASE_DIR)/src/platform diff --git a/base-hw/src/core/tlb/arm.h b/base-hw/src/core/tlb/arm.h index dd96aaec74..0c788c259b 100644 --- a/base-hw/src/core/tlb/arm.h +++ b/base-hw/src/core/tlb/arm.h @@ -106,7 +106,14 @@ namespace Arm /* lookup table for AP bitfield values according to 'w' and 'k' flag */ typedef typename T::Ap_1_0 Ap_1_0; typedef typename T::Ap_2 Ap_2; - static typename T::access_t const ap_bits[2][2] = {{ + + /* + * Note: Don't make 'ap_bits' static to avoid implicit use of 'cmpxchg' + * prior enabling the MMU. + * + * XXX Replace array with a simpler-to-grasp switch statement. + */ + typename T::access_t const ap_bits[2][2] = {{ Ap_1_0::bits(Ap_1_0::USER_RO_ACCESS) | /* -- */ Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS),