x86: Fixes TLS bug causing kernel page faults
[akaros.git] / kern / arch / sparc / atomic.h
1 #ifndef ROS_INCLUDE_ATOMIC_H
2 #define ROS_INCLUDE_ATOMIC_H
3
4 #include <ros/common.h>
5 #include <arch/membar.h>
6
7 typedef struct
8 {
9         volatile uint32_t rlock;
10 } spinlock_t;
11
12 #define SPINLOCK_INITIALIZER {0}
13
14 // atomic_t is void*, so we can't accidentally dereference it
15 typedef void* atomic_t;
16
17 static inline void atomic_init(atomic_t* number, int32_t val);
18 static inline int32_t atomic_read(atomic_t* number);
19 static inline void atomic_set(atomic_t* number, int32_t val);
20 static inline void atomic_add(atomic_t* number, int32_t inc);
21 static inline void atomic_inc(atomic_t* number);
22 static inline void atomic_dec(atomic_t* number);
23 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val);
24 static inline uint32_t spin_trylock(spinlock_t*SAFE lock);
25 static inline uint32_t spin_locked(spinlock_t*SAFE lock);
26 static inline void spin_lock(spinlock_t*SAFE lock);
27 static inline void spin_unlock(spinlock_t*SAFE lock);
28
29 /* Inlined functions declared above */
30
31 static inline void atomic_init(atomic_t* number, int32_t val)
32 {
33         val <<= 8;
34         __asm__ __volatile__ ("st %0,[%1]" : : "r"(val), "r"(number) : "memory");
35 }
36
37 static inline int32_t atomic_read(atomic_t* number)
38 {
39         int32_t val;
40         __asm__ __volatile__ ("ld [%1],%0" : "=r"(val) : "r"(number));
41         return val >> 8;
42 }
43
44 static inline void atomic_add(atomic_t* number, int32_t inc)
45 {
46         // this is pretty clever.  the lower 8 bits (i.e byte 3)
47         // of the atomic_t serve as a spinlock.  let's acquire it.
48         { TRUSTEDBLOCK spin_lock((spinlock_t*)number); }
49
50         // compute new counter value.
51         inc += atomic_read(number);
52
53         // set the new counter value.  the lock is cleared (for free)
54         atomic_init(number,inc);
55 }
56
57 static inline void atomic_set(atomic_t* number, int32_t val)
58 {
59         // this works basically the same as atomic_add... but without the add
60         spin_lock((spinlock_t*)number);
61         atomic_init(number,val);
62 }
63
64 static inline void atomic_inc(atomic_t* number)
65 {
66         atomic_add(number,1);
67 }
68
69 static inline void atomic_dec(atomic_t* number)
70 {
71         atomic_add(number,-1);
72 }
73
74 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val)
75 {
76         __asm__ __volatile__ ("swap [%2],%0" : "=r"(val) : "0"(val),"r"(addr) : "memory");
77         return val;
78 }
79
80 static inline uint32_t spin_trylock(spinlock_t*SAFE lock)
81 {
82         uint32_t reg;
83         __asm__ __volatile__ ("ldstub [%1+3],%0" : "=r"(reg) : "r"(&lock->rlock) : "memory");
84         return reg;
85 }
86
87 static inline uint32_t spin_locked(spinlock_t*SAFE lock)
88 {
89         uint32_t reg;
90         __asm__ __volatile__ ("ldub [%1+3],%0" : "=r"(reg) : "r"(&lock->rlock));
91         return reg;
92 }
93
94 static inline void spin_lock(spinlock_t*SAFE lock)
95 {
96         while(spin_trylock(lock))
97                 while(spin_locked(lock));
98 }
99
100 static inline void spin_unlock(spinlock_t*SAFE lock)
101 {
102         wmb();
103         __asm__ __volatile__ ("stub %%g0,[%0+3]" : : "r"(&lock->rlock) : "memory");
104 }
105
106 static inline void spinlock_init(spinlock_t* lock)
107 {
108         lock->rlock = 0;
109 }
110
111 static inline void spinlock_debug(spinlock_t* lock)
112 {
113 }
114
115 #endif /* !ROS_INCLUDE_ATOMIC_H */