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