base-hw: Avoid early calls of cmpxchg

This patch eliminates calls of 'cmpxchg' prior enabling the MMU. This is
needed because the 'ldrex' and 'strex' instructions do not always work
with MMU and L1 cache disabled, i.e., on Raspberry Pi.
This commit is contained in:
Norman Feske 2013-05-14 22:40:30 +02:00
parent ddffc8765e
commit 71cd7b9d2e
6 changed files with 91 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/**
/*
* \brief Genode-console backend
* \author Martin Stein
* \date 2011-10-17
@ -16,6 +16,9 @@
#include <base/printf.h>
#include <drivers/serial_log.h>
/* 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<Platform_console>();
}

View File

@ -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 <typename T, int ALIGN = 2, typename... Args>
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<T *>(inst);
}
#endif /* _SINGLETON_H_ */

View File

@ -33,6 +33,9 @@
#include <tlb.h>
#include <trustzone.h>
/* base-hw includes */
#include <singleton.h>
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<Mode_transition_control>(); }
/**
* 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<Pic>(); }
}
@ -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<Core_tlb, tlb_align>();
Pd *pd = unsynchronized_singleton<Pd>(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]

View File

@ -25,6 +25,9 @@
#include <timer.h>
#include <assert.h>
/* base-hw includes */
#include <singleton.h>
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<Id_alloc>();
}
public:
@ -224,8 +226,7 @@ namespace Kernel
*/
static Pool * pool()
{
static Pool _pool;
return &_pool;
return unsynchronized_singleton<Pool>();
}
/**

View File

@ -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

View File

@ -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),