MSI cleanup and IRQ routing
[akaros.git] / kern / arch / x86 / x86.h
1 #ifndef ROS_INC_X86_H
2 #define ROS_INC_X86_H
3
4 #include <ros/common.h>
5 #include <arch/mmu.h>
6
7 /* Model Specific Registers */
8 // TODO: figure out which are intel specific, and name them accordingly
9 #define IA32_APIC_BASE                          0x1b
10 /* These two are intel-only */
11 #define IA32_FEATURE_CONTROL            0x3a
12 #define IA32_MISC_ENABLE                        0x1a0
13
14 #define IA32_MTRR_DEF_TYPE                      0x2ff
15 #define IA32_MTRR_PHYSBASE0                     0x200
16 #define IA32_MTRR_PHYSMASK0                     0x201
17 #define IA32_MTRR_PHYSBASE1                     0x202
18 #define IA32_MTRR_PHYSMASK1                     0x203
19 #define IA32_MTRR_PHYSBASE2                     0x204
20 #define IA32_MTRR_PHYSMASK2                     0x205
21 #define IA32_MTRR_PHYSBASE3                     0x206
22 #define IA32_MTRR_PHYSMASK3                     0x207
23 #define IA32_MTRR_PHYSBASE4                     0x208
24 #define IA32_MTRR_PHYSMASK4                     0x209
25 #define IA32_MTRR_PHYSBASE5                     0x20a
26 #define IA32_MTRR_PHYSMASK5                     0x20b
27 #define IA32_MTRR_PHYSBASE6                     0x20c
28 #define IA32_MTRR_PHYSMASK6                     0x20d
29 #define IA32_MTRR_PHYSBASE7                     0x20e
30 #define IA32_MTRR_PHYSMASK7                     0x20f
31
32 #define MSR_APIC_ENABLE                         0x00000800
33 #define MSR_APIC_BASE_ADDRESS           0x0000000FFFFFF000
34
35 #define IA32_EFER_MSR                           0xc0000080
36 # define IA32_EFER_SYSCALL                      (1 << 0)
37 # define IA32_EFER_IA32E_EN                     (1 << 8)
38 # define IA32_EFER_IA32E_ACT            (1 << 10)
39 # define IA32_EFER_EXE_DIS_BIT          (1 << 11)
40
41 #define MSR_TSC_AUX                                     0xc0000103
42
43 #define MSR_FS_BASE                                     0xc0000100
44 #define MSR_GS_BASE                                     0xc0000101
45 #define MSR_KERN_GS_BASE                        0xc0000102
46
47 #define MSR_STAR                                        0xc0000081
48 #define MSR_LSTAR                                       0xc0000082
49 #define MSR_CSTAR                                       0xc0000083
50 #define MSR_SFMASK                                      0xc0000084
51
52 /* CPUID */
53 #define CPUID_PSE_SUPPORT                       0x00000008
54
55 /* Arch Constants */
56 #define MAX_NUM_CPUS                            255
57
58 #ifdef CONFIG_X86_64
59
60 #define X86_REG_BP                                      "rbp"
61 #define X86_REG_SP                                      "rsp"
62 #define X86_REG_IP                                      "rip"
63 #define X86_REG_AX                                      "rax"
64 #define X86_REG_BX                                      "rbx"
65 #define X86_REG_CX                                      "rcx"
66 #define X86_REG_DX                                      "rdx"
67
68 #else /* 32 bit */
69
70 #define X86_REG_BP                                      "ebp"
71 #define X86_REG_SP                                      "esp"
72 #define X86_REG_IP                                      "eip"
73 #define X86_REG_AX                                      "eax"
74 #define X86_REG_BX                                      "ebx"
75 #define X86_REG_CX                                      "ecx"
76 #define X86_REG_DX                                      "edx"
77
78 #endif /* 64bit / 32bit */
79
80 /* Various flags defined: can be included from assembler. */
81
82 /*
83  * EFLAGS bits
84  */
85 #define X86_EFLAGS_CF   0x00000001 /* Carry Flag */
86 #define X86_EFLAGS_BIT1 0x00000002 /* Bit 1 - always on */
87 #define X86_EFLAGS_PF   0x00000004 /* Parity Flag */
88 #define X86_EFLAGS_AF   0x00000010 /* Auxiliary carry Flag */
89 #define X86_EFLAGS_ZF   0x00000040 /* Zero Flag */
90 #define X86_EFLAGS_SF   0x00000080 /* Sign Flag */
91 #define X86_EFLAGS_TF   0x00000100 /* Trap Flag */
92 #define X86_EFLAGS_IF   0x00000200 /* Interrupt Flag */
93 #define X86_EFLAGS_DF   0x00000400 /* Direction Flag */
94 #define X86_EFLAGS_OF   0x00000800 /* Overflow Flag */
95 #define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
96 #define X86_EFLAGS_NT   0x00004000 /* Nested Task */
97 #define X86_EFLAGS_RF   0x00010000 /* Resume Flag */
98 #define X86_EFLAGS_VM   0x00020000 /* Virtual Mode */
99 #define X86_EFLAGS_AC   0x00040000 /* Alignment Check */
100 #define X86_EFLAGS_VIF  0x00080000 /* Virtual Interrupt Flag */
101 #define X86_EFLAGS_VIP  0x00100000 /* Virtual Interrupt Pending */
102 #define X86_EFLAGS_ID   0x00200000 /* CPUID detection flag */
103
104 /*
105  * Basic CPU control in CR0
106  */
107 #define X86_CR0_PE      0x00000001 /* Protection Enable */
108 #define X86_CR0_MP      0x00000002 /* Monitor Coprocessor */
109 #define X86_CR0_EM      0x00000004 /* Emulation */
110 #define X86_CR0_TS      0x00000008 /* Task Switched */
111 #define X86_CR0_ET      0x00000010 /* Extension Type */
112 #define X86_CR0_NE      0x00000020 /* Numeric Error */
113 #define X86_CR0_WP      0x00010000 /* Write Protect */
114 #define X86_CR0_AM      0x00040000 /* Alignment Mask */
115 #define X86_CR0_NW      0x20000000 /* Not Write-through */
116 #define X86_CR0_CD      0x40000000 /* Cache Disable */
117 #define X86_CR0_PG      0x80000000 /* Paging */
118
119 /*
120  * Paging options in CR3
121  */
122 #define X86_CR3_PWT     0x00000008 /* Page Write Through */
123 #define X86_CR3_PCD     0x00000010 /* Page Cache Disable */
124 #define X86_CR3_PCID_MASK 0x00000fff /* PCID Mask */
125
126 /*
127  * Intel CPU features in CR4
128  */
129 #define X86_CR4_VME     0x00000001 /* enable vm86 extensions */
130 #define X86_CR4_PVI     0x00000002 /* virtual interrupts flag enable */
131 #define X86_CR4_TSD     0x00000004 /* disable time stamp at ipl 3 */
132 #define X86_CR4_DE      0x00000008 /* enable debugging extensions */
133 #define X86_CR4_PSE     0x00000010 /* enable page size extensions */
134 #define X86_CR4_PAE     0x00000020 /* enable physical address extensions */
135 #define X86_CR4_MCE     0x00000040 /* Machine check enable */
136 #define X86_CR4_PGE     0x00000080 /* enable global pages */
137 #define X86_CR4_PCE     0x00000100 /* enable performance counters at ipl 3 */
138 #define X86_CR4_OSFXSR  0x00000200 /* enable fast FPU save and restore */
139 #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */
140 #define X86_CR4_VMXE    0x00002000 /* enable VMX virtualization */
141 #define X86_CR4_RDWRGSFS 0x00010000 /* enable RDWRGSFS support */
142 #define X86_CR4_PCIDE   0x00020000 /* enable PCID support */
143 #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
144 #define X86_CR4_SMEP    0x00100000 /* enable SMEP support */
145 #define X86_CR4_SMAP    0x00200000 /* enable SMAP support */
146
147 /*
148  * x86-64 Task Priority Register, CR8
149  */
150 #define X86_CR8_TPR     0x0000000F /* task priority register */
151
152 #ifndef __ASSEMBLER__
153 static inline uint8_t inb(int port) __attribute__((always_inline));
154 static inline void insb(int port, void *addr, int cnt)
155               __attribute__((always_inline));
156 static inline uint16_t inw(int port) __attribute__((always_inline));
157 static inline void insw(int port, void *addr, int cnt)
158               __attribute__((always_inline));
159 static inline uint32_t inl(int port) __attribute__((always_inline));
160 static inline void insl(int port, void *addr, int cnt)
161               __attribute__((always_inline));
162 static inline void outb(int port, uint8_t data) __attribute__((always_inline));
163 static inline void outsb(int port, const void *addr, int cnt)
164               __attribute__((always_inline));
165 static inline void outw(int port, uint16_t data) __attribute__((always_inline));
166 static inline void outsw(int port, const void *addr, int cnt)
167               __attribute__((always_inline));
168 static inline void outsl(int port, const void *addr, int cnt)
169               __attribute__((always_inline));
170 static inline void outl(int port, uint32_t data) __attribute__((always_inline));
171 static inline void lidt(void *p) __attribute__((always_inline));
172 static inline void lldt(uint16_t sel) __attribute__((always_inline));
173 static inline void ltr(uint16_t sel) __attribute__((always_inline));
174 static inline void lcr0(unsigned long val) __attribute__((always_inline));
175 static inline unsigned long rcr0(void) __attribute__((always_inline));
176 static inline unsigned long rcr2(void) __attribute__((always_inline));
177 static inline void lcr3(unsigned long val) __attribute__((always_inline));
178 static inline unsigned long rcr3(void) __attribute__((always_inline));
179 static inline void lcr4(unsigned long val) __attribute__((always_inline));
180 static inline unsigned long rcr4(void) __attribute__((always_inline));
181 static inline unsigned long read_flags(void) __attribute__((always_inline));
182 static inline void write_eflags(unsigned long eflags)
183               __attribute__((always_inline));
184 static inline unsigned long read_bp(void) __attribute__((always_inline));
185 static inline unsigned long read_pc(void) __attribute__((always_inline));
186 static inline unsigned long read_sp(void) __attribute__((always_inline));
187 static inline void cpuid(uint32_t info1, uint32_t info2, uint32_t *eaxp,
188                          uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
189                                                                __attribute__((always_inline));
190 static inline uint32_t cpuid_ecx(int op) __attribute__((always_inline));
191 static inline uint64_t read_msr(uint32_t reg) __attribute__((always_inline));
192 static inline void write_msr(uint32_t reg, uint64_t val)
193               __attribute__((always_inline));
194 static inline void write_mmreg32(uintptr_t reg, uint32_t val)
195               __attribute__((always_inline));
196 static inline uint32_t read_mmreg32(uintptr_t reg)
197               __attribute__((always_inline));
198 static inline void wbinvd(void) __attribute__((always_inline));
199 static inline void __cpu_relax(void) __attribute__((always_inline));
200
201 static inline uint8_t inb(int port)
202 {
203         uint8_t data;
204         asm volatile("inb %w1,%0" : "=a" (data) : "d" (port));
205         return data;
206 }
207
208 static inline void insb(int port, void *addr, int cnt)
209 {
210         asm volatile("cld\n\trepne\n\tinsb"
211                      : "=D" (addr), "=c" (cnt)
212                      : "d" (port), "0" (addr), "1" (cnt)
213                      : "memory", "cc");
214 }
215
216 static inline uint16_t inw(int port)
217 {
218         uint16_t data;
219         asm volatile("inw %w1,%0" : "=a" (data) : "d" (port));
220         return data;
221 }
222
223 static inline void insw(int port, void *addr, int cnt)
224 {
225         asm volatile("cld\n\trepne\n\tinsw"
226                      : "=D" (addr), "=c" (cnt)
227                      : "d" (port), "0" (addr), "1" (cnt)
228                      : "memory", "cc");
229 }
230
231 static inline uint32_t inl(int port)
232 {
233         uint32_t data;
234         asm volatile("inl %w1,%0" : "=a" (data) : "d" (port));
235         return data;
236 }
237
238 static inline void insl(int port, void *addr, int cnt)
239 {
240         asm volatile("cld\n\trepne\n\tinsl"
241                      : "=D" (addr), "=c" (cnt)
242                      : "d" (port), "0" (addr), "1" (cnt)
243                      : "memory", "cc");
244 }
245
246 static inline void outb(int port, uint8_t data)
247 {
248         asm volatile("outb %0,%w1" : : "a" (data), "d" (port));
249 }
250
251 static inline void outsb(int port, const void *addr, int cnt)
252 {
253         asm volatile("cld\n\trepne\n\toutsb"
254                      : "=S" (addr), "=c" (cnt)
255                      : "d" (port), "0" (addr), "1" (cnt)
256                      : "cc");
257 }
258
259 static inline void outw(int port, uint16_t data)
260 {
261         asm volatile("outw %0,%w1" : : "a" (data), "d" (port));
262 }
263
264 static inline void outsw(int port, const void *addr, int cnt)
265 {
266         asm volatile("cld\n\trepne\n\toutsw"
267                      : "=S" (addr), "=c" (cnt)
268                      : "d" (port), "0" (addr), "1" (cnt)
269                      : "cc");
270 }
271
272 static inline void outsl(int port, const void *addr, int cnt)
273 {
274         asm volatile("cld\n\trepne\n\toutsl"
275                      : "=S" (addr), "=c" (cnt)
276                      : "d" (port), "0" (addr), "1" (cnt)
277                      : "cc");
278 }
279
280 static inline void outl(int port, uint32_t data)
281 {
282         asm volatile("outl %0,%w1" : : "a" (data), "d" (port));
283 }
284
285 static inline void lidt(void *p)
286 {
287         asm volatile("lidt (%0)" : : "r" (p));
288 }
289
290 static inline void lldt(uint16_t sel)
291 {
292         asm volatile("lldt %0" : : "r" (sel));
293 }
294
295 static inline void ltr(uint16_t sel)
296 {
297         asm volatile("ltr %0" : : "r" (sel));
298 }
299
300 static inline void lcr0(unsigned long val)
301 {
302         asm volatile("mov %0,%%cr0" : : "r" (val));
303 }
304
305 static inline unsigned long rcr0(void)
306 {
307         unsigned long val;
308         asm volatile("mov %%cr0,%0" : "=r" (val));
309         return val;
310 }
311
312 static inline unsigned long rcr2(void)
313 {
314         unsigned long val;
315         asm volatile("mov %%cr2,%0" : "=r" (val));
316         return val;
317 }
318
319 static inline void lcr3(unsigned long val)
320 {
321         asm volatile("mov %0,%%cr3" : : "r" (val));
322 }
323
324 static inline unsigned long rcr3(void)
325 {
326         unsigned long val;
327         asm volatile("mov %%cr3,%0" : "=r" (val));
328         return val;
329 }
330
331 static inline void lcr4(unsigned long val)
332 {
333         asm volatile("mov %0,%%cr4" : : "r" (val));
334 }
335
336 static inline unsigned long rcr4(void)
337 {
338         unsigned long cr4;
339         asm volatile("mov %%cr4,%0" : "=r" (cr4));
340         return cr4;
341 }
342
343 static inline unsigned long read_flags(void)
344 {
345         unsigned long eflags;
346         asm volatile("pushf; pop %0" : "=r" (eflags));
347         return eflags;
348 }
349
350 static inline void write_eflags(unsigned long eflags)
351 {
352         asm volatile("push %0; popf" : : "r" (eflags));
353 }
354
355 static inline unsigned long read_bp(void)
356 {
357         unsigned long bp;
358         asm volatile("mov %%"X86_REG_BP",%0" : "=r" (bp));
359         return bp;
360 }
361
362 static inline unsigned long read_pc(void)
363 {
364         unsigned long ip;
365         asm volatile("call 1f; 1: pop %0" : "=r"(ip));
366         return ip;
367 }
368
369 static inline unsigned long read_sp(void)
370 {
371         unsigned long sp;
372         asm volatile("mov %%"X86_REG_SP",%0" : "=r" (sp));
373         return sp;
374 }
375
376 static inline void cpuid(uint32_t info1, uint32_t info2, uint32_t *eaxp,
377                          uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
378 {
379         uint32_t eax, ebx, ecx, edx;
380         /* Can select with both eax (info1) and ecx (info2) */
381         asm volatile("cpuid" 
382                 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
383                 : "a" (info1), "c" (info2));
384         if (eaxp)
385                 *eaxp = eax;
386         if (ebxp)
387                 *ebxp = ebx;
388         if (ecxp)
389                 *ecxp = ecx;
390         if (edxp)
391                 *edxp = edx;
392 }
393
394 static inline uint32_t cpuid_ecx(int opcode)
395 {
396         uint32_t ecx;
397         cpuid(1, 0, NULL, NULL, &ecx, NULL);
398         return ecx;
399 }
400
401 // Might need to mfence rdmsr.  supposedly wrmsr serializes, but not for x2APIC
402 static inline uint64_t read_msr(uint32_t reg)
403 {
404         uint32_t edx, eax;
405         asm volatile("rdmsr; mfence" : "=d"(edx), "=a"(eax) : "c"(reg));
406         return (uint64_t)edx << 32 | eax;
407 }
408
409 static inline void write_msr(uint32_t reg, uint64_t val)
410 {
411         asm volatile("wrmsr" : : "d"((uint32_t)(val >> 32)),
412                                  "a"((uint32_t)(val & 0xFFFFFFFF)), 
413                                  "c"(reg));
414 }
415
416 static inline void write_mmreg32(uintptr_t reg, uint32_t val)
417 {
418         *((volatile uint32_t*)reg) = val;
419 }
420
421 static inline uint32_t read_mmreg32(uintptr_t reg)
422 {
423         return *((volatile uint32_t*)reg);
424 }
425
426 static inline void wbinvd(void)
427 {
428         asm volatile("wbinvd");
429 }
430
431 /* this version of cpu_relax is needed to resolve some circular dependencies
432  * with arch/arch.h and arch/apic.h */
433 static inline void __cpu_relax(void)
434 {
435         // in case the compiler doesn't serialize for pause, the "m" will make sure
436         // no memory is reordered around this instruction.
437         asm volatile("pause" : : : "memory");
438 }
439
440 #ifndef UNUSED_ARG
441 #define UNUSED_ARG(x) (void)x
442 #endif /* This prevents compiler warnings for UNUSED_ARG */ 
443 #endif /* !__ASSEMBLER__ */
444
445 #endif /* !ROS_INC_X86_H */