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>
18 #include <util/AutoLock.h>
20 #include "timers/apic_timer.h"
23 static void *sLocalAPIC
= NULL
;
24 static bool sX2APIC
= false;
30 return sLocalAPIC
!= NULL
|| sX2APIC
;
42 apic_read(uint32 offset
)
44 return *(volatile uint32
*)((char *)sLocalAPIC
+ offset
);
49 apic_write(uint32 offset
, uint32 data
)
51 *(volatile uint32
*)((char *)sLocalAPIC
+ offset
) = data
;
59 return x86_read_msr(IA32_MSR_APIC_ID
);
61 return (apic_read(APIC_ID
) & 0xffffffff) >> 24;
69 return x86_read_msr(IA32_MSR_APIC_VERSION
);
71 return apic_read(APIC_VERSION
);
79 return x86_read_msr(IA32_MSR_APIC_TASK_PRIORITY
);
81 return apic_read(APIC_TASK_PRIORITY
);
86 apic_set_task_priority(uint32 config
)
89 x86_write_msr(IA32_MSR_APIC_TASK_PRIORITY
, config
);
91 apic_write(APIC_TASK_PRIORITY
, config
);
96 apic_end_of_interrupt()
99 x86_write_msr(IA32_MSR_APIC_EOI
, 0);
101 apic_write(APIC_EOI
, 0);
106 apic_logical_apic_id()
109 return x86_read_msr(IA32_MSR_APIC_LOGICAL_DEST
);
111 return apic_read(APIC_LOGICAL_DEST
);
116 apic_disable_local_ints()
118 // just clear them out completely
120 x86_write_msr(IA32_MSR_APIC_LVT_LINT0
, APIC_LVT_MASKED
);
121 x86_write_msr(IA32_MSR_APIC_LVT_LINT1
, APIC_LVT_MASKED
);
123 apic_write(APIC_LVT_LINT0
, APIC_LVT_MASKED
);
124 apic_write(APIC_LVT_LINT1
, APIC_LVT_MASKED
);
130 apic_spurious_intr_vector()
133 return x86_read_msr(IA32_MSR_APIC_SPURIOUS_INTR_VECTOR
);
135 return apic_read(APIC_SPURIOUS_INTR_VECTOR
);
140 apic_set_spurious_intr_vector(uint32 config
)
143 x86_write_msr(IA32_MSR_APIC_SPURIOUS_INTR_VECTOR
, config
);
145 apic_write(APIC_SPURIOUS_INTR_VECTOR
, config
);
150 apic_set_interrupt_command(uint32 destination
, uint32 mode
)
153 uint64 command
= x86_read_msr(IA32_MSR_APIC_INTR_COMMAND
);
154 command
&= APIC_INTR_COMMAND_1_MASK
;
155 command
|= (uint64
)destination
<< 32;
157 x86_write_msr(IA32_MSR_APIC_INTR_COMMAND
, command
);
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
;
167 apic_write(APIC_INTR_COMMAND_1
, command1
);
173 apic_interrupt_delivered(void)
178 return (apic_read(APIC_INTR_COMMAND_1
) & APIC_DELIVERY_STATUS
) == 0;
186 return x86_read_msr(IA32_MSR_APIC_LVT_TIMER
);
188 return apic_read(APIC_LVT_TIMER
);
193 apic_set_lvt_timer(uint32 config
)
196 x86_write_msr(IA32_MSR_APIC_LVT_TIMER
, config
);
198 apic_write(APIC_LVT_TIMER
, config
);
206 return x86_read_msr(IA32_MSR_APIC_LVT_ERROR
);
208 return apic_read(APIC_LVT_ERROR
);
213 apic_set_lvt_error(uint32 config
)
216 x86_write_msr(IA32_MSR_APIC_LVT_ERROR
, config
);
218 apic_write(APIC_LVT_ERROR
, config
);
223 apic_lvt_initial_timer_count()
226 return x86_read_msr(IA32_MSR_APIC_INITIAL_TIMER_COUNT
);
228 return apic_read(APIC_INITIAL_TIMER_COUNT
);
233 apic_set_lvt_initial_timer_count(uint32 config
)
236 x86_write_msr(IA32_MSR_APIC_INITIAL_TIMER_COUNT
, config
);
238 apic_write(APIC_INITIAL_TIMER_COUNT
, config
);
243 apic_lvt_timer_divide_config()
246 return x86_read_msr(IA32_MSR_APIC_TIMER_DIVIDE_CONFIG
);
248 return apic_read(APIC_TIMER_DIVIDE_CONFIG
);
253 apic_set_lvt_timer_divide_config(uint32 config
)
256 x86_write_msr(IA32_MSR_APIC_TIMER_DIVIDE_CONFIG
, config
);
258 apic_write(APIC_TIMER_DIVIDE_CONFIG
, config
);
263 apic_init(kernel_args
*args
)
265 if (args
->arch_args
.apic
== NULL
)
268 if (x86_check_feature(IA32_FEATURE_EXT_X2APIC
, FEATURE_EXT
)) {
269 dprintf("found x2apic\n");
271 if (!get_safemode_boolean(B_SAFEMODE_DISABLE_X2APIC
, false)) {
276 dprintf("x2apic disabled per safemode setting\n");
278 if (get_safemode_boolean(B_SAFEMODE_ENABLE_X2APIC
, false)) {
281 dprintf("x2apic enabled per safemode setting\n");
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");
302 apic_per_cpu_init(kernel_args
*args
, int32 cpu
)
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(),
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
);
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();
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...
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
);
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
);
362 dprintf("0: LINT0: %p\n", (void *)apic_read(APIC_LINT0
));
363 dprintf("0: LINT1: %p\n", (void *)apic_read(APIC_LINT1
));
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();