Signed-off-by: Jason Wang <jasowang@xxxxxxxxxx> --- config-x86-common.mak | 1 lib/x86/atomic.c | 37 +++++++++++ lib/x86/atomic.h | 164 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 0 deletions(-) create mode 100644 lib/x86/atomic.c create mode 100644 lib/x86/atomic.h diff --git a/config-x86-common.mak b/config-x86-common.mak index fdb9e3e..b8ca859 100644 --- a/config-x86-common.mak +++ b/config-x86-common.mak @@ -10,6 +10,7 @@ cflatobjs += \ cflatobjs += lib/x86/fwcfg.o cflatobjs += lib/x86/apic.o +cflatobjs += lib/x86/atomic.o $(libcflat): LDFLAGS += -nostdlib $(libcflat): CFLAGS += -ffreestanding -I lib diff --git a/lib/x86/atomic.c b/lib/x86/atomic.c new file mode 100644 index 0000000..da74ff2 --- /dev/null +++ b/lib/x86/atomic.c @@ -0,0 +1,37 @@ +#include <libcflat.h> +#include "atomic.h" + +#ifdef __i386__ + +u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new) +{ + u32 low = new; + u32 high = new >> 32; + + asm volatile("lock cmpxchg8b %1\n" + : "+A" (old), + "+m" (*(volatile long long *)&v->counter) + : "b" (low), "c" (high) + : "memory" + ); + + return old; +} + +#else + +u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new) +{ + u64 ret; + u64 _old = old; + u64 _new = new; + + asm volatile("lock cmpxchgq %2,%1" + : "=a" (ret), "+m" (*(volatile long *)&v->counter) + : "r" (_new), "0" (_old) + : "memory" + ); + return ret; +} + +#endif diff --git a/lib/x86/atomic.h b/lib/x86/atomic.h new file mode 100644 index 0000000..de2f033 --- /dev/null +++ b/lib/x86/atomic.h @@ -0,0 +1,164 @@ +#ifndef __ATOMIC_H +#define __ATOMIC_H + +typedef struct { + volatile int counter; +} atomic_t; + +#ifdef __i386__ + +/** + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const atomic_t *v) +{ + return v->counter; +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(atomic_t *v, int i) +{ + v->counter = i; +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(atomic_t *v) +{ + asm volatile("lock incl %0" + : "+m" (v->counter)); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(atomic_t *v) +{ + asm volatile("lock decl %0" + : "+m" (v->counter)); +} + +typedef struct { + u64 __attribute__((aligned(8))) counter; +} atomic64_t; + +#define ATOMIC64_INIT(val) { (val) } + +/** + * atomic64_read - read atomic64 variable + * @ptr: pointer to type atomic64_t + * + * Atomically reads the value of @ptr and returns it. + */ +static inline u64 atomic64_read(atomic64_t *ptr) +{ + u64 res; + + /* + * Note, we inline this atomic64_t primitive because + * it only clobbers EAX/EDX and leaves the others + * untouched. We also (somewhat subtly) rely on the + * fact that cmpxchg8b returns the current 64-bit value + * of the memory location we are touching: + */ + asm volatile("mov %%ebx, %%eax\n\t" + "mov %%ecx, %%edx\n\t" + "lock cmpxchg8b %1\n" + : "=&A" (res) + : "m" (*ptr) + ); + return res; +} + +u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new); + +#elif defined(__x86_64__) + +/** + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const atomic_t *v) +{ + return v->counter; +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(atomic_t *v, int i) +{ + v->counter = i; +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(atomic_t *v) +{ + asm volatile("lock incl %0" + : "=m" (v->counter) + : "m" (v->counter)); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(atomic_t *v) +{ + asm volatile("lock decl %0" + : "=m" (v->counter) + : "m" (v->counter)); +} + +typedef struct { + long long counter; +} atomic64_t; + +#define ATOMIC64_INIT(i) { (i) } + +/** + * atomic64_read - read atomic64 variable + * @v: pointer of type atomic64_t + * + * Atomically reads the value of @v. + * Doesn't imply a read memory barrier. + */ +static inline long atomic64_read(const atomic64_t *v) +{ + return v->counter; +} + +u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new); + +#endif + +#endif -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html