xref: /haiku/src/system/kernel/arch/x86/apic.cpp (revision b289aaf66bbf6e173aa90fa194fc256965f1b34d)
1 /*
2  * Copyright 2010, Michael Lotz, mmlr@mlotz.ch. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
6  * Distributed under the terms of the MIT License.
7  *
8  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
9  * Distributed under the terms of the NewOS License.
10  */
11 
12 #include <arch/x86/apic.h>
13 
14 #include <debug.h>
15 #include <vm/vm.h>
16 
17 #include "timers/apic_timer.h"
18 
19 
20 static void *sLocalAPIC = NULL;
21 
22 
23 bool
24 apic_available()
25 {
26 	return sLocalAPIC != NULL;
27 }
28 
29 
30 uint32
31 apic_read(uint32 offset)
32 {
33 	return *(volatile uint32 *)((char *)sLocalAPIC + offset);
34 }
35 
36 
37 void
38 apic_write(uint32 offset, uint32 data)
39 {
40 	*(volatile uint32 *)((char *)sLocalAPIC + offset) = data;
41 }
42 
43 
44 uint32
45 apic_local_id()
46 {
47 	return (apic_read(APIC_ID) & 0xffffffff) >> 24;
48 }
49 
50 
51 void
52 apic_end_of_interrupt()
53 {
54 	apic_write(APIC_EOI, 0);
55 }
56 
57 
58 status_t
59 apic_init(kernel_args *args)
60 {
61 	if (args->arch_args.apic == NULL)
62 		return B_NO_INIT;
63 
64 	sLocalAPIC = args->arch_args.apic;
65 	dprintf("mapping local apic at %p\n", sLocalAPIC);
66 	if (vm_map_physical_memory(B_SYSTEM_TEAM, "local apic", &sLocalAPIC,
67 			B_EXACT_ADDRESS, B_PAGE_SIZE,
68 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
69 			args->arch_args.apic_phys, true) < 0) {
70 		panic("mapping the local apic failed");
71 		return B_ERROR;
72 	}
73 
74 	return B_OK;
75 }
76 
77 
78 status_t
79 apic_per_cpu_init(kernel_args *args, int32 cpu)
80 {
81 	dprintf("setting up apic for CPU %ld: apic id %lu, version %lu\n", cpu,
82 		apic_local_id(), apic_read(APIC_VERSION));
83 
84 	/* set spurious interrupt vector to 0xff */
85 	uint32 config = apic_read(APIC_SPURIOUS_INTR_VECTOR) & 0xffffff00;
86 	config |= APIC_ENABLE | 0xff;
87 	apic_write(APIC_SPURIOUS_INTR_VECTOR, config);
88 
89 	// don't touch the LINT0/1 configuration in virtual wire mode
90 	// ToDo: implement support for other modes...
91 #if 0
92 	if (cpu == 0) {
93 		/* setup LINT0 as ExtINT */
94 		config = (apic_read(APIC_LINT0) & 0xffff00ff);
95 		config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM;
96 		apic_write(APIC_LINT0, config);
97 
98 		/* setup LINT1 as NMI */
99 		config = (apic_read(APIC_LINT1) & 0xffff00ff);
100 		config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP;
101 		apic_write(APIC_LINT1, config);
102 	}
103 	if (cpu > 0) {
104 		dprintf("LINT0: %p\n", (void *)apic_read(APIC_LINT0));
105 		dprintf("LINT1: %p\n", (void *)apic_read(APIC_LINT1));
106 
107 		/* disable LINT0/1 */
108 		config = apic_read(APIC_LINT0);
109 		apic_write(APIC_LINT0, config | APIC_LVT_MASKED);
110 
111 		config = apic_read(APIC_LINT1);
112 		apic_write(APIC_LINT1, config | APIC_LVT_MASKED);
113 	} else {
114 		dprintf("0: LINT0: %p\n", (void *)apic_read(APIC_LINT0));
115 		dprintf("0: LINT1: %p\n", (void *)apic_read(APIC_LINT1));
116 	}
117 #endif
118 
119 	apic_timer_per_cpu_init(args, cpu);
120 
121 	/* setup error vector to 0xfe */
122 	config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe;
123 	apic_write(APIC_LVT_ERROR, config);
124 
125 	/* accept all interrupts */
126 	config = apic_read(APIC_TASK_PRIORITY) & 0xffffff00;
127 	apic_write(APIC_TASK_PRIORITY, config);
128 
129 	config = apic_read(APIC_SPURIOUS_INTR_VECTOR);
130 	apic_end_of_interrupt();
131 
132 	return B_OK;
133 }
134