[haiku-commits] haiku: hrev46092 - src/system/kernel/arch/arm src/system/libroot/os/arch/arm headers/private/system/arch/arm

  • From: ithamar@xxxxxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 18 Sep 2013 05:08:17 +0200 (CEST)

hrev46092 adds 1 changeset to branch 'master'
old head: cc65466f0de34d946d9311517f4e7781b7294ef8
new head: 501b24c63b267527538aa4a7591348b3832bb84d
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=501b24c+%5Ecc65466

----------------------------------------------------------------------------

501b24c: ARM: kernel: Make 32/64-bit atomics work for ARMv5/6
  
  Support for 64-bit atomic operations for ARMv7+ is currently stubbed
  out in libroot, but our current targets do not use it anyway.
  
  We now select atomics-as-syscalls automatically based on the ARM
  architecture we're building for. The intent is to do away with
  most of the board specifics (at the very least on the kernel side)
  and just specify the lowest ARMvX version you want to build for.
  
  This will give flexibility in being able to distribute a single
  image for a wide range of devices, and building a tuned system
  for one specific core type.

                          [ Ithamar R. Adema <ithamar@xxxxxxxxxxxxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev46092
Commit:      501b24c63b267527538aa4a7591348b3832bb84d
URL:         http://cgit.haiku-os.org/haiku/commit/?id=501b24c
Author:      Ithamar R. Adema <ithamar@xxxxxxxxxxxxxxxxxxx>
Date:        Wed Sep 18 03:03:18 2013 UTC

----------------------------------------------------------------------------

5 files changed, 389 insertions(+), 90 deletions(-)
headers/private/system/arch/arm/arch_config.h |  10 +-
src/system/kernel/arch/arm/Jamfile            |   5 +-
src/system/kernel/arch/arm/arch_atomic32.cpp  | 177 ++++++++++++++++++++
src/system/kernel/arch/arm/arch_atomic64.cpp  | 192 ++++++++++++++++++++++
src/system/libroot/os/arch/arm/atomic.S       |  95 +----------

----------------------------------------------------------------------------

diff --git a/headers/private/system/arch/arm/arch_config.h 
b/headers/private/system/arch/arm/arch_config.h
index 409f58d..5e20381 100644
--- a/headers/private/system/arch/arm/arch_config.h
+++ b/headers/private/system/arch/arm/arch_config.h
@@ -10,8 +10,14 @@
 
 #define STACK_GROWS_DOWNWARDS
 
-//#define ATOMIC_FUNCS_ARE_SYSCALLS
-//#define ATOMIC64_FUNCS_ARE_SYSCALLS
+// If we're building on ARMv5 or older, all our atomics need to be syscalls... 
:(
+#if _M_ARM <= 5
+#define ATOMIC_FUNCS_ARE_SYSCALLS
+#endif
 
+// If we're building on ARMv6 or older, 64-bit atomics need to be syscalls...
+#if _M_ARM < 7
+#define ATOMIC64_FUNCS_ARE_SYSCALLS
+#endif
 
 #endif /* _KERNEL_ARCH_ARM_CONFIG_H */
diff --git a/src/system/kernel/arch/arm/Jamfile 
b/src/system/kernel/arch/arm/Jamfile
index 25e4f8a..8386a75 100644
--- a/src/system/kernel/arch/arm/Jamfile
+++ b/src/system/kernel/arch/arm/Jamfile
@@ -10,10 +10,8 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) paging 32bit ] ;
 SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ;
 
 KernelMergeObject kernel_arch_arm.o :
-#      arch_atomic.c
        arch_commpage.cpp
        arch_cpu.cpp
-#      arch_cpu_asm.S
        arch_debug_console.cpp
        arch_debug.cpp
        arch_elf.cpp
@@ -33,6 +31,9 @@ KernelMergeObject kernel_arch_arm.o :
        arch_uart_8250.cpp
        arch_uart_pl011.cpp
 
+       arch_atomic64.cpp
+       arch_atomic32.cpp
+
        # paging
        arm_physical_page_mapper.cpp
        arm_physical_page_mapper_large_memory.cpp
diff --git a/src/system/kernel/arch/arm/arch_atomic32.cpp 
b/src/system/kernel/arch/arm/arch_atomic32.cpp
new file mode 100644
index 0000000..df10e72
--- /dev/null
+++ b/src/system/kernel/arch/arm/arch_atomic32.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2013 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Ithamar R. Adema, ithamar@xxxxxxxxxxxxxxxxxxx
+ */
+
+#include <KernelExport.h>
+
+#include <kernel.h>
+#include <user_atomic.h>
+
+#include <util/AutoLock.h>
+
+#ifdef ATOMIC_FUNCS_ARE_SYSCALLS
+
+/*
+ * NOTE: These functions are _intentionally_ not using spinlocks, unlike
+ * the 64 bit versions. The reason for this is that they are used by the
+ * spinlock code itself, and therefore would deadlock.
+ *
+ * Since these are only really needed for ARMv5, which is not SMP anyway,
+ * this is an acceptable compromise.
+ */
+
+int32
+atomic_set(vint32 *value, int32 newValue)
+{
+       InterruptsLocker locker;
+
+       int32 oldValue = *value;
+       *value = newValue;
+       return oldValue;
+}
+
+int32
+atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst)
+{
+       InterruptsLocker locker;
+
+       int32 oldValue = *value;
+       if (oldValue == testAgainst)
+               *value = newValue;
+       return oldValue;
+}
+
+int32
+atomic_add(vint32 *value, int32 addValue)
+{
+       InterruptsLocker locker;
+
+       int32 oldValue = *value;
+       *value += addValue;
+       return oldValue;
+}
+
+int32
+atomic_and(vint32 *value, int32 andValue)
+{
+       InterruptsLocker locker;
+
+       int32 oldValue = *value;
+       *value &= andValue;
+       return oldValue;
+}
+
+int32
+atomic_or(vint32 *value, int32 orValue)
+{
+       InterruptsLocker locker;
+
+       int32 oldValue = *value;
+       *value |= orValue;
+       return oldValue;
+}
+
+int32
+atomic_get(vint32 *value)
+{
+       InterruptsLocker locker;
+
+       int32 oldValue = *value;
+       return oldValue;
+}
+
+int32
+_user_atomic_set(vint32 *value, int32 newValue)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == 
B_OK) {
+               int32 oldValue = atomic_set(value, newValue);
+               unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+int32
+_user_atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == 
B_OK) {
+               int32 oldValue = atomic_test_and_set(value, newValue, 
testAgainst);
+               unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+int32
+_user_atomic_add(vint32 *value, int32 addValue)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == 
B_OK) {
+               int32 oldValue = atomic_add(value, addValue);
+               unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+int32
+_user_atomic_and(vint32 *value, int32 andValue)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == 
B_OK) {
+               int32 oldValue = atomic_and(value, andValue);
+               unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+int32
+_user_atomic_or(vint32 *value, int32 orValue)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == 
B_OK) {
+               int32 oldValue = atomic_or(value, orValue);
+               unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+int32
+_user_atomic_get(vint32 *value)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == 
B_OK) {
+               int32 oldValue = atomic_get(value);
+               unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+#endif /* ATOMIC_FUNCS_ARE_SYSCALLS */
diff --git a/src/system/kernel/arch/arm/arch_atomic64.cpp 
b/src/system/kernel/arch/arm/arch_atomic64.cpp
new file mode 100644
index 0000000..a57fd61
--- /dev/null
+++ b/src/system/kernel/arch/arm/arch_atomic64.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2013 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Ithamar R. Adema, ithamar@xxxxxxxxxxxxxxxxxxx
+ */
+
+#include <KernelExport.h>
+
+#include <kernel.h>
+#include <user_atomic.h>
+
+#include <util/AutoLock.h>
+
+#ifdef ATOMIC64_FUNCS_ARE_SYSCALLS
+
+/*
+ * NOTE: Unlike their 32-bit counterparts, these functions can use
+ * spinlocks safely currently, as no atomic 64-bit operations are
+ * done in the spinlock code. If this ever changes, this code will
+ * have to change.
+ *
+ * This code is here for ARMv6, which cannot do proper 64-bit atomic
+ * operations. Anything newer is capable, and does therefore not
+ * depend on this code.
+ */
+
+
+static spinlock atomic_lock = B_SPINLOCK_INITIALIZER;
+
+
+int64
+atomic_set64(vint64 *value, int64 newValue)
+{
+       SpinLocker locker(&atomic_lock);
+
+       int64 oldValue = *value;
+       *value = newValue;
+       return oldValue;
+}
+
+
+int64
+atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst)
+{
+       SpinLocker locker(&atomic_lock);
+
+       int64 oldValue = *value;
+       if (oldValue == testAgainst)
+               *value = newValue;
+       return oldValue;
+}
+
+
+int64
+atomic_add64(vint64 *value, int64 addValue)
+{
+       SpinLocker locker(&atomic_lock);
+
+       int64 oldValue = *value;
+       *value += addValue;
+       return oldValue;
+}
+
+
+int64
+atomic_and64(vint64 *value, int64 andValue)
+{
+       SpinLocker locker(&atomic_lock);
+
+       int64 oldValue = *value;
+       *value &= andValue;
+       return oldValue;
+}
+
+
+int64
+atomic_or64(vint64 *value, int64 orValue)
+{
+       SpinLocker locker(&atomic_lock);
+
+       int64 oldValue = *value;
+       *value |= orValue;
+       return oldValue;
+}
+
+
+int64
+atomic_get64(vint64 *value)
+{
+       SpinLocker locker(&atomic_lock);
+       return *value;
+}
+
+
+int64
+_user_atomic_set64(vint64 *value, int64 newValue)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == 
B_OK) {
+               int64 oldValue = atomic_set64(value, newValue);
+               unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+
+int64
+_user_atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == 
B_OK) {
+               int64 oldValue = atomic_test_and_set64(value, newValue, 
testAgainst);
+               unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+
+int64
+_user_atomic_add64(vint64 *value, int64 addValue)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == 
B_OK) {
+               int64 oldValue = atomic_add64(value, addValue);
+               unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+
+int64
+_user_atomic_and64(vint64 *value, int64 andValue)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == 
B_OK) {
+               int64 oldValue = atomic_and64(value, andValue);
+               unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+
+int64
+_user_atomic_or64(vint64 *value, int64 orValue)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == 
B_OK) {
+               int64 oldValue = atomic_or64(value, orValue);
+               unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+
+int64
+_user_atomic_get64(vint64 *value)
+{
+       if (IS_USER_ADDRESS(value)
+               && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == 
B_OK) {
+               int64 oldValue = atomic_get64(value);
+               unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
+               return oldValue;
+       }
+
+access_violation:
+       // XXX kill application
+       return -1;
+}
+
+#endif /* ATOMIC64_FUNCS_ARE_SYSCALLS */
diff --git a/src/system/libroot/os/arch/arm/atomic.S 
b/src/system/libroot/os/arch/arm/atomic.S
index 795e899..f27bfd7 100644
--- a/src/system/libroot/os/arch/arm/atomic.S
+++ b/src/system/libroot/os/arch/arm/atomic.S
@@ -4,14 +4,15 @@
 */
 
 #include <asm_defs.h>
-
+#include <arch_config.h>
 
 .text
 
+#ifndef ATOMIC_FUNCS_ARE_SYSCALLS
+
 /* int atomic_add(int *value, int increment)
  */
 FUNCTION(atomic_add):
-#if __ARM_ARCH__ >= 6
 miss1:         ldrex       r12, [r0]
                add         r2,  r12, r1
                strex       r3,  r2,  [r0]
@@ -19,25 +20,6 @@ miss1:               ldrex       r12, [r0]
                bne         miss1
                mov         r0,  r12
                bx          lr
-#else
-        /* disable interrupts, do the add, and reenable */
-        mrs     r2, cpsr
-        mov     r12, r2
-        orr     r2, r2, #(3<<6)
-        msr     cpsr_c, r2
-
-        /* ints disabled, old cpsr state in r12 */
-
-        /* do the add, leave the previous value in r0 */
-        mov     r3, r0
-        ldr     r0, [r3]
-        add     r2, r0, r1
-        str     r2, [r3]
-
-        /* restore interrupts and exit */
-        msr     cpsr_c, r12
-        bx      lr
-#endif
 FUNCTION_END(atomic_add)
 
 
@@ -46,7 +28,6 @@ FUNCTION_END(atomic_add)
 /* int atomic_and(int *value, int andValue)
  */
 FUNCTION(atomic_and):
-#if __ARM_ARCH__ >= 6
 miss2:         ldrex       r12, [r0]
                and         r2,  r12, r1
                strex       r3,  r2,  [r0]
@@ -54,33 +35,11 @@ miss2:              ldrex       r12, [r0]
                bne         miss2
                mov         r0,  r12
                bx          lr
-#else
-        /* disable interrupts, do the and, and reenable */
-        mrs     r2, cpsr
-        mov     r12, r2
-        orr     r2, r2, #(3<<6)
-        msr     cpsr_c, r2
-
-        /* ints disabled, old cpsr state in r12 */
-
-        /* do the and, leave the previous value in r0 */
-        mov     r3, r0
-        ldr     r0, [r3]
-        and     r2, r0, r1
-        str     r2, [r3]
-
-        /* restore interrupts and exit */
-        msr     cpsr_c, r12
-        bx      lr
-#endif
-
 FUNCTION_END(atomic_and)
 
 /* int atomic_or(int *value, int orValue)
  */
 FUNCTION(atomic_or):
-#if __ARM_ARCH__ >= 6
-
 miss3:         ldrex       r12, [r0]
                eor         r2,  r12, r1
                strex       r3,  r2,  [r0]
@@ -88,48 +47,21 @@ miss3:              ldrex       r12, [r0]
                bne         miss3
                mov         r0,  r12
                bx      lr
-#else
-        /* disable interrupts, do the or, and reenable */
-        mrs     r2, cpsr
-        mov     r12, r2
-        orr     r2, r2, #(3<<6)
-        msr     cpsr_c, r2
-
-        /* ints disabled, old cpsr state in r12 */
-
-        /* do the or, leave the previous value in r0 */
-        mov     r3, r0
-        ldr     r0, [r3]
-        orr     r2, r0, r1
-        str     r2, [r3]
-
-        /* restore interrupts and exit */
-        msr     cpsr_c, r12
-        bx      lr
-#endif
-
 FUNCTION_END(atomic_or)
 
 /* int atomic_set(int *value, int setTo)
  */
 FUNCTION(atomic_set):
-#if __ARM_ARCH__ >= 6
 miss4:         ldrex   r12, [r0]
                        strex   r3, r1, [r0]
                        teq     r3, #0
                        bne     miss4
                bx  lr
-#else
-       mov     r3, r0
-       swp     r0, r1, [r3]
-        bx      lr
-#endif
 FUNCTION_END(atomic_set)
 
 /* int atomic_test_and_set(int *value, int setTo, int testValue) 
  */
 FUNCTION(atomic_test_and_set):
-#if __ARM_ARCH__ >= 6
 miss5:  ldrex       r12, [r0]                       @ load from the address 
and mark it exclusive
         cmp         r12, r2                         @ compare the value with 
the comperand(r2)
         strexeq     r3,  r1,  [r0]                  @ if they were equal, 
attempt to store the new value (r1)
@@ -139,21 +71,6 @@ miss5:  ldrex       r12, [r0]                       @ load 
from the address and
         bne         same                            @ if it succeeded, jump to 
(same) and return. there is no need to clrex if strex succeeded
 differ: clrex                                      @ clrex
 same:   mov         r0,  r12
-#else
-        /* disable interrupts, and save state */
-        mrs     r3, cpsr
-        mov     r12, r3
-        orr     r3, r3, #(3<<6)
-        msr     cpsr_c, r3
-
-       mov     r3, r0
-       ldr     r0, [r3]
-       cmp     r0, r2
-       streq   r1, [r3]
-
-        /* restore interrupts and exit */
-        msr     cpsr_c, r12
-#endif
         bx      lr
 FUNCTION_END(atomic_test_and_set)
 
@@ -168,6 +85,10 @@ FUNCTION(__sync_fetch_and_add_4):
        bx      lr
 FUNCTION_END(__sync_fetch_and_add_4)
 
+#endif
+
+#ifndef ATOMIC64_FUNCS_ARE_SYSCALLS
+
 /* int64       atomic_add64(vint64 *value, int64 addValue) */
 FUNCTION(atomic_add64):
        bx      lr
@@ -197,3 +118,5 @@ FUNCTION_END(atomic_test_and_set64)
 FUNCTION(atomic_get64):
        bx      lr
 FUNCTION_END(atomic_get64)
+
+#endif /* ATOMIC64_FUNCS_ARE_SYSCALLS */


Other related posts:

  • » [haiku-commits] haiku: hrev46092 - src/system/kernel/arch/arm src/system/libroot/os/arch/arm headers/private/system/arch/arm - ithamar