Merge remote branch 'origin/sparc-dev'
[akaros.git] / kern / arch / i386 / atomic.h
1 #ifndef ROS_INCLUDE_ATOMIC_H
2 #define ROS_INCLUDE_ATOMIC_H
3
4 /* This enables tracking who last locked a spinlock. */
5 #define SPINLOCK_DEBUG
6
7 #include <ros/common.h>
8 #include <arch/x86.h>
9 #include <arch/arch.h>
10
11 #define mb() {rmb(); wmb();}
12 #define rmb() ({ asm volatile("lfence"); })
13 #define wmb() 
14 /* Force a wmb, used in cases where an IPI could beat a write, even though
15  * write-orderings are respected. */
16 #define wmb_f() ({ asm volatile("sfence"); })
17
18 typedef void * RACY atomic_t;
19 struct spinlock {
20         volatile uint32_t RACY rlock;
21 #ifdef SPINLOCK_DEBUG
22         void *call_site;        
23         uint32_t calling_core;
24 #endif
25 };
26 typedef struct spinlock RACY spinlock_t;
27 #define SPINLOCK_INITIALIZER {0}
28
29 static inline void atomic_init(atomic_t *number, int32_t val);
30 static inline int32_t atomic_read(atomic_t *number);
31 static inline void atomic_set(atomic_t *number, int32_t val);
32 static inline void atomic_inc(atomic_t *number);
33 static inline void atomic_dec(atomic_t *number);
34 static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
35 static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
36 static inline uint32_t spin_locked(spinlock_t *SAFE lock);
37 static inline void __spin_lock(volatile uint32_t SRACY*CT(1) rlock);
38 static inline void spin_lock(spinlock_t *lock);
39 static inline void spin_unlock(spinlock_t *lock);
40 static inline void spinlock_init(spinlock_t *lock);
41 void spinlock_debug(spinlock_t *lock);
42
43 /* Inlined functions declared above */
44 static inline void atomic_init(atomic_t *number, int32_t val)
45 {
46         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
47 }
48
49 static inline int32_t atomic_read(atomic_t *number)
50 {
51         int32_t val;
52         asm volatile("movl %1,%0" : "=r"(val) : "m"(*number));
53         return val;
54 }
55
56 static inline void atomic_set(atomic_t *number, int32_t val)
57 {
58         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
59 }
60
61 // need to do this with pointers and deref.  %0 needs to be the memory address
62 static inline void atomic_inc(atomic_t *number)
63 {
64         asm volatile("lock incl %0" : "=m"(*number) : : "cc");
65 }
66
67 static inline void atomic_dec(atomic_t *number)
68 {
69         asm volatile("lock decl %0" : "=m"(*number) : : "cc");
70 }
71
72 static inline void atomic_andb(volatile uint8_t RACY*number, uint8_t mask)
73 {
74         asm volatile("lock andb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
75 }
76
77 static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
78 {
79         asm volatile("lock orb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
80 }
81
82 static inline uint32_t spin_locked(spinlock_t *SAFE lock)
83 {
84         // the lock status is the lowest byte of the lock
85         return lock->rlock & 0xff;
86 }
87
88 static inline void __spin_lock(volatile uint32_t *rlock)
89 {
90         asm volatile(
91                         "1:                       "
92                         "       cmpb $0, %0;          "
93                         "       je 2f;                "
94                         "       pause;                "
95                         "       jmp 1b;               "
96                         "2:                       " 
97                         "       movb $1, %%al;        "
98                         "       xchgb %%al, %0;       "
99                         "       cmpb $0, %%al;        "
100                         "       jne 1b;               "
101                 : : "m"(*rlock) : "eax", "cc");
102 }
103
104 static inline void spin_lock(spinlock_t *lock)
105 {
106         __spin_lock(&lock->rlock);
107 #ifdef SPINLOCK_DEBUG
108         lock->call_site = (void RACY*CT(1))TC(read_eip());
109         lock->calling_core = core_id();
110 #endif
111 }
112
113 static inline void spin_unlock(spinlock_t *lock)
114 {
115         lock->rlock = 0;
116 }
117
118 static inline void spinlock_init(spinlock_t *lock)
119 #ifdef SPINLOCK_DEBUG
120 WRITES(lock->rlock,lock->call_site,lock->calling_core)
121 #else
122 WRITES(lock->rlock)
123 #endif
124 {
125         lock->rlock = 0;
126 #ifdef SPINLOCK_DEBUG
127         lock->call_site = 0;
128         lock->calling_core = 0;
129 #endif
130 }
131
132 #endif /* !ROS_INCLUDE_ATOMIC_H */