Arch specific PC/IP and FP/BP helpers
[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 #define IA32_APIC_BASE                          0x1b
9 #define IA32_FEATURE_CONTROL            0x3a
10 #define IA32_MISC_ENABLE                        0x1a0
11
12 #define IA32_MTRR_DEF_TYPE                      0x2ff
13 #define IA32_MTRR_PHYSBASE0                     0x200
14 #define IA32_MTRR_PHYSMASK0                     0x201
15 #define IA32_MTRR_PHYSBASE1                     0x202
16 #define IA32_MTRR_PHYSMASK1                     0x203
17 #define IA32_MTRR_PHYSBASE2                     0x204
18 #define IA32_MTRR_PHYSMASK2                     0x205
19 #define IA32_MTRR_PHYSBASE3                     0x206
20 #define IA32_MTRR_PHYSMASK3                     0x207
21 #define IA32_MTRR_PHYSBASE4                     0x208
22 #define IA32_MTRR_PHYSMASK4                     0x209
23 #define IA32_MTRR_PHYSBASE5                     0x20a
24 #define IA32_MTRR_PHYSMASK5                     0x20b
25 #define IA32_MTRR_PHYSBASE6                     0x20c
26 #define IA32_MTRR_PHYSMASK6                     0x20d
27 #define IA32_MTRR_PHYSBASE7                     0x20e
28 #define IA32_MTRR_PHYSMASK7                     0x20f
29
30 #define MSR_APIC_ENABLE                         0x00000800
31 #define MSR_APIC_BASE_ADDRESS           0x0000000FFFFFF000
32
33 #define IA32_EFER_MSR                           0xc0000080
34 # define IA32_EFER_SYSCALL                      (1 << 0)
35 # define IA32_EFER_IA32E_EN                     (1 << 8)
36 # define IA32_EFER_IA32E_ACT            (1 << 10)
37 # define IA32_EFER_EXE_DIS_BIT          (1 << 11)
38
39 #define MSR_TSC_AUX                                     0xc0000103
40
41 #define MSR_FS_BASE                                     0xc0000100
42 #define MSR_GS_BASE                                     0xc0000101
43 #define MSR_KERN_GS_BASE                        0xc0000102
44
45 #define MSR_STAR                                        0xc0000081
46 #define MSR_LSTAR                                       0xc0000082
47 #define MSR_CSTAR                                       0xc0000083
48 #define MSR_SFMASK                                      0xc0000084
49
50 /* CPUID */
51 #define CPUID_PSE_SUPPORT                       0x00000008
52
53 /* Arch Constants */
54 #define MAX_NUM_CPUS                            255
55
56 #ifdef CONFIG_X86_64
57
58 #define X86_REG_BP                                      "rbp"
59 #define X86_REG_SP                                      "rsp"
60 #define X86_REG_IP                                      "rip"
61 #define X86_REG_AX                                      "rax"
62 #define X86_REG_BX                                      "rbx"
63 #define X86_REG_CX                                      "rcx"
64 #define X86_REG_DX                                      "rdx"
65
66 #else /* 32 bit */
67
68 #define X86_REG_BP                                      "ebp"
69 #define X86_REG_SP                                      "esp"
70 #define X86_REG_IP                                      "eip"
71 #define X86_REG_AX                                      "eax"
72 #define X86_REG_BX                                      "ebx"
73 #define X86_REG_CX                                      "ecx"
74 #define X86_REG_DX                                      "edx"
75
76 #endif /* 64bit / 32bit */
77
78 #ifndef __ASSEMBLER__
79 static inline uint8_t inb(int port) __attribute__((always_inline));
80 static inline void insb(int port, void *addr, int cnt)
81               __attribute__((always_inline));
82 static inline uint16_t inw(int port) __attribute__((always_inline));
83 static inline void insw(int port, void *addr, int cnt)
84               __attribute__((always_inline));
85 static inline uint32_t inl(int port) __attribute__((always_inline));
86 static inline void insl(int port, void *addr, int cnt)
87               __attribute__((always_inline));
88 static inline void outb(int port, uint8_t data) __attribute__((always_inline));
89 static inline void outsb(int port, const void *addr, int cnt)
90               __attribute__((always_inline));
91 static inline void outw(int port, uint16_t data) __attribute__((always_inline));
92 static inline void outsw(int port, const void *addr, int cnt)
93               __attribute__((always_inline));
94 static inline void outsl(int port, const void *addr, int cnt)
95               __attribute__((always_inline));
96 static inline void outl(int port, uint32_t data) __attribute__((always_inline));
97 static inline void lidt(void *p) __attribute__((always_inline));
98 static inline void lldt(uint16_t sel) __attribute__((always_inline));
99 static inline void ltr(uint16_t sel) __attribute__((always_inline));
100 static inline void lcr0(unsigned long val) __attribute__((always_inline));
101 static inline unsigned long rcr0(void) __attribute__((always_inline));
102 static inline unsigned long rcr2(void) __attribute__((always_inline));
103 static inline void lcr3(unsigned long val) __attribute__((always_inline));
104 static inline unsigned long rcr3(void) __attribute__((always_inline));
105 static inline void lcr4(unsigned long val) __attribute__((always_inline));
106 static inline unsigned long rcr4(void) __attribute__((always_inline));
107 static inline unsigned long read_flags(void) __attribute__((always_inline));
108 static inline void write_eflags(unsigned long eflags)
109               __attribute__((always_inline));
110 static inline unsigned long read_bp(void) __attribute__((always_inline));
111 static inline unsigned long read_pc(void) __attribute__((always_inline));
112 static inline unsigned long read_sp(void) __attribute__((always_inline));
113 static inline void cpuid(uint32_t info1, uint32_t info2, uint32_t *eaxp,
114                          uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
115                                                                __attribute__((always_inline));
116 static inline uint64_t read_msr(uint32_t reg) __attribute__((always_inline));
117 static inline void write_msr(uint32_t reg, uint64_t val)
118               __attribute__((always_inline));
119 static inline void write_mmreg32(uintptr_t reg, uint32_t val)
120               __attribute__((always_inline));
121 static inline uint32_t read_mmreg32(uintptr_t reg)
122               __attribute__((always_inline));
123 static inline void wbinvd(void) __attribute__((always_inline));
124 static inline void __cpu_relax(void) __attribute__((always_inline));
125
126 static inline uint8_t inb(int port)
127 {
128         uint8_t data;
129         asm volatile("inb %w1,%0" : "=a" (data) : "d" (port));
130         return data;
131 }
132
133 static inline void insb(int port, void *addr, int cnt)
134 {
135         asm volatile("cld\n\trepne\n\tinsb"
136                      : "=D" (addr), "=c" (cnt)
137                      : "d" (port), "0" (addr), "1" (cnt)
138                      : "memory", "cc");
139 }
140
141 static inline uint16_t inw(int port)
142 {
143         uint16_t data;
144         asm volatile("inw %w1,%0" : "=a" (data) : "d" (port));
145         return data;
146 }
147
148 static inline void insw(int port, void *addr, int cnt)
149 {
150         asm volatile("cld\n\trepne\n\tinsw"
151                      : "=D" (addr), "=c" (cnt)
152                      : "d" (port), "0" (addr), "1" (cnt)
153                      : "memory", "cc");
154 }
155
156 static inline uint32_t inl(int port)
157 {
158         uint32_t data;
159         asm volatile("inl %w1,%0" : "=a" (data) : "d" (port));
160         return data;
161 }
162
163 static inline void insl(int port, void *addr, int cnt)
164 {
165         asm volatile("cld\n\trepne\n\tinsl"
166                      : "=D" (addr), "=c" (cnt)
167                      : "d" (port), "0" (addr), "1" (cnt)
168                      : "memory", "cc");
169 }
170
171 static inline void outb(int port, uint8_t data)
172 {
173         asm volatile("outb %0,%w1" : : "a" (data), "d" (port));
174 }
175
176 static inline void outsb(int port, const void *addr, int cnt)
177 {
178         asm volatile("cld\n\trepne\n\toutsb"
179                      : "=S" (addr), "=c" (cnt)
180                      : "d" (port), "0" (addr), "1" (cnt)
181                      : "cc");
182 }
183
184 static inline void outw(int port, uint16_t data)
185 {
186         asm volatile("outw %0,%w1" : : "a" (data), "d" (port));
187 }
188
189 static inline void outsw(int port, const void *addr, int cnt)
190 {
191         asm volatile("cld\n\trepne\n\toutsw"
192                      : "=S" (addr), "=c" (cnt)
193                      : "d" (port), "0" (addr), "1" (cnt)
194                      : "cc");
195 }
196
197 static inline void outsl(int port, const void *addr, int cnt)
198 {
199         asm volatile("cld\n\trepne\n\toutsl"
200                      : "=S" (addr), "=c" (cnt)
201                      : "d" (port), "0" (addr), "1" (cnt)
202                      : "cc");
203 }
204
205 static inline void outl(int port, uint32_t data)
206 {
207         asm volatile("outl %0,%w1" : : "a" (data), "d" (port));
208 }
209
210 static inline void lidt(void *p)
211 {
212         asm volatile("lidt (%0)" : : "r" (p));
213 }
214
215 static inline void lldt(uint16_t sel)
216 {
217         asm volatile("lldt %0" : : "r" (sel));
218 }
219
220 static inline void ltr(uint16_t sel)
221 {
222         asm volatile("ltr %0" : : "r" (sel));
223 }
224
225 static inline void lcr0(unsigned long val)
226 {
227         asm volatile("mov %0,%%cr0" : : "r" (val));
228 }
229
230 static inline unsigned long rcr0(void)
231 {
232         unsigned long val;
233         asm volatile("mov %%cr0,%0" : "=r" (val));
234         return val;
235 }
236
237 static inline unsigned long rcr2(void)
238 {
239         unsigned long val;
240         asm volatile("mov %%cr2,%0" : "=r" (val));
241         return val;
242 }
243
244 static inline void lcr3(unsigned long val)
245 {
246         asm volatile("mov %0,%%cr3" : : "r" (val));
247 }
248
249 static inline unsigned long rcr3(void)
250 {
251         unsigned long val;
252         asm volatile("mov %%cr3,%0" : "=r" (val));
253         return val;
254 }
255
256 static inline void lcr4(unsigned long val)
257 {
258         asm volatile("mov %0,%%cr4" : : "r" (val));
259 }
260
261 static inline unsigned long rcr4(void)
262 {
263         unsigned long cr4;
264         asm volatile("mov %%cr4,%0" : "=r" (cr4));
265         return cr4;
266 }
267
268 static inline unsigned long read_flags(void)
269 {
270         unsigned long eflags;
271         asm volatile("pushf; pop %0" : "=r" (eflags));
272         return eflags;
273 }
274
275 static inline void write_eflags(unsigned long eflags)
276 {
277         asm volatile("push %0; popf" : : "r" (eflags));
278 }
279
280 static inline unsigned long read_bp(void)
281 {
282         unsigned long bp;
283         asm volatile("mov %%"X86_REG_BP",%0" : "=r" (bp));
284         return bp;
285 }
286
287 static inline unsigned long read_pc(void)
288 {
289         unsigned long ip;
290         asm volatile("call 1f; 1: pop %0" : "=r"(ip));
291         return ip;
292 }
293
294 static inline unsigned long read_sp(void)
295 {
296         unsigned long sp;
297         asm volatile("mov %%"X86_REG_SP",%0" : "=r" (sp));
298         return sp;
299 }
300
301 static inline void cpuid(uint32_t info1, uint32_t info2, uint32_t *eaxp,
302                          uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
303 {
304         uint32_t eax, ebx, ecx, edx;
305         /* Can select with both eax (info1) and ecx (info2) */
306         asm volatile("cpuid" 
307                 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
308                 : "a" (info1), "c" (info2));
309         if (eaxp)
310                 *eaxp = eax;
311         if (ebxp)
312                 *ebxp = ebx;
313         if (ecxp)
314                 *ecxp = ecx;
315         if (edxp)
316                 *edxp = edx;
317 }
318
319 // Might need to mfence rdmsr.  supposedly wrmsr serializes, but not for x2APIC
320 static inline uint64_t 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 write_msr(uint32_t reg, uint64_t val)
328 {
329         asm volatile("wrmsr" : : "d"((uint32_t)(val >> 32)),
330                                  "a"((uint32_t)(val & 0xFFFFFFFF)), 
331                                  "c"(reg));
332 }
333
334 static inline void write_mmreg32(uintptr_t reg, uint32_t val)
335 {
336         *((volatile uint32_t*)reg) = val;
337 }
338
339 static inline uint32_t read_mmreg32(uintptr_t reg)
340 {
341         return *((volatile uint32_t*)reg);
342 }
343
344 static inline void wbinvd(void)
345 {
346         asm volatile("wbinvd");
347 }
348
349 /* this version of cpu_relax is needed to resolve some circular dependencies
350  * with arch/arch.h and arch/apic.h */
351 static inline void __cpu_relax(void)
352 {
353         // in case the compiler doesn't serialize for pause, the "m" will make sure
354         // no memory is reordered around this instruction.
355         asm volatile("pause" : : : "memory");
356 }
357
358 #ifndef UNUSED_ARG
359 #define UNUSED_ARG(x) (void)x
360 #endif /* This prevents compiler warnings for UNUSED_ARG */ 
361 #endif /* !__ASSEMBLER__ */
362
363 #endif /* !ROS_INC_X86_H */