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