Call arbitrary functions from the monitor
[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 #include <arch/membar.h>
8
9 typedef void * RACY atomic_t;
10 struct spinlock {
11         volatile uint32_t RACY rlock;
12 #ifdef __CONFIG_SPINLOCK_DEBUG__
13         void *call_site;        
14         uint32_t calling_core;
15 #endif
16 };
17 typedef struct spinlock RACY spinlock_t;
18 #define SPINLOCK_INITIALIZER {0}
19
20 static inline void atomic_init(atomic_t *number, int32_t val);
21 static inline int32_t atomic_read(atomic_t *number);
22 static inline void atomic_set(atomic_t *number, int32_t val);
23 static inline void atomic_inc(atomic_t *number);
24 static inline void atomic_dec(atomic_t *number);
25 static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
26 static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
27 static inline uint32_t spin_locked(spinlock_t *SAFE lock);
28 static inline void __spin_lock(volatile uint32_t SRACY*CT(1) rlock);
29 static inline void spin_lock(spinlock_t *lock);
30 static inline void spin_unlock(spinlock_t *lock);
31 static inline void spinlock_init(spinlock_t *lock);
32 void spinlock_debug(spinlock_t *lock);
33
34 /* Inlined functions declared above */
35 static inline void atomic_init(atomic_t *number, int32_t val)
36 {
37         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
38 }
39
40 static inline int32_t atomic_read(atomic_t *number)
41 {
42         int32_t val;
43         asm volatile("movl %1,%0" : "=r"(val) : "m"(*number));
44         return val;
45 }
46
47 static inline void atomic_set(atomic_t *number, int32_t val)
48 {
49         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
50 }
51
52 // need to do this with pointers and deref.  %0 needs to be the memory address
53 static inline void atomic_inc(atomic_t *number)
54 {
55         asm volatile("lock incl %0" : "=m"(*number) : : "cc");
56 }
57
58 static inline void atomic_dec(atomic_t *number)
59 {
60         asm volatile("lock decl %0" : "=m"(*number) : : "cc");
61 }
62
63 static inline void atomic_andb(volatile uint8_t RACY*number, uint8_t mask)
64 {
65         asm volatile("lock andb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
66 }
67
68 static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
69 {
70         asm volatile("lock orb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
71 }
72
73 static inline uint32_t spin_locked(spinlock_t *SAFE lock)
74 {
75         // the lock status is the lowest byte of the lock
76         return lock->rlock & 0xff;
77 }
78
79 static inline void __spin_lock(volatile uint32_t *rlock)
80 {
81         asm volatile(
82                         "1:                       "
83                         "       cmpb $0, %0;          "
84                         "       je 2f;                "
85                         "       pause;                "
86                         "       jmp 1b;               "
87                         "2:                       " 
88                         "       movb $1, %%al;        "
89                         "       xchgb %%al, %0;       "
90                         "       cmpb $0, %%al;        "
91                         "       jne 1b;               "
92                 : : "m"(*rlock) : "eax", "cc");
93 }
94
95 static inline void spin_lock(spinlock_t *lock)
96 {
97         __spin_lock(&lock->rlock);
98 #ifdef __CONFIG_SPINLOCK_DEBUG__
99         lock->call_site = (void RACY*CT(1))TC(read_eip());
100         lock->calling_core = core_id();
101 #endif
102 }
103
104 static inline void spin_unlock(spinlock_t *lock)
105 {
106         lock->rlock = 0;
107 }
108
109 static inline void spinlock_init(spinlock_t *lock)
110 #ifdef __CONFIG_SPINLOCK_DEBUG__
111 WRITES(lock->rlock,lock->call_site,lock->calling_core)
112 #else
113 WRITES(lock->rlock)
114 #endif
115 {
116         lock->rlock = 0;
117 #ifdef __CONFIG_SPINLOCK_DEBUG__
118         lock->call_site = 0;
119         lock->calling_core = 0;
120 #endif
121 }
122
123 #endif /* !ROS_INCLUDE_ATOMIC_H */