SMP Booting, APIC, and IRQs
[akaros.git] / inc / x86.h
1 #ifndef JOS_INC_X86_H
2 #define JOS_INC_X86_H
3
4 #include <inc/types.h>
5
6 /* Model Specific Registers */
7 #define IA32_APIC_BASE                          0x1b
8 #define IA32_MTRR_DEF_TYPE                      0x2ff
9
10 #define MSR_APIC_ENABLE                         0x00000800
11 #define MSR_APIC_BASE_ADDRESS           0x0000000FFFFFF000
12
13 /* CPUID */
14 #define CPUID_PSE_SUPPORT                       0x00000008
15
16 static __inline void breakpoint(void) __attribute__((always_inline));
17 static __inline uint8_t inb(int port) __attribute__((always_inline));
18 static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
19 static __inline uint16_t inw(int port) __attribute__((always_inline));
20 static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline));
21 static __inline uint32_t inl(int port) __attribute__((always_inline));
22 static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline));
23 static __inline void outb(int port, uint8_t data) __attribute__((always_inline));
24 static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline));
25 static __inline void outw(int port, uint16_t data) __attribute__((always_inline));
26 static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline));
27 static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline));
28 static __inline void outl(int port, uint32_t data) __attribute__((always_inline));
29 static __inline void invlpg(void *addr) __attribute__((always_inline));
30 static __inline void lidt(void *p) __attribute__((always_inline));
31 static __inline void lldt(uint16_t sel) __attribute__((always_inline));
32 static __inline void ltr(uint16_t sel) __attribute__((always_inline));
33 static __inline void lcr0(uint32_t val) __attribute__((always_inline));
34 static __inline uint32_t rcr0(void) __attribute__((always_inline));
35 static __inline uint32_t rcr2(void) __attribute__((always_inline));
36 static __inline void lcr3(uint32_t val) __attribute__((always_inline));
37 static __inline uint32_t rcr3(void) __attribute__((always_inline));
38 static __inline void lcr4(uint32_t val) __attribute__((always_inline));
39 static __inline uint32_t rcr4(void) __attribute__((always_inline));
40 static __inline void tlbflush(void) __attribute__((always_inline));
41 static __inline uint32_t read_eflags(void) __attribute__((always_inline));
42 static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline));
43 static __inline uint32_t read_ebp(void) __attribute__((always_inline));
44 static __inline uint32_t read_esp(void) __attribute__((always_inline));
45 static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp);
46 static __inline uint64_t read_tsc(void) __attribute__((always_inline));
47 static __inline uint64_t read_msr(uint32_t reg) __attribute__((always_inline));
48 static __inline void write_msr(uint32_t reg, uint64_t val) __attribute__((always_inline));
49 static __inline uint32_t read_mmreg32(uint32_t reg) __attribute__((always_inline));
50 static __inline void write_mmreg32(uint32_t reg, uint32_t val) __attribute__((always_inline));
51
52 static __inline void
53 breakpoint(void)
54 {
55         __asm __volatile("int3");
56 }
57
58 static __inline uint8_t
59 inb(int port)
60 {
61         uint8_t data;
62         __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
63         return data;
64 }
65
66 static __inline void
67 insb(int port, void *addr, int cnt)
68 {
69         __asm __volatile("cld\n\trepne\n\tinsb"                 :
70                          "=D" (addr), "=c" (cnt)                :
71                          "d" (port), "0" (addr), "1" (cnt)      :
72                          "memory", "cc");
73 }
74
75 static __inline uint16_t
76 inw(int port)
77 {
78         uint16_t data;
79         __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
80         return data;
81 }
82
83 static __inline void
84 insw(int port, void *addr, int cnt)
85 {
86         __asm __volatile("cld\n\trepne\n\tinsw"                 :
87                          "=D" (addr), "=c" (cnt)                :
88                          "d" (port), "0" (addr), "1" (cnt)      :
89                          "memory", "cc");
90 }
91
92 static __inline uint32_t
93 inl(int port)
94 {
95         uint32_t data;
96         __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
97         return data;
98 }
99
100 static __inline void
101 insl(int port, void *addr, int cnt)
102 {
103         __asm __volatile("cld\n\trepne\n\tinsl"                 :
104                          "=D" (addr), "=c" (cnt)                :
105                          "d" (port), "0" (addr), "1" (cnt)      :
106                          "memory", "cc");
107 }
108
109 static __inline void
110 outb(int port, uint8_t data)
111 {
112         __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
113 }
114
115 static __inline void
116 outsb(int port, const void *addr, int cnt)
117 {
118         __asm __volatile("cld\n\trepne\n\toutsb"                :
119                          "=S" (addr), "=c" (cnt)                :
120                          "d" (port), "0" (addr), "1" (cnt)      :
121                          "cc");
122 }
123
124 static __inline void
125 outw(int port, uint16_t data)
126 {
127         __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
128 }
129
130 static __inline void
131 outsw(int port, const void *addr, int cnt)
132 {
133         __asm __volatile("cld\n\trepne\n\toutsw"                :
134                          "=S" (addr), "=c" (cnt)                :
135                          "d" (port), "0" (addr), "1" (cnt)      :
136                          "cc");
137 }
138
139 static __inline void
140 outsl(int port, const void *addr, int cnt)
141 {
142         __asm __volatile("cld\n\trepne\n\toutsl"                :
143                          "=S" (addr), "=c" (cnt)                :
144                          "d" (port), "0" (addr), "1" (cnt)      :
145                          "cc");
146 }
147
148 static __inline void
149 outl(int port, uint32_t data)
150 {
151         __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
152 }
153
154 static __inline void 
155 invlpg(void *addr)
156
157         __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
158 }  
159
160 static __inline void
161 lidt(void *p)
162 {
163         __asm __volatile("lidt (%0)" : : "r" (p));
164 }
165
166 static __inline void
167 lldt(uint16_t sel)
168 {
169         __asm __volatile("lldt %0" : : "r" (sel));
170 }
171
172 static __inline void
173 ltr(uint16_t sel)
174 {
175         __asm __volatile("ltr %0" : : "r" (sel));
176 }
177
178 static __inline void
179 lcr0(uint32_t val)
180 {
181         __asm __volatile("movl %0,%%cr0" : : "r" (val));
182 }
183
184 static __inline uint32_t
185 rcr0(void)
186 {
187         uint32_t val;
188         __asm __volatile("movl %%cr0,%0" : "=r" (val));
189         return val;
190 }
191
192 static __inline uint32_t
193 rcr2(void)
194 {
195         uint32_t val;
196         __asm __volatile("movl %%cr2,%0" : "=r" (val));
197         return val;
198 }
199
200 static __inline void
201 lcr3(uint32_t val)
202 {
203         __asm __volatile("movl %0,%%cr3" : : "r" (val));
204 }
205
206 static __inline uint32_t
207 rcr3(void)
208 {
209         uint32_t val;
210         __asm __volatile("movl %%cr3,%0" : "=r" (val));
211         return val;
212 }
213
214 static __inline void
215 lcr4(uint32_t val)
216 {
217         __asm __volatile("movl %0,%%cr4" : : "r" (val));
218 }
219
220 static __inline uint32_t
221 rcr4(void)
222 {
223         uint32_t cr4;
224         __asm __volatile("movl %%cr4,%0" : "=r" (cr4));
225         return cr4;
226 }
227
228 static __inline void
229 tlbflush(void)
230 {
231         uint32_t cr3;
232         __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
233         __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
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_esp(void)
260 {
261         uint32_t esp;
262         __asm __volatile("movl %%esp,%0" : "=r" (esp));
263         return esp;
264 }
265
266 static __inline void
267 cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
268 {
269         uint32_t eax, ebx, ecx, edx;
270         asm volatile("cpuid" 
271                 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
272                 : "a" (info));
273         if (eaxp)
274                 *eaxp = eax;
275         if (ebxp)
276                 *ebxp = ebx;
277         if (ecxp)
278                 *ecxp = ecx;
279         if (edxp)
280                 *edxp = edx;
281 }
282
283 static __inline uint64_t
284 read_tsc(void)
285 {
286         uint64_t tsc;
287         __asm __volatile("rdtsc" : "=A" (tsc));
288         return tsc;
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 #endif /* !JOS_INC_X86_H */