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