Avoids nehalem keyboard issues, better monitors
[akaros.git] / kern / arch / i686 / 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_MTRR_DEF_TYPE                      0x2ff
11 #define IA32_MTRR_PHYSBASE0                     0x200
12 #define IA32_MTRR_PHYSMASK0                     0x201
13 #define IA32_MTRR_PHYSBASE1                     0x202
14 #define IA32_MTRR_PHYSMASK1                     0x203
15 #define IA32_MTRR_PHYSBASE2                     0x204
16 #define IA32_MTRR_PHYSMASK2                     0x205
17 #define IA32_MTRR_PHYSBASE3                     0x206
18 #define IA32_MTRR_PHYSMASK3                     0x207
19 #define IA32_MTRR_PHYSBASE4                     0x208
20 #define IA32_MTRR_PHYSMASK4                     0x209
21 #define IA32_MTRR_PHYSBASE5                     0x20a
22 #define IA32_MTRR_PHYSMASK5                     0x20b
23 #define IA32_MTRR_PHYSBASE6                     0x20c
24 #define IA32_MTRR_PHYSMASK6                     0x20d
25 #define IA32_MTRR_PHYSBASE7                     0x20e
26 #define IA32_MTRR_PHYSMASK7                     0x20f
27
28 #define MSR_APIC_ENABLE                         0x00000800
29 #define MSR_APIC_BASE_ADDRESS           0x0000000FFFFFF000
30
31 /* CPUID */
32 #define CPUID_PSE_SUPPORT                       0x00000008
33
34 /* Arch Constants */
35 #define MAX_NUM_CPUS                            255
36
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 lidt(void *p) __attribute__((always_inline));
50 static __inline void lldt(uint16_t sel) __attribute__((always_inline));
51 static __inline void ltr(uint16_t sel) __attribute__((always_inline));
52 static __inline void lcr0(uint32_t val) __attribute__((always_inline));
53 static __inline uint32_t rcr0(void) __attribute__((always_inline));
54 static __inline uint32_t rcr2(void) __attribute__((always_inline));
55 static __inline void lcr3(uint32_t val) __attribute__((always_inline));
56 static __inline uint32_t rcr3(void) __attribute__((always_inline));
57 static __inline void lcr4(uint32_t val) __attribute__((always_inline));
58 static __inline uint32_t rcr4(void) __attribute__((always_inline));
59 static __inline uint32_t read_eflags(void) __attribute__((always_inline));
60 static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline));
61 static __inline uint32_t read_ebp(void) __attribute__((always_inline));
62 static __inline uint32_t read_eip(void) __attribute__((always_inline));
63 static __inline uint32_t read_esp(void) __attribute__((always_inline));
64 static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp);
65 static __inline uint64_t read_msr(uint32_t reg) __attribute__((always_inline));
66 static __inline void write_msr(uint32_t reg, uint64_t val) __attribute__((always_inline));
67 static __inline uint32_t read_mmreg32(uint32_t reg) __attribute__((always_inline));
68 static __inline void write_mmreg32(uint32_t reg, uint32_t val) __attribute__((always_inline));
69 static __inline void wbinvd(void) __attribute__((always_inline));
70 static __inline void __cpu_relax(void) __attribute__((always_inline));
71
72 static __inline uint8_t
73 inb(int port)
74 {
75         uint8_t data;
76         __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
77         return data;
78 }
79
80 static __inline void
81 insb(int port, void *addr, int cnt)
82 {
83         __asm __volatile("cld\n\trepne\n\tinsb"                 :
84                          "=D" (addr), "=c" (cnt)                :
85                          "d" (port), "0" (addr), "1" (cnt)      :
86                          "memory", "cc");
87 }
88
89 static __inline uint16_t
90 inw(int port)
91 {
92         uint16_t data;
93         __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
94         return data;
95 }
96
97 static __inline void
98 insw(int port, void *addr, int cnt)
99 {
100         __asm __volatile("cld\n\trepne\n\tinsw"                 :
101                          "=D" (addr), "=c" (cnt)                :
102                          "d" (port), "0" (addr), "1" (cnt)      :
103                          "memory", "cc");
104 }
105
106 static __inline uint32_t
107 inl(int port)
108 {
109         uint32_t data;
110         __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
111         return data;
112 }
113
114 static __inline void
115 insl(int port, void *addr, int cnt)
116 {
117         __asm __volatile("cld\n\trepne\n\tinsl"                 :
118                          "=D" (addr), "=c" (cnt)                :
119                          "d" (port), "0" (addr), "1" (cnt)      :
120                          "memory", "cc");
121 }
122
123 static __inline void
124 outb(int port, uint8_t data)
125 {
126         __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
127 }
128
129 static __inline void
130 outsb(int port, const void *addr, int cnt)
131 {
132         __asm __volatile("cld\n\trepne\n\toutsb"                :
133                          "=S" (addr), "=c" (cnt)                :
134                          "d" (port), "0" (addr), "1" (cnt)      :
135                          "cc");
136 }
137
138 static __inline void
139 outw(int port, uint16_t data)
140 {
141         __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
142 }
143
144 static __inline void
145 outsw(int port, const void *addr, int cnt)
146 {
147         __asm __volatile("cld\n\trepne\n\toutsw"                :
148                          "=S" (addr), "=c" (cnt)                :
149                          "d" (port), "0" (addr), "1" (cnt)      :
150                          "cc");
151 }
152
153 static __inline void
154 outsl(int port, const void *addr, int cnt)
155 {
156         __asm __volatile("cld\n\trepne\n\toutsl"                :
157                          "=S" (addr), "=c" (cnt)                :
158                          "d" (port), "0" (addr), "1" (cnt)      :
159                          "cc");
160 }
161
162 static __inline void
163 outl(int port, uint32_t data)
164 {
165         __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
166 }
167
168 static __inline void
169 lidt(void *p)
170 {
171         __asm __volatile("lidt (%0)" : : "r" (p));
172 }
173
174 static __inline void
175 lldt(uint16_t sel)
176 {
177         __asm __volatile("lldt %0" : : "r" (sel));
178 }
179
180 static __inline void
181 ltr(uint16_t sel)
182 {
183         __asm __volatile("ltr %0" : : "r" (sel));
184 }
185
186 static __inline void
187 lcr0(uint32_t val)
188 {
189         __asm __volatile("movl %0,%%cr0" : : "r" (val));
190 }
191
192 static __inline uint32_t
193 rcr0(void)
194 {
195         uint32_t val;
196         __asm __volatile("movl %%cr0,%0" : "=r" (val));
197         return val;
198 }
199
200 static __inline uint32_t
201 rcr2(void)
202 {
203         uint32_t val;
204         __asm __volatile("movl %%cr2,%0" : "=r" (val));
205         return val;
206 }
207
208 static __inline void
209 lcr3(uint32_t val)
210 {
211         __asm __volatile("movl %0,%%cr3" : : "r" (val));
212 }
213
214 static __inline uint32_t
215 rcr3(void)
216 {
217         uint32_t val;
218         __asm __volatile("movl %%cr3,%0" : "=r" (val));
219         return val;
220 }
221
222 static __inline void
223 lcr4(uint32_t val)
224 {
225         __asm __volatile("movl %0,%%cr4" : : "r" (val));
226 }
227
228 static __inline uint32_t
229 rcr4(void)
230 {
231         uint32_t cr4;
232         __asm __volatile("movl %%cr4,%0" : "=r" (cr4));
233         return cr4;
234 }
235
236 static __inline uint32_t
237 read_eflags(void)
238 {
239         uint32_t eflags;
240         __asm __volatile("pushfl; popl %0" : "=r" (eflags));
241         return eflags;
242 }
243
244 static __inline void
245 write_eflags(uint32_t eflags)
246 {
247         __asm __volatile("pushl %0; popfl" : : "r" (eflags));
248 }
249
250 static __inline uint32_t
251 read_ebp(void)
252 {
253         uint32_t ebp;
254         __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
255         return ebp;
256 }
257
258 static __inline uint32_t
259 read_eip(void)
260 {
261         uint32_t eip;
262         asm volatile("call 1f; 1: popl %0" : "=r"(eip));
263         return eip;
264 }
265
266 static __inline uint32_t
267 read_esp(void)
268 {
269         uint32_t esp;
270         __asm __volatile("movl %%esp,%0" : "=r" (esp));
271         return esp;
272 }
273
274 static __inline void
275 cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
276 {
277         uint32_t eax, ebx, ecx, edx;
278         asm volatile("cpuid" 
279                 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
280                 : "a" (info));
281         if (eaxp)
282                 *eaxp = eax;
283         if (ebxp)
284                 *ebxp = ebx;
285         if (ecxp)
286                 *ecxp = ecx;
287         if (edxp)
288                 *edxp = edx;
289 }
290
291 // Might need to mfence rdmsr.  supposedly wrmsr serializes, but not for x2APIC
292 static __inline uint64_t
293 read_msr(uint32_t reg)
294 {
295         uint32_t edx, eax;
296         asm volatile("rdmsr; mfence" : "=d"(edx), "=a"(eax) : "c"(reg));
297         return (uint64_t)edx << 32 | eax;
298 }
299
300 static __inline void
301 write_msr(uint32_t reg, uint64_t val)
302 {
303         asm volatile("wrmsr" : : "d"((uint32_t)(val >> 32)),
304                                  "a"((uint32_t)(val & 0xFFFFFFFF)), 
305                                  "c"(reg));
306 }
307
308 static __inline void
309 write_mmreg32(uint32_t reg, uint32_t val)
310 {
311         {TRUSTEDBLOCK *((volatile uint32_t*)reg) = val; }
312         //the C ends up producing better asm than this:
313         //asm volatile("movl %0, (%1)" : : "r"(val), "r"(reg));
314 }
315
316 static __inline uint32_t
317 read_mmreg32(uint32_t reg)
318 {
319         {TRUSTEDBLOCK return *((volatile uint32_t*)reg); }
320 }
321
322 static __inline void
323 wbinvd(void)
324 {
325         asm volatile("wbinvd");
326 }
327
328 /* this version of cpu_relax is needed to resolve some circular dependencies
329  * with arch/arch.h and arch/apic.h */
330 static __inline void
331 __cpu_relax(void)
332 {
333         // in case the compiler doesn't serialize for pause, the "m" will make sure
334         // no memory is reordered around this instruction.
335         asm volatile("pause" : : : "memory");
336 }
337
338 #endif /* !ROS_INC_X86_H */