Bochs compatible SMP booting and enable_irqsave()
[akaros.git] / inc / x86.h
1 #ifndef JOS_INC_X86_H
2 #define JOS_INC_X86_H
3
4 #include <inc/types.h>
5 #include <inc/mmu.h>
6
7 /* Model Specific Registers */
8 #define IA32_APIC_BASE                          0x1b
9 #define IA32_MTRR_DEF_TYPE                      0x2ff
10
11 #define MSR_APIC_ENABLE                         0x00000800
12 #define MSR_APIC_BASE_ADDRESS           0x0000000FFFFFF000
13
14 /* CPUID */
15 #define CPUID_PSE_SUPPORT                       0x00000008
16
17 static __inline void breakpoint(void) __attribute__((always_inline));
18 static __inline uint8_t inb(int port) __attribute__((always_inline));
19 static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
20 static __inline uint16_t inw(int port) __attribute__((always_inline));
21 static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline));
22 static __inline uint32_t inl(int port) __attribute__((always_inline));
23 static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline));
24 static __inline void outb(int port, uint8_t data) __attribute__((always_inline));
25 static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline));
26 static __inline void outw(int port, uint16_t data) __attribute__((always_inline));
27 static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline));
28 static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline));
29 static __inline void outl(int port, uint32_t data) __attribute__((always_inline));
30 static __inline void invlpg(void *addr) __attribute__((always_inline));
31 static __inline void lidt(void *p) __attribute__((always_inline));
32 static __inline void lldt(uint16_t sel) __attribute__((always_inline));
33 static __inline void ltr(uint16_t sel) __attribute__((always_inline));
34 static __inline void lcr0(uint32_t val) __attribute__((always_inline));
35 static __inline uint32_t rcr0(void) __attribute__((always_inline));
36 static __inline uint32_t rcr2(void) __attribute__((always_inline));
37 static __inline void lcr3(uint32_t val) __attribute__((always_inline));
38 static __inline uint32_t rcr3(void) __attribute__((always_inline));
39 static __inline void lcr4(uint32_t val) __attribute__((always_inline));
40 static __inline uint32_t rcr4(void) __attribute__((always_inline));
41 static __inline void tlbflush(void) __attribute__((always_inline));
42 static __inline uint32_t read_eflags(void) __attribute__((always_inline));
43 static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline));
44 static __inline uint32_t read_ebp(void) __attribute__((always_inline));
45 static __inline uint32_t read_esp(void) __attribute__((always_inline));
46 static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp);
47 static __inline uint64_t read_tsc(void) __attribute__((always_inline));
48 static __inline uint64_t read_msr(uint32_t reg) __attribute__((always_inline));
49 static __inline void write_msr(uint32_t reg, uint64_t val) __attribute__((always_inline));
50 static __inline uint32_t read_mmreg32(uint32_t reg) __attribute__((always_inline));
51 static __inline void write_mmreg32(uint32_t reg, uint32_t val) __attribute__((always_inline));
52 static __inline void enable_irq(void) __attribute__((always_inline));
53 static __inline void disable_irq(void) __attribute__((always_inline));
54 static __inline bool enable_irqsave(void) __attribute__((always_inline));
55 static __inline void disable_irqsave(bool state) __attribute__((always_inline));
56 static __inline void cpu_relax(void) __attribute__((always_inline));
57
58 static __inline void
59 breakpoint(void)
60 {
61         __asm __volatile("int3");
62 }
63
64 static __inline uint8_t
65 inb(int port)
66 {
67         uint8_t data;
68         __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
69         return data;
70 }
71
72 static __inline void
73 insb(int port, void *addr, int cnt)
74 {
75         __asm __volatile("cld\n\trepne\n\tinsb"                 :
76                          "=D" (addr), "=c" (cnt)                :
77                          "d" (port), "0" (addr), "1" (cnt)      :
78                          "memory", "cc");
79 }
80
81 static __inline uint16_t
82 inw(int port)
83 {
84         uint16_t data;
85         __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
86         return data;
87 }
88
89 static __inline void
90 insw(int port, void *addr, int cnt)
91 {
92         __asm __volatile("cld\n\trepne\n\tinsw"                 :
93                          "=D" (addr), "=c" (cnt)                :
94                          "d" (port), "0" (addr), "1" (cnt)      :
95                          "memory", "cc");
96 }
97
98 static __inline uint32_t
99 inl(int port)
100 {
101         uint32_t data;
102         __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
103         return data;
104 }
105
106 static __inline void
107 insl(int port, void *addr, int cnt)
108 {
109         __asm __volatile("cld\n\trepne\n\tinsl"                 :
110                          "=D" (addr), "=c" (cnt)                :
111                          "d" (port), "0" (addr), "1" (cnt)      :
112                          "memory", "cc");
113 }
114
115 static __inline void
116 outb(int port, uint8_t data)
117 {
118         __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
119 }
120
121 static __inline void
122 outsb(int port, const void *addr, int cnt)
123 {
124         __asm __volatile("cld\n\trepne\n\toutsb"                :
125                          "=S" (addr), "=c" (cnt)                :
126                          "d" (port), "0" (addr), "1" (cnt)      :
127                          "cc");
128 }
129
130 static __inline void
131 outw(int port, uint16_t data)
132 {
133         __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
134 }
135
136 static __inline void
137 outsw(int port, const void *addr, int cnt)
138 {
139         __asm __volatile("cld\n\trepne\n\toutsw"                :
140                          "=S" (addr), "=c" (cnt)                :
141                          "d" (port), "0" (addr), "1" (cnt)      :
142                          "cc");
143 }
144
145 static __inline void
146 outsl(int port, const void *addr, int cnt)
147 {
148         __asm __volatile("cld\n\trepne\n\toutsl"                :
149                          "=S" (addr), "=c" (cnt)                :
150                          "d" (port), "0" (addr), "1" (cnt)      :
151                          "cc");
152 }
153
154 static __inline void
155 outl(int port, uint32_t data)
156 {
157         __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
158 }
159
160 static __inline void 
161 invlpg(void *addr)
162
163         __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
164 }  
165
166 static __inline void
167 lidt(void *p)
168 {
169         __asm __volatile("lidt (%0)" : : "r" (p));
170 }
171
172 static __inline void
173 lldt(uint16_t sel)
174 {
175         __asm __volatile("lldt %0" : : "r" (sel));
176 }
177
178 static __inline void
179 ltr(uint16_t sel)
180 {
181         __asm __volatile("ltr %0" : : "r" (sel));
182 }
183
184 static __inline void
185 lcr0(uint32_t val)
186 {
187         __asm __volatile("movl %0,%%cr0" : : "r" (val));
188 }
189
190 static __inline uint32_t
191 rcr0(void)
192 {
193         uint32_t val;
194         __asm __volatile("movl %%cr0,%0" : "=r" (val));
195         return val;
196 }
197
198 static __inline uint32_t
199 rcr2(void)
200 {
201         uint32_t val;
202         __asm __volatile("movl %%cr2,%0" : "=r" (val));
203         return val;
204 }
205
206 static __inline void
207 lcr3(uint32_t val)
208 {
209         __asm __volatile("movl %0,%%cr3" : : "r" (val));
210 }
211
212 static __inline uint32_t
213 rcr3(void)
214 {
215         uint32_t val;
216         __asm __volatile("movl %%cr3,%0" : "=r" (val));
217         return val;
218 }
219
220 static __inline void
221 lcr4(uint32_t val)
222 {
223         __asm __volatile("movl %0,%%cr4" : : "r" (val));
224 }
225
226 static __inline uint32_t
227 rcr4(void)
228 {
229         uint32_t cr4;
230         __asm __volatile("movl %%cr4,%0" : "=r" (cr4));
231         return cr4;
232 }
233
234 static __inline void
235 tlbflush(void)
236 {
237         uint32_t cr3;
238         __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
239         __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
240 }
241
242 static __inline uint32_t
243 read_eflags(void)
244 {
245         uint32_t eflags;
246         __asm __volatile("pushfl; popl %0" : "=r" (eflags));
247         return eflags;
248 }
249
250 static __inline void
251 write_eflags(uint32_t eflags)
252 {
253         __asm __volatile("pushl %0; popfl" : : "r" (eflags));
254 }
255
256 static __inline uint32_t
257 read_ebp(void)
258 {
259         uint32_t ebp;
260         __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
261         return ebp;
262 }
263
264 static __inline uint32_t
265 read_esp(void)
266 {
267         uint32_t esp;
268         __asm __volatile("movl %%esp,%0" : "=r" (esp));
269         return esp;
270 }
271
272 static __inline void
273 cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
274 {
275         uint32_t eax, ebx, ecx, edx;
276         asm volatile("cpuid" 
277                 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
278                 : "a" (info));
279         if (eaxp)
280                 *eaxp = eax;
281         if (ebxp)
282                 *ebxp = ebx;
283         if (ecxp)
284                 *ecxp = ecx;
285         if (edxp)
286                 *edxp = edx;
287 }
288
289 static __inline uint64_t
290 read_tsc(void)
291 {
292         uint64_t tsc;
293         __asm __volatile("rdtsc" : "=A" (tsc));
294         return tsc;
295 }
296
297 // Might need to mfence rdmsr.  supposedly wrmsr serializes, but not for x2APIC
298 static __inline uint64_t
299 read_msr(uint32_t reg)
300 {
301         uint32_t edx, eax;
302         asm volatile("rdmsr; mfence" : "=d"(edx), "=a"(eax) : "c"(reg));
303         return (uint64_t)edx << 32 | eax;
304 }
305
306 static __inline void
307 write_msr(uint32_t reg, uint64_t val)
308 {
309         asm volatile("wrmsr" : : "d"((uint32_t)(val >> 32)),
310                                  "a"((uint32_t)(val & 0xFFFFFFFF)), 
311                                  "c"(reg));
312 }
313
314 static __inline void
315 write_mmreg32(uint32_t reg, uint32_t val)
316 {
317         {TRUSTEDBLOCK *((volatile uint32_t*)reg) = val; }
318         //the C ends up producing better asm than this:
319         //asm volatile("movl %0, (%1)" : : "r"(val), "r"(reg));
320 }
321
322 static __inline uint32_t
323 read_mmreg32(uint32_t reg)
324 {
325         {TRUSTEDBLOCK return *((volatile uint32_t*)reg); }
326 }
327
328 static __inline void
329 enable_irq(void)
330 {
331         asm volatile("sti");
332 }
333
334 static __inline void
335 disable_irq(void)
336 {
337         asm volatile("cli");
338 }
339
340 static __inline bool
341 enable_irqsave(void)
342 {
343         // if interrupts are already on, return true
344         if (read_eflags() & FL_IF)
345                 return 1;
346         enable_irq();
347         return 0;
348 }
349
350 static __inline void
351 disable_irqsave(bool state)
352 {
353         // if ints were already on, leave them on.
354         if (state)
355                 return;
356         disable_irq();
357 }
358
359 static __inline void
360 cpu_relax(void)
361 {
362         asm volatile("pause");
363 }
364 #endif /* !JOS_INC_X86_H */