Userspace no longer includes the kernel's arch/*
[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 static inline void atomic_andb(volatile uint8_t RACY*number, uint8_t mask)
87 {
88         asm volatile("lock andb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
89 }
90
91 static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
92 {
93         asm volatile("lock orb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
94 }
95
96 static inline uint32_t spin_locked(spinlock_t *SAFE lock)
97 {
98         // the lock status is the lowest byte of the lock
99         return lock->rlock & 0xff;
100 }
101
102 static inline void __spin_lock(volatile uint32_t *rlock)
103 {
104         asm volatile(
105                         "1:                       "
106                         "       cmpb $0, %0;          "
107                         "       je 2f;                "
108                         "       pause;                "
109                         "       jmp 1b;               "
110                         "2:                       " 
111                         "       movb $1, %%al;        "
112                         "       xchgb %%al, %0;       "
113                         "       cmpb $0, %%al;        "
114                         "       jne 1b;               "
115                 : : "m"(*rlock) : "eax", "cc");
116 }
117
118 static inline void spin_lock(spinlock_t *lock)
119 {
120         __spin_lock(&lock->rlock);
121 #ifdef __CONFIG_SPINLOCK_DEBUG__
122         lock->call_site = (void RACY*CT(1))TC(read_eip());
123         lock->calling_core = core_id();
124 #endif
125 }
126
127 static inline void spin_unlock(spinlock_t *lock)
128 {
129         lock->rlock = 0;
130 }
131
132 static inline void spinlock_init(spinlock_t *lock)
133 #ifdef __CONFIG_SPINLOCK_DEBUG__
134 WRITES(lock->rlock,lock->call_site,lock->calling_core)
135 #else
136 WRITES(lock->rlock)
137 #endif
138 {
139         lock->rlock = 0;
140 #ifdef __CONFIG_SPINLOCK_DEBUG__
141         lock->call_site = 0;
142         lock->calling_core = 0;
143 #endif
144 }
145
146 #endif /* !ROS_INCLUDE_ATOMIC_H */