xref: /haiku/src/system/kernel/arch/x86/apic.cpp (revision 2beda3bb5be8191b672688bed7ddcadd2b17dc41)
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 #include <arch/x86/msi.h>
14 
15 #include <debug.h>
16 #include <vm/vm.h>
17 
18 #include "timers/apic_timer.h"
19 
20 
21 static void *sLocalAPIC = NULL;
22 
23 
24 bool
25 apic_available()
26 {
27 	return sLocalAPIC != NULL;
28 }
29 
30 
31 uint32
32 apic_read(uint32 offset)
33 {
34 	return *(volatile uint32 *)((char *)sLocalAPIC + offset);
35 }
36 
37 
38 void
39 apic_write(uint32 offset, uint32 data)
40 {
41 	*(volatile uint32 *)((char *)sLocalAPIC + offset) = data;
42 }
43 
44 
45 uint32
46 apic_local_id()
47 {
48 	return (apic_read(APIC_ID) & 0xffffffff) >> 24;
49 }
50 
51 
52 void
53 apic_end_of_interrupt()
54 {
55 	apic_write(APIC_EOI, 0);
56 }
57 
58 
59 void
60 apic_disable_local_ints()
61 {
62 	// just clear them out completely
63 	apic_write(APIC_LVT_LINT0, APIC_LVT_MASKED);
64 	apic_write(APIC_LVT_LINT1, APIC_LVT_MASKED);
65 }
66 
67 
68 status_t
69 apic_init(kernel_args *args)
70 {
71 	if (args->arch_args.apic == NULL)
72 		return B_NO_INIT;
73 
74 	sLocalAPIC = args->arch_args.apic;
75 	dprintf("mapping local apic at %p\n", sLocalAPIC);
76 	if (vm_map_physical_memory(B_SYSTEM_TEAM, "local apic", &sLocalAPIC,
77 			B_EXACT_ADDRESS, B_PAGE_SIZE,
78 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
79 			args->arch_args.apic_phys, true) < 0) {
80 		panic("mapping the local apic failed");
81 		return B_ERROR;
82 	}
83 
84 	return B_OK;
85 }
86 
87 
88 status_t
89 apic_per_cpu_init(kernel_args *args, int32 cpu)
90 {
91 	dprintf("setting up apic for CPU %" B_PRId32 ": apic id %" B_PRIu32 ", "
92 		"version %" B_PRIu32 "\n", cpu, apic_local_id(),
93 		apic_read(APIC_VERSION));
94 
95 	/* set spurious interrupt vector to 0xff */
96 	uint32 config = apic_read(APIC_SPURIOUS_INTR_VECTOR) & 0xffffff00;
97 	config |= APIC_ENABLE | 0xff;
98 	apic_write(APIC_SPURIOUS_INTR_VECTOR, config);
99 
100 	// don't touch the LINT0/1 configuration in virtual wire mode
101 	// ToDo: implement support for other modes...
102 #if 0
103 	if (cpu == 0) {
104 		/* setup LINT0 as ExtINT */
105 		config = (apic_read(APIC_LINT0) & 0xffff00ff);
106 		config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM;
107 		apic_write(APIC_LINT0, config);
108 
109 		/* setup LINT1 as NMI */
110 		config = (apic_read(APIC_LINT1) & 0xffff00ff);
111 		config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP;
112 		apic_write(APIC_LINT1, config);
113 	}
114 	if (cpu > 0) {
115 		dprintf("LINT0: %p\n", (void *)apic_read(APIC_LINT0));
116 		dprintf("LINT1: %p\n", (void *)apic_read(APIC_LINT1));
117 
118 		/* disable LINT0/1 */
119 		config = apic_read(APIC_LINT0);
120 		apic_write(APIC_LINT0, config | APIC_LVT_MASKED);
121 
122 		config = apic_read(APIC_LINT1);
123 		apic_write(APIC_LINT1, config | APIC_LVT_MASKED);
124 	} else {
125 		dprintf("0: LINT0: %p\n", (void *)apic_read(APIC_LINT0));
126 		dprintf("0: LINT1: %p\n", (void *)apic_read(APIC_LINT1));
127 	}
128 #endif
129 
130 	apic_timer_per_cpu_init(args, cpu);
131 
132 	/* setup error vector to 0xfe */
133 	config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe;
134 	apic_write(APIC_LVT_ERROR, config);
135 
136 	/* accept all interrupts */
137 	config = apic_read(APIC_TASK_PRIORITY) & 0xffffff00;
138 	apic_write(APIC_TASK_PRIORITY, config);
139 
140 	config = apic_read(APIC_SPURIOUS_INTR_VECTOR);
141 	apic_end_of_interrupt();
142 
143 	return B_OK;
144 }
145