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