qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

atomic64.c (2537B)


      1 /*
      2  * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
      3  *
      4  * License: GNU GPL, version 2 or later.
      5  *   See the COPYING file in the top-level directory.
      6  */
      7 #include "qemu/osdep.h"
      8 #include "qemu/atomic.h"
      9 #include "qemu/thread.h"
     10 #include "qemu/cacheinfo.h"
     11 #include "qemu/memalign.h"
     12 
     13 #ifdef CONFIG_ATOMIC64
     14 #error This file must only be compiled if !CONFIG_ATOMIC64
     15 #endif
     16 
     17 /*
     18  * When !CONFIG_ATOMIC64, we serialize both reads and writes with spinlocks.
     19  * We use an array of spinlocks, with padding computed at run-time based on
     20  * the host's dcache line size.
     21  * We point to the array with a void * to simplify the padding's computation.
     22  * Each spinlock is located every lock_size bytes.
     23  */
     24 static void *lock_array;
     25 static size_t lock_size;
     26 
     27 /*
     28  * Systems without CONFIG_ATOMIC64 are unlikely to have many cores, so we use a
     29  * small array of locks.
     30  */
     31 #define NR_LOCKS 16
     32 
     33 static QemuSpin *addr_to_lock(const void *addr)
     34 {
     35     uintptr_t a = (uintptr_t)addr;
     36     uintptr_t idx;
     37 
     38     idx = a >> qemu_dcache_linesize_log;
     39     idx ^= (idx >> 8) ^ (idx >> 16);
     40     idx &= NR_LOCKS - 1;
     41     return lock_array + idx * lock_size;
     42 }
     43 
     44 #define GEN_READ(name, type)                    \
     45     type name(const type *ptr)                  \
     46     {                                           \
     47         QemuSpin *lock = addr_to_lock(ptr);     \
     48         type ret;                               \
     49                                                 \
     50         qemu_spin_lock(lock);                   \
     51         ret = *ptr;                             \
     52         qemu_spin_unlock(lock);                 \
     53         return ret;                             \
     54     }
     55 
     56 GEN_READ(qatomic_read_i64, int64_t)
     57 GEN_READ(qatomic_read_u64, uint64_t)
     58 #undef GEN_READ
     59 
     60 #define GEN_SET(name, type)                     \
     61     void name(type *ptr, type val)              \
     62     {                                           \
     63         QemuSpin *lock = addr_to_lock(ptr);     \
     64                                                 \
     65         qemu_spin_lock(lock);                   \
     66         *ptr = val;                             \
     67         qemu_spin_unlock(lock);                 \
     68     }
     69 
     70 GEN_SET(qatomic_set_i64, int64_t)
     71 GEN_SET(qatomic_set_u64, uint64_t)
     72 #undef GEN_SET
     73 
     74 void qatomic64_init(void)
     75 {
     76     int i;
     77 
     78     lock_size = ROUND_UP(sizeof(QemuSpin), qemu_dcache_linesize);
     79     lock_array = qemu_memalign(qemu_dcache_linesize, lock_size * NR_LOCKS);
     80     for (i = 0; i < NR_LOCKS; i++) {
     81         QemuSpin *lock = lock_array + i * lock_size;
     82 
     83         qemu_spin_init(lock);
     84     }
     85 }