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