2
0

atomic64.c 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  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. #ifdef CONFIG_ATOMIC64
  11. #error This file must only be compiled if !CONFIG_ATOMIC64
  12. #endif
  13. /*
  14. * When !CONFIG_ATOMIC64, we serialize both reads and writes with spinlocks.
  15. * We use an array of spinlocks, with padding computed at run-time based on
  16. * the host's dcache line size.
  17. * We point to the array with a void * to simplify the padding's computation.
  18. * Each spinlock is located every lock_size bytes.
  19. */
  20. static void *lock_array;
  21. static size_t lock_size;
  22. /*
  23. * Systems without CONFIG_ATOMIC64 are unlikely to have many cores, so we use a
  24. * small array of locks.
  25. */
  26. #define NR_LOCKS 16
  27. static QemuSpin *addr_to_lock(const void *addr)
  28. {
  29. uintptr_t a = (uintptr_t)addr;
  30. uintptr_t idx;
  31. idx = a >> qemu_dcache_linesize_log;
  32. idx ^= (idx >> 8) ^ (idx >> 16);
  33. idx &= NR_LOCKS - 1;
  34. return lock_array + idx * lock_size;
  35. }
  36. #define GEN_READ(name, type) \
  37. type name(const type *ptr) \
  38. { \
  39. QemuSpin *lock = addr_to_lock(ptr); \
  40. type ret; \
  41. \
  42. qemu_spin_lock(lock); \
  43. ret = *ptr; \
  44. qemu_spin_unlock(lock); \
  45. return ret; \
  46. }
  47. GEN_READ(atomic_read_i64, int64_t)
  48. GEN_READ(atomic_read_u64, uint64_t)
  49. #undef GEN_READ
  50. #define GEN_SET(name, type) \
  51. void name(type *ptr, type val) \
  52. { \
  53. QemuSpin *lock = addr_to_lock(ptr); \
  54. \
  55. qemu_spin_lock(lock); \
  56. *ptr = val; \
  57. qemu_spin_unlock(lock); \
  58. }
  59. GEN_SET(atomic_set_i64, int64_t)
  60. GEN_SET(atomic_set_u64, uint64_t)
  61. #undef GEN_SET
  62. void atomic64_init(void)
  63. {
  64. int i;
  65. lock_size = ROUND_UP(sizeof(QemuSpin), qemu_dcache_linesize);
  66. lock_array = qemu_memalign(qemu_dcache_linesize, lock_size * NR_LOCKS);
  67. for (i = 0; i < NR_LOCKS; i++) {
  68. QemuSpin *lock = lock_array + i * lock_size;
  69. qemu_spin_init(lock);
  70. }
  71. }