Fixed DISABLE_SMT to report the right max_vcores
[akaros.git] / kern / arch / i686 / atomic.h
1 #ifndef ROS_INCLUDE_ATOMIC_H
2 #define ROS_INCLUDE_ATOMIC_H
3
4 #include <ros/common.h>
5 #include <arch/x86.h>
6 #include <arch/arch.h>
7
8 typedef void * RACY atomic_t;
9 struct spinlock {
10         volatile uint32_t RACY rlock;
11 #ifdef __CONFIG_SPINLOCK_DEBUG__
12         void *call_site;        
13         uint32_t calling_core;
14 #endif
15 };
16 typedef struct spinlock RACY spinlock_t;
17 #define SPINLOCK_INITIALIZER {0}
18
19 static inline void atomic_init(atomic_t *number, int32_t val);
20 static inline int32_t atomic_read(atomic_t *number);
21 static inline void atomic_set(atomic_t *number, int32_t val);
22 static inline void atomic_inc(atomic_t *number);
23 static inline void atomic_dec(atomic_t *number);
24 static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val);
25 static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
26                                     uint32_t new_val);
27 static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
28 static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
29 static inline uint32_t spin_locked(spinlock_t *SAFE lock);
30 static inline void __spin_lock(volatile uint32_t SRACY*CT(1) rlock);
31 static inline void spin_lock(spinlock_t *lock);
32 static inline void spin_unlock(spinlock_t *lock);
33 static inline void spinlock_init(spinlock_t *lock);
34 void spinlock_debug(spinlock_t *lock);
35
36 /* Inlined functions declared above */
37 static inline void atomic_init(atomic_t *number, int32_t val)
38 {
39         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
40 }
41
42 static inline int32_t atomic_read(atomic_t *number)
43 {
44         int32_t val;
45         asm volatile("movl %1,%0" : "=r"(val) : "m"(*number));
46         return val;
47 }
48
49 static inline void atomic_set(atomic_t *number, int32_t val)
50 {
51         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
52 }
53
54 // need to do this with pointers and deref.  %0 needs to be the memory address
55 static inline void atomic_inc(atomic_t *number)
56 {
57         asm volatile("lock incl %0" : "=m"(*number) : : "cc");
58 }
59
60 static inline void atomic_dec(atomic_t *number)
61 {
62         // for instance, this doesn't work:
63         //asm volatile("lock decl (%0)" : "=r"(number) : : "cc");
64         asm volatile("lock decl %0" : "=m"(*number) : : "cc");
65 }
66
67 static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val)
68 {
69         // this would work, but its code is bigger, and it's not like the others
70         //asm volatile("xchgl %0,(%2)" : "=r"(val) : "0"(val), "r"(addr) : "memory");
71         asm volatile("xchgl %0,%1" : "=r"(val), "=m"(*addr) : "0"(val), "m"(*addr));
72         return val;
73 }
74
75 /* reusing exp_val for the bool return */
76 static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
77                                     uint32_t new_val)
78 {
79         asm volatile("lock cmpxchgl %4,%1; sete %%al"
80                      : "=a"(exp_val), "=m"(*addr)
81                      : "m"(*addr), "a"(exp_val), "r"(new_val)
82                      : "cc");
83         return exp_val;
84 }
85
86 /* Be sure to use "q" for byte operations (compared to longs), since this
87  * constrains the asm to use e{a,b,c,d}x instead of esi and edi.  32 bit x86
88  * cannot access the lower parts of esi or edi (will get warnings like "no such
89  * register %sil or %dil." */
90 static inline void atomic_andb(volatile uint8_t RACY*number, uint8_t mask)
91 {
92         asm volatile("lock andb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
93 }
94
95 static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
96 {
97         asm volatile("lock orb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
98 }
99
100 static inline uint32_t spin_locked(spinlock_t *SAFE lock)
101 {
102         // the lock status is the lowest byte of the lock
103         return lock->rlock & 0xff;
104 }
105
106 static inline void __spin_lock(volatile uint32_t *rlock)
107 {
108         asm volatile(
109                         "1:                       "
110                         "       cmpb $0, %0;          "
111                         "       je 2f;                "
112                         "       pause;                "
113                         "       jmp 1b;               "
114                         "2:                       " 
115                         "       movb $1, %%al;        "
116                         "       xchgb %%al, %0;       "
117                         "       cmpb $0, %%al;        "
118                         "       jne 1b;               "
119                 : : "m"(*rlock) : "eax", "cc");
120 }
121
122 static inline void spin_lock(spinlock_t *lock)
123 {
124         __spin_lock(&lock->rlock);
125 #ifdef __CONFIG_SPINLOCK_DEBUG__
126         lock->call_site = (void RACY*CT(1))TC(read_eip());
127         lock->calling_core = core_id();
128 #endif
129 }
130
131 static inline void spin_unlock(spinlock_t *lock)
132 {
133         lock->rlock = 0;
134 }
135
136 static inline void spinlock_init(spinlock_t *lock)
137 #ifdef __CONFIG_SPINLOCK_DEBUG__
138 WRITES(lock->rlock,lock->call_site,lock->calling_core)
139 #else
140 WRITES(lock->rlock)
141 #endif
142 {
143         lock->rlock = 0;
144 #ifdef __CONFIG_SPINLOCK_DEBUG__
145         lock->call_site = 0;
146         lock->calling_core = 0;
147 #endif
148 }
149
150 #endif /* !ROS_INCLUDE_ATOMIC_H */