Bit ops/bit masks
[akaros.git] / kern / arch / x86 / arch.h
1 #ifndef ROS_INC_ARCH_H
2 #define ROS_INC_ARCH_H
3
4 #include <ros/arch/arch.h>
5 #include <ros/common.h>
6 #include <arch/x86.h>
7 #include <arch/apic.h>
8
9 /* Arch Constants */
10 #define ARCH_CL_SIZE                             64
11
12 #define __always_inline __attribute__((always_inline))
13 static inline void breakpoint(void) __attribute__((always_inline));
14 static inline void invlpg(void *addr) __attribute__((always_inline));  
15 static inline void tlbflush(void) __attribute__((always_inline));
16 static inline void icache_flush_page(void *va, void *kva)
17               __attribute__((always_inline));
18 static inline uint64_t read_tsc(void) __attribute__((always_inline));
19 static inline uint64_t read_tscp(void) __attribute__((always_inline));
20 static inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
21 static inline void enable_irq(void) __attribute__((always_inline));
22 static inline void disable_irq(void) __attribute__((always_inline));
23 static inline void enable_irqsave(int8_t *state) __attribute__((always_inline));
24 static inline void disable_irqsave(int8_t *state)
25               __attribute__((always_inline));
26 static inline void cpu_relax(void) __attribute__((always_inline));
27 static inline void cpu_halt(void) __attribute__((always_inline));
28 static inline void clflush(uintptr_t* addr) __attribute__((always_inline));
29 static inline int irq_is_enabled(void) __attribute__((always_inline));
30 static inline int get_hw_coreid(uint32_t coreid) __attribute__((always_inline));
31 static inline int hw_core_id(void) __attribute__((always_inline));
32 static inline int get_os_coreid(int hw_coreid) __attribute__((always_inline));
33 static inline int core_id(void) __attribute__((always_inline));
34 static inline int node_id(void) __attribute__((always_inline));
35 static inline int core_id_early(void) __attribute__((always_inline));
36 static inline void cache_flush(void) __attribute__((always_inline));
37 static inline void reboot(void)
38               __attribute__((always_inline)) __attribute__((noreturn));
39
40 /* in trap.c */
41 void send_ipi(uint32_t os_coreid, uint8_t vector);
42 /* in cpuinfo.c */
43 void print_cpuinfo(void);
44 void show_mapping(uintptr_t start, size_t size);
45 int vendor_id(char *);
46
47 /* declared in smp.c */
48 extern int hw_coreid_lookup[MAX_NUM_CPUS];
49 extern int os_coreid_lookup[MAX_NUM_CPUS];
50
51 static inline void breakpoint(void)
52 {
53         asm volatile("int3");
54 }
55
56 static inline void invlpg(void *addr)
57
58         asm volatile("invlpg (%0)" : : "r" (addr) : "memory");
59 }  
60
61 static inline void tlbflush(void)
62 {
63         unsigned long cr3;
64         asm volatile("mov %%cr3,%0" : "=r" (cr3));
65         asm volatile("mov %0,%%cr3" : : "r" (cr3));
66 }
67
68 static inline void icache_flush_page(void *va, void *kva)
69 {
70         // x86 handles self-modifying code (mostly) without SW support
71 }
72
73 static inline uint64_t read_tsc(void)
74 {
75         uint32_t edx, eax;
76         asm volatile("rdtsc" : "=d"(edx), "=a"(eax));
77         return (uint64_t)edx << 32 | eax;
78 }
79
80 /* non-core-id reporting style (it is in ecx) */
81 static inline uint64_t read_tscp(void)
82 {
83         uint32_t edx, eax;
84         asm volatile("rdtscp" : "=d"(edx), "=a"(eax) : : X86_REG_CX);
85         return (uint64_t)edx << 32 | eax;
86 }
87
88 /* Check out k/a/x86/rdtsc_test.c for more info */
89 static inline uint64_t read_tsc_serialized(void)
90 {
91         asm volatile("lfence" ::: "memory");    /* mfence on amd? */
92         return read_tsc();
93 }
94
95 static inline void enable_irq(void)
96 {
97         asm volatile("sti");
98 }
99
100 static inline void disable_irq(void)
101 {
102         asm volatile("cli");
103 }
104
105 static inline void enable_irqsave(int8_t *state)
106 {
107         // *state tracks the number of nested enables and disables
108         // initial value of state: 0 = first run / no favorite
109         // > 0 means more enabled calls have been made
110         // < 0 means more disabled calls have been made
111         // Mostly doing this so we can call disable_irqsave first if we want
112
113         // one side or another "gets a point" if interrupts were already the
114         // way it wanted to go.  o/w, state stays at 0.  if the state was not 0
115         // then, enabling/disabling isn't even an option.  just increment/decrement
116
117         // if enabling is winning or tied, make sure it's enabled
118         if ((*state == 0) && !irq_is_enabled())
119                 enable_irq();
120         else
121                 (*state)++;
122 }
123
124 static inline void disable_irqsave(int8_t *state)
125 {
126         if ((*state == 0) && irq_is_enabled())
127                 disable_irq();
128         else 
129                 (*state)--;
130 }
131
132 static inline void cpu_relax(void)
133 {
134         __cpu_relax();
135 }
136
137 /* This doesn't atomically enable interrupts and then halt, like we want, so
138  * x86 needs to use a custom helper in the irq handler in trap.c. */
139 static inline void cpu_halt(void)
140 {
141         asm volatile("sti; hlt" : : : "memory");
142 }
143
144 static inline void clflush(uintptr_t* addr)
145 {
146         asm volatile("clflush %0" : : "m"(*addr));
147 }
148
149 static inline int irq_is_enabled(void)
150 {
151         return read_flags() & FL_IF;
152 }
153
154 /* os_coreid -> hw_coreid */
155 static inline int get_hw_coreid(uint32_t coreid)
156 {
157         return hw_coreid_lookup[coreid];
158 }
159
160 static inline int hw_core_id(void)
161 {
162         return lapic_get_id();
163 }
164
165 /* hw_coreid -> os_coreid */
166 static inline int get_os_coreid(int hw_coreid)
167 {
168         return os_coreid_lookup[hw_coreid];
169 }
170
171 static inline int node_id(void)
172 {
173         return 0;
174 }
175
176 #ifdef CONFIG_FAST_COREID
177 static inline int core_id(void)
178 {
179         int ret;
180         asm volatile ("rdtscp" : "=c"(ret) : : "eax", "edx");
181         return ret;
182 }
183 #else
184 /* core_id() returns the OS core number, not to be confused with the
185  * hardware-specific core identifier (such as the lapic id) returned by
186  * hw_core_id() */
187 static inline int core_id(void)
188 {
189         return get_os_coreid(hw_core_id());
190 }
191 #endif /* CONFIG_FAST_COREID */
192
193 static inline int core_id_early(void)
194 {
195         if (!core_id_ready)
196                 return 0;
197         return core_id();
198 }
199
200 static inline void cache_flush(void)
201 {
202         wbinvd();
203 }
204
205 static inline void reboot(void)
206 {
207         uint8_t cf9 = inb(0xcf9) & ~6;
208         outb(0x92, 0x3);
209         outb(0xcf9, cf9 | 2);
210         outb(0xcf9, cf9 | 6);
211         asm volatile ("mov $0, %"X86_REG_SP"; int $0");
212         while (1);
213 }
214
215 #endif /* !ROS_INC_ARCH_H */