Merged the timing and measurement stuff together and cleaned it up a bit
[akaros.git] / inc / x86.h
1 #ifndef ROS_INC_X86_H
2 #define ROS_INC_X86_H
3
4 #include <inc/types.h>
5 #include <inc/mmu.h>
6
7 #define CHECK_FLAG(flags,bit)   ((flags) & (1 << (bit)))
8
9 /* Model Specific Registers */
10 #define IA32_APIC_BASE                          0x1b
11 #define IA32_MTRR_DEF_TYPE                      0x2ff
12 #define IA32_MTRR_PHYSBASE0                     0x200
13 #define IA32_MTRR_PHYSMASK0                     0x201
14 #define IA32_MTRR_PHYSBASE1                     0x202
15 #define IA32_MTRR_PHYSMASK1                     0x203
16 #define IA32_MTRR_PHYSBASE2                     0x204
17 #define IA32_MTRR_PHYSMASK2                     0x205
18 #define IA32_MTRR_PHYSBASE3                     0x206
19 #define IA32_MTRR_PHYSMASK3                     0x207
20 #define IA32_MTRR_PHYSBASE4                     0x208
21 #define IA32_MTRR_PHYSMASK4                     0x209
22 #define IA32_MTRR_PHYSBASE5                     0x20a
23 #define IA32_MTRR_PHYSMASK5                     0x20b
24 #define IA32_MTRR_PHYSBASE6                     0x20c
25 #define IA32_MTRR_PHYSMASK6                     0x20d
26 #define IA32_MTRR_PHYSBASE7                     0x20e
27 #define IA32_MTRR_PHYSMASK7                     0x20f
28
29 #define MSR_APIC_ENABLE                         0x00000800
30 #define MSR_APIC_BASE_ADDRESS           0x0000000FFFFFF000
31
32 /* CPUID */
33 #define CPUID_PSE_SUPPORT                       0x00000008
34
35 /* Arch Constants */
36 #define MAX_NUM_CPUS                            255
37
38 static __inline void breakpoint(void) __attribute__((always_inline));
39 static __inline uint8_t inb(int port) __attribute__((always_inline));
40 static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
41 static __inline uint16_t inw(int port) __attribute__((always_inline));
42 static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline));
43 static __inline uint32_t inl(int port) __attribute__((always_inline));
44 static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline));
45 static __inline void outb(int port, uint8_t data) __attribute__((always_inline));
46 static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline));
47 static __inline void outw(int port, uint16_t data) __attribute__((always_inline));
48 static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline));
49 static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline));
50 static __inline void outl(int port, uint32_t data) __attribute__((always_inline));
51 static __inline void invlpg(void *addr) __attribute__((always_inline));
52 static __inline void lidt(void *p) __attribute__((always_inline));
53 static __inline void lldt(uint16_t sel) __attribute__((always_inline));
54 static __inline void ltr(uint16_t sel) __attribute__((always_inline));
55 static __inline void lcr0(uint32_t val) __attribute__((always_inline));
56 static __inline uint32_t rcr0(void) __attribute__((always_inline));
57 static __inline uint32_t rcr2(void) __attribute__((always_inline));
58 static __inline void lcr3(uint32_t val) __attribute__((always_inline));
59 static __inline uint32_t rcr3(void) __attribute__((always_inline));
60 static __inline void lcr4(uint32_t val) __attribute__((always_inline));
61 static __inline uint32_t rcr4(void) __attribute__((always_inline));
62 static __inline void tlbflush(void) __attribute__((always_inline));
63 static __inline uint32_t read_eflags(void) __attribute__((always_inline));
64 static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline));
65 static __inline uint32_t read_ebp(void) __attribute__((always_inline));
66 static __inline uint32_t read_esp(void) __attribute__((always_inline));
67 static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp);
68 static __inline uint64_t read_tsc(void) __attribute__((always_inline));
69 static __inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
70 static __inline uint64_t read_msr(uint32_t reg) __attribute__((always_inline));
71 static __inline void write_msr(uint32_t reg, uint64_t val) __attribute__((always_inline));
72 static __inline uint32_t read_mmreg32(uint32_t reg) __attribute__((always_inline));
73 static __inline void write_mmreg32(uint32_t reg, uint32_t val) __attribute__((always_inline));
74 static __inline void enable_irq(void) __attribute__((always_inline));
75 static __inline void disable_irq(void) __attribute__((always_inline));
76 static __inline void enable_irqsave(int8_t* state) __attribute__((always_inline));
77 static __inline void disable_irqsave(int8_t* state) __attribute__((always_inline));
78 static __inline void cpu_relax(void) __attribute__((always_inline));
79 static __inline void wbinvd(void) __attribute__((always_inline));
80 static __inline void clflush(uintptr_t* addr) __attribute__((always_inline));
81
82 static __inline void
83 breakpoint(void)
84 {
85         __asm __volatile("int3");
86 }
87
88 static __inline uint8_t
89 inb(int port)
90 {
91         uint8_t data;
92         __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
93         return data;
94 }
95
96 static __inline void
97 insb(int port, void *addr, int cnt)
98 {
99         __asm __volatile("cld\n\trepne\n\tinsb"                 :
100                          "=D" (addr), "=c" (cnt)                :
101                          "d" (port), "0" (addr), "1" (cnt)      :
102                          "memory", "cc");
103 }
104
105 static __inline uint16_t
106 inw(int port)
107 {
108         uint16_t data;
109         __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
110         return data;
111 }
112
113 static __inline void
114 insw(int port, void *addr, int cnt)
115 {
116         __asm __volatile("cld\n\trepne\n\tinsw"                 :
117                          "=D" (addr), "=c" (cnt)                :
118                          "d" (port), "0" (addr), "1" (cnt)      :
119                          "memory", "cc");
120 }
121
122 static __inline uint32_t
123 inl(int port)
124 {
125         uint32_t data;
126         __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
127         return data;
128 }
129
130 static __inline void
131 insl(int port, void *addr, int cnt)
132 {
133         __asm __volatile("cld\n\trepne\n\tinsl"                 :
134                          "=D" (addr), "=c" (cnt)                :
135                          "d" (port), "0" (addr), "1" (cnt)      :
136                          "memory", "cc");
137 }
138
139 static __inline void
140 outb(int port, uint8_t data)
141 {
142         __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
143 }
144
145 static __inline void
146 outsb(int port, const void *addr, int cnt)
147 {
148         __asm __volatile("cld\n\trepne\n\toutsb"                :
149                          "=S" (addr), "=c" (cnt)                :
150                          "d" (port), "0" (addr), "1" (cnt)      :
151                          "cc");
152 }
153
154 static __inline void
155 outw(int port, uint16_t data)
156 {
157         __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
158 }
159
160 static __inline void
161 outsw(int port, const void *addr, int cnt)
162 {
163         __asm __volatile("cld\n\trepne\n\toutsw"                :
164                          "=S" (addr), "=c" (cnt)                :
165                          "d" (port), "0" (addr), "1" (cnt)      :
166                          "cc");
167 }
168
169 static __inline void
170 outsl(int port, const void *addr, int cnt)
171 {
172         __asm __volatile("cld\n\trepne\n\toutsl"                :
173                          "=S" (addr), "=c" (cnt)                :
174                          "d" (port), "0" (addr), "1" (cnt)      :
175                          "cc");
176 }
177
178 static __inline void
179 outl(int port, uint32_t data)
180 {
181         __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
182 }
183
184 static __inline void 
185 invlpg(void *addr)
186
187         __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
188 }  
189
190 static __inline void
191 lidt(void *p)
192 {
193         __asm __volatile("lidt (%0)" : : "r" (p));
194 }
195
196 static __inline void
197 lldt(uint16_t sel)
198 {
199         __asm __volatile("lldt %0" : : "r" (sel));
200 }
201
202 static __inline void
203 ltr(uint16_t sel)
204 {
205         __asm __volatile("ltr %0" : : "r" (sel));
206 }
207
208 static __inline void
209 lcr0(uint32_t val)
210 {
211         __asm __volatile("movl %0,%%cr0" : : "r" (val));
212 }
213
214 static __inline uint32_t
215 rcr0(void)
216 {
217         uint32_t val;
218         __asm __volatile("movl %%cr0,%0" : "=r" (val));
219         return val;
220 }
221
222 static __inline uint32_t
223 rcr2(void)
224 {
225         uint32_t val;
226         __asm __volatile("movl %%cr2,%0" : "=r" (val));
227         return val;
228 }
229
230 static __inline void
231 lcr3(uint32_t val)
232 {
233         __asm __volatile("movl %0,%%cr3" : : "r" (val));
234 }
235
236 static __inline uint32_t
237 rcr3(void)
238 {
239         uint32_t val;
240         __asm __volatile("movl %%cr3,%0" : "=r" (val));
241         return val;
242 }
243
244 static __inline void
245 lcr4(uint32_t val)
246 {
247         __asm __volatile("movl %0,%%cr4" : : "r" (val));
248 }
249
250 static __inline uint32_t
251 rcr4(void)
252 {
253         uint32_t cr4;
254         __asm __volatile("movl %%cr4,%0" : "=r" (cr4));
255         return cr4;
256 }
257
258 static __inline void
259 tlbflush(void)
260 {
261         uint32_t cr3;
262         __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
263         __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
264 }
265
266 static __inline uint32_t
267 read_eflags(void)
268 {
269         uint32_t eflags;
270         __asm __volatile("pushfl; popl %0" : "=r" (eflags));
271         return eflags;
272 }
273
274 static __inline void
275 write_eflags(uint32_t eflags)
276 {
277         __asm __volatile("pushl %0; popfl" : : "r" (eflags));
278 }
279
280 static __inline uint32_t
281 read_ebp(void)
282 {
283         uint32_t ebp;
284         __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
285         return ebp;
286 }
287
288 static __inline uint32_t
289 read_esp(void)
290 {
291         uint32_t esp;
292         __asm __volatile("movl %%esp,%0" : "=r" (esp));
293         return esp;
294 }
295
296 static __inline void
297 cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
298 {
299         uint32_t eax, ebx, ecx, edx;
300         asm volatile("cpuid" 
301                 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
302                 : "a" (info));
303         if (eaxp)
304                 *eaxp = eax;
305         if (ebxp)
306                 *ebxp = ebx;
307         if (ecxp)
308                 *ecxp = ecx;
309         if (edxp)
310                 *edxp = edx;
311 }
312
313 static __inline uint64_t
314 read_tsc(void)
315 {
316         uint64_t tsc;
317         __asm __volatile("rdtsc" : "=A" (tsc));
318         return tsc;
319 }
320
321 static __inline uint64_t 
322 read_tsc_serialized(void)
323 {
324     uint64_t tsc;
325     __asm __volatile("cpuid; rdtsc" : "=A" (tsc));
326         return tsc;
327 }
328
329 // Might need to mfence rdmsr.  supposedly wrmsr serializes, but not for x2APIC
330 static __inline uint64_t
331 read_msr(uint32_t reg)
332 {
333         uint32_t edx, eax;
334         asm volatile("rdmsr; mfence" : "=d"(edx), "=a"(eax) : "c"(reg));
335         return (uint64_t)edx << 32 | eax;
336 }
337
338 static __inline void
339 write_msr(uint32_t reg, uint64_t val)
340 {
341         asm volatile("wrmsr" : : "d"((uint32_t)(val >> 32)),
342                                  "a"((uint32_t)(val & 0xFFFFFFFF)), 
343                                  "c"(reg));
344 }
345
346 static __inline void
347 write_mmreg32(uint32_t reg, uint32_t val)
348 {
349         {TRUSTEDBLOCK *((volatile uint32_t*)reg) = val; }
350         //the C ends up producing better asm than this:
351         //asm volatile("movl %0, (%1)" : : "r"(val), "r"(reg));
352 }
353
354 static __inline uint32_t
355 read_mmreg32(uint32_t reg)
356 {
357         {TRUSTEDBLOCK return *((volatile uint32_t*)reg); }
358 }
359
360 static __inline void
361 enable_irq(void)
362 {
363         asm volatile("sti");
364 }
365
366 static __inline void
367 disable_irq(void)
368 {
369         asm volatile("cli");
370 }
371
372 static __inline void
373 enable_irqsave(int8_t* state)
374 {
375         // *state tracks the number of nested enables and disables
376         // initial value of state: 0 = first run / no favorite
377         // > 0 means more enabled calls have been made
378         // < 0 means more disabled calls have been made
379         // Mostly doing this so we can call disable_irqsave first if we want
380
381         // one side or another "gets a point" if interrupts were already the
382         // way it wanted to go.  o/w, state stays at 0.  if the state was not 0
383         // then, enabling/disabling isn't even an option.  just increment/decrement
384
385         // if enabling is winning or tied, make sure it's enabled
386         if ((*state == 0) && (!(read_eflags() & FL_IF)))
387                 enable_irq();
388         else
389                 (*state)++;
390 }
391
392 static __inline void
393 disable_irqsave(int8_t* state)
394 {
395         if ((*state == 0) && (read_eflags() & FL_IF))
396                 disable_irq();
397         else 
398                 (*state)--;
399 }
400
401 static __inline void
402 cpu_relax(void)
403 {
404         // in case the compiler doesn't serialize for pause, the "m" will make sure
405         // no memory is reordered around this instruction.
406         asm volatile("pause" : : : "memory");
407 }
408
409 static __inline void
410 wbinvd(void) __attribute__((always_inline))
411 {
412         asm volatile("wbinvd");
413 }
414
415 static __inline void
416 clflush(uintptr_t* addr) __attribute__((always_inline))
417 {
418         asm volatile("clflush %0" : : "m"(*addr));
419 }
420 #endif /* !ROS_INC_X86_H */