mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-27 01:11:06 +00:00
ec6c19a487
The memory barrier prevents the compiler from changing the program order of memory accesses in such a way that accesses to the guarded resource get outside the guarded stage. As cmpxchg() defines the start of the guarded stage it also represents an effective memory barrier. On x86, the architecture ensures to not reorder writes with older reads, writes to memory with other writes (except in cases that are not relevant for our locks), or read/write instructions with I/O instructions, locked instructions, and serializing instructions. However on ARM, the architectural memory model allows not only that memory accesses take local effect in another order as their program order but also that different observers (components that can access memory like data-busses, TLBs and branch predictors) observe these effects each in another order. Thus, a correct program order isn't sufficient for a correct observation order. An additional architectural preservation of the memory barrier is needed to achieve this. Fixes #692
60 lines
1.5 KiB
C++
60 lines
1.5 KiB
C++
/*
|
|
* \brief Atomic operations for ARM
|
|
* \author Norman Feske
|
|
* \author Stefan Kalkowski
|
|
* \date 2007-04-28
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2007-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 _INCLUDE__ARM__CPU__ATOMIC_H_
|
|
#define _INCLUDE__ARM__CPU__ATOMIC_H_
|
|
|
|
#include <cpu/memory_barrier.h>
|
|
|
|
namespace Genode {
|
|
|
|
/**
|
|
* Atomic compare and exchange
|
|
*
|
|
* This function compares the value at dest with cmp_val.
|
|
* If both values are equal, dest is set to new_val. If
|
|
* both values are different, the value at dest remains
|
|
* unchanged.
|
|
*
|
|
* Note, that cmpxchg() represents a memory barrier.
|
|
*
|
|
* \return 1 if the value was successfully changed to new_val,
|
|
* 0 if cmp_val and the value at dest differ.
|
|
*/
|
|
inline int cmpxchg(volatile int *dest, int cmp_val, int new_val)
|
|
{
|
|
unsigned long equal, not_exclusive;
|
|
|
|
__asm__ __volatile__(
|
|
"@ cmpxchg\n"
|
|
" 1: \n"
|
|
" ldrex %0, [%2] \n"
|
|
" cmp %0, %3 \n"
|
|
" bne 2f \n"
|
|
" strexeq %0, %4, [%2]\n"
|
|
" teqeq %0, #0 \n"
|
|
" bne 1b \n"
|
|
" moveq %1, #1 \n"
|
|
" 2: \n"
|
|
" movne %1, #0 \n"
|
|
: "=&r" (not_exclusive), "=&r" (equal)
|
|
: "r" (dest), "r" (cmp_val), "r" (new_val)
|
|
: "cc");
|
|
Genode::memory_barrier();
|
|
return equal && !not_exclusive;
|
|
}
|
|
}
|
|
|
|
#endif /* _INCLUDE__ARM__CPU__ATOMIC_H_ */
|