btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / arch / x86 / apic.cpp
blob176102977d1f06738850f0d5e73144a923266b86
1 /*
2 * Copyright 2010, Michael Lotz, mmlr@mlotz.ch. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
6 * Distributed under the terms of the MIT License.
8 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
9 * Distributed under the terms of the NewOS License.
12 #include <arch/x86/apic.h>
13 #include <arch/x86/msi.h>
15 #include <debug.h>
16 #include <safemode.h>
17 #include <vm/vm.h>
18 #include <util/AutoLock.h>
20 #include "timers/apic_timer.h"
23 static void *sLocalAPIC = NULL;
24 static bool sX2APIC = false;
27 bool
28 apic_available()
30 return sLocalAPIC != NULL || sX2APIC;
34 bool
35 x2apic_available()
37 return sX2APIC;
41 uint32
42 apic_read(uint32 offset)
44 return *(volatile uint32 *)((char *)sLocalAPIC + offset);
48 void
49 apic_write(uint32 offset, uint32 data)
51 *(volatile uint32 *)((char *)sLocalAPIC + offset) = data;
55 uint32
56 apic_local_id()
58 if (sX2APIC)
59 return x86_read_msr(IA32_MSR_APIC_ID);
60 else
61 return (apic_read(APIC_ID) & 0xffffffff) >> 24;
65 uint32
66 apic_version()
68 if (sX2APIC)
69 return x86_read_msr(IA32_MSR_APIC_VERSION);
70 else
71 return apic_read(APIC_VERSION);
75 uint32
76 apic_task_priority()
78 if (sX2APIC)
79 return x86_read_msr(IA32_MSR_APIC_TASK_PRIORITY);
80 else
81 return apic_read(APIC_TASK_PRIORITY);
85 void
86 apic_set_task_priority(uint32 config)
88 if (sX2APIC)
89 x86_write_msr(IA32_MSR_APIC_TASK_PRIORITY, config);
90 else
91 apic_write(APIC_TASK_PRIORITY, config);
95 void
96 apic_end_of_interrupt()
98 if (sX2APIC)
99 x86_write_msr(IA32_MSR_APIC_EOI, 0);
100 else
101 apic_write(APIC_EOI, 0);
105 uint32
106 apic_logical_apic_id()
108 if (sX2APIC)
109 return x86_read_msr(IA32_MSR_APIC_LOGICAL_DEST);
110 else
111 return apic_read(APIC_LOGICAL_DEST);
115 void
116 apic_disable_local_ints()
118 // just clear them out completely
119 if (sX2APIC) {
120 x86_write_msr(IA32_MSR_APIC_LVT_LINT0, APIC_LVT_MASKED);
121 x86_write_msr(IA32_MSR_APIC_LVT_LINT1, APIC_LVT_MASKED);
122 } else {
123 apic_write(APIC_LVT_LINT0, APIC_LVT_MASKED);
124 apic_write(APIC_LVT_LINT1, APIC_LVT_MASKED);
129 uint32
130 apic_spurious_intr_vector()
132 if (sX2APIC)
133 return x86_read_msr(IA32_MSR_APIC_SPURIOUS_INTR_VECTOR);
134 else
135 return apic_read(APIC_SPURIOUS_INTR_VECTOR);
139 void
140 apic_set_spurious_intr_vector(uint32 config)
142 if (sX2APIC)
143 x86_write_msr(IA32_MSR_APIC_SPURIOUS_INTR_VECTOR, config);
144 else
145 apic_write(APIC_SPURIOUS_INTR_VECTOR, config);
149 void
150 apic_set_interrupt_command(uint32 destination, uint32 mode)
152 if (sX2APIC) {
153 uint64 command = x86_read_msr(IA32_MSR_APIC_INTR_COMMAND);
154 command &= APIC_INTR_COMMAND_1_MASK;
155 command |= (uint64)destination << 32;
156 command |= mode;
157 x86_write_msr(IA32_MSR_APIC_INTR_COMMAND, command);
158 } else {
159 uint32 command2 = apic_read(APIC_INTR_COMMAND_2)
160 & APIC_INTR_COMMAND_2_MASK;
161 command2 |= destination << 24;
162 apic_write(APIC_INTR_COMMAND_2, command2);
164 uint32 command1 = apic_read(APIC_INTR_COMMAND_1)
165 & APIC_INTR_COMMAND_1_MASK;
166 command1 |= mode;
167 apic_write(APIC_INTR_COMMAND_1, command1);
172 bool
173 apic_interrupt_delivered(void)
175 if (sX2APIC)
176 return true;
177 else
178 return (apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) == 0;
182 uint32
183 apic_lvt_timer()
185 if (sX2APIC)
186 return x86_read_msr(IA32_MSR_APIC_LVT_TIMER);
187 else
188 return apic_read(APIC_LVT_TIMER);
192 void
193 apic_set_lvt_timer(uint32 config)
195 if (sX2APIC)
196 x86_write_msr(IA32_MSR_APIC_LVT_TIMER, config);
197 else
198 apic_write(APIC_LVT_TIMER, config);
202 uint32
203 apic_lvt_error()
205 if (sX2APIC)
206 return x86_read_msr(IA32_MSR_APIC_LVT_ERROR);
207 else
208 return apic_read(APIC_LVT_ERROR);
212 void
213 apic_set_lvt_error(uint32 config)
215 if (sX2APIC)
216 x86_write_msr(IA32_MSR_APIC_LVT_ERROR, config);
217 else
218 apic_write(APIC_LVT_ERROR, config);
222 uint32
223 apic_lvt_initial_timer_count()
225 if (sX2APIC)
226 return x86_read_msr(IA32_MSR_APIC_INITIAL_TIMER_COUNT);
227 else
228 return apic_read(APIC_INITIAL_TIMER_COUNT);
232 void
233 apic_set_lvt_initial_timer_count(uint32 config)
235 if (sX2APIC)
236 x86_write_msr(IA32_MSR_APIC_INITIAL_TIMER_COUNT, config);
237 else
238 apic_write(APIC_INITIAL_TIMER_COUNT, config);
242 uint32
243 apic_lvt_timer_divide_config()
245 if (sX2APIC)
246 return x86_read_msr(IA32_MSR_APIC_TIMER_DIVIDE_CONFIG);
247 else
248 return apic_read(APIC_TIMER_DIVIDE_CONFIG);
252 void
253 apic_set_lvt_timer_divide_config(uint32 config)
255 if (sX2APIC)
256 x86_write_msr(IA32_MSR_APIC_TIMER_DIVIDE_CONFIG, config);
257 else
258 apic_write(APIC_TIMER_DIVIDE_CONFIG, config);
262 status_t
263 apic_init(kernel_args *args)
265 if (args->arch_args.apic == NULL)
266 return B_NO_INIT;
268 if (x86_check_feature(IA32_FEATURE_EXT_X2APIC, FEATURE_EXT)) {
269 dprintf("found x2apic\n");
270 #if 0
271 if (!get_safemode_boolean(B_SAFEMODE_DISABLE_X2APIC, false)) {
272 sX2APIC = true;
273 return B_OK;
276 dprintf("x2apic disabled per safemode setting\n");
277 #else
278 if (get_safemode_boolean(B_SAFEMODE_ENABLE_X2APIC, false)) {
279 sX2APIC = true;
281 dprintf("x2apic enabled per safemode setting\n");
282 return B_OK;
284 #endif
287 sLocalAPIC = args->arch_args.apic;
288 dprintf("mapping local apic at %p\n", sLocalAPIC);
289 if (vm_map_physical_memory(B_SYSTEM_TEAM, "local apic", &sLocalAPIC,
290 B_EXACT_ADDRESS, B_PAGE_SIZE,
291 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
292 args->arch_args.apic_phys, true) < 0) {
293 panic("mapping the local apic failed");
294 return B_ERROR;
297 return B_OK;
301 status_t
302 apic_per_cpu_init(kernel_args *args, int32 cpu)
304 if (sX2APIC) {
305 uint64 apic_base = x86_read_msr(IA32_MSR_APIC_BASE);
306 if ((apic_base & IA32_MSR_APIC_BASE_X2APIC) == 0) {
307 x86_write_msr(IA32_MSR_APIC_BASE, apic_base
308 | IA32_MSR_APIC_BASE_X2APIC);
312 dprintf("setting up %sapic for CPU %" B_PRId32 ": apic id %" B_PRIu32 ", "
313 "version %" B_PRIu32 "\n", sX2APIC ? "x2" : "", cpu, apic_local_id(),
314 apic_version());
316 if (!sX2APIC && cpu < 8) {
317 apic_write(APIC_DEST_FORMAT, uint32(-1));
319 uint8 logical_apic_id = 1 << cpu;
320 uint32 value = apic_read(APIC_LOGICAL_DEST);
321 value &= 0xffffff;
322 apic_write(APIC_LOGICAL_DEST, value | (logical_apic_id << 24));
325 // get logical APIC ID
326 gCPU[cpu].arch.logical_apic_id = apic_logical_apic_id();
327 if (!sX2APIC)
328 gCPU[cpu].arch.logical_apic_id >>= 24;
329 dprintf("CPU %" B_PRId32 ": logical apic id: %#" B_PRIx32 "\n", cpu,
330 gCPU[cpu].arch.logical_apic_id);
332 /* set spurious interrupt vector to 0xff */
333 uint32 config = apic_spurious_intr_vector() & 0xffffff00;
334 config |= APIC_ENABLE | 0xff;
335 apic_set_spurious_intr_vector(config);
337 // don't touch the LINT0/1 configuration in virtual wire mode
338 // ToDo: implement support for other modes...
339 #if 0
340 if (cpu == 0) {
341 /* setup LINT0 as ExtINT */
342 config = (apic_read(APIC_LINT0) & 0xffff00ff);
343 config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM;
344 apic_write(APIC_LINT0, config);
346 /* setup LINT1 as NMI */
347 config = (apic_read(APIC_LINT1) & 0xffff00ff);
348 config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP;
349 apic_write(APIC_LINT1, config);
351 if (cpu > 0) {
352 dprintf("LINT0: %p\n", (void *)apic_read(APIC_LINT0));
353 dprintf("LINT1: %p\n", (void *)apic_read(APIC_LINT1));
355 /* disable LINT0/1 */
356 config = apic_read(APIC_LINT0);
357 apic_write(APIC_LINT0, config | APIC_LVT_MASKED);
359 config = apic_read(APIC_LINT1);
360 apic_write(APIC_LINT1, config | APIC_LVT_MASKED);
361 } else {
362 dprintf("0: LINT0: %p\n", (void *)apic_read(APIC_LINT0));
363 dprintf("0: LINT1: %p\n", (void *)apic_read(APIC_LINT1));
365 #endif
367 apic_timer_per_cpu_init(args, cpu);
369 /* setup error vector to 0xfe */
370 config = (apic_lvt_error() & 0xffffff00) | 0xfe;
371 apic_set_lvt_error(config);
373 /* accept all interrupts */
374 config = apic_task_priority() & 0xffffff00;
375 apic_set_task_priority(config);
377 config = apic_spurious_intr_vector();
378 apic_end_of_interrupt();
380 return B_OK;