xref: /haiku/src/system/kernel/arch/x86/arch_smp.cpp (revision e5d65858f2361fe0552495b61620c84dcee6bc00)
1 /*
2  * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6  * Distributed under the terms of the NewOS License.
7  */
8 
9 
10 #include <boot/kernel_args.h>
11 #include <vm/vm.h>
12 #include <int.h>
13 #include <smp.h>
14 #include <smp_priv.h>
15 
16 #include <arch/cpu.h>
17 #include <arch/vm.h>
18 #include <arch/smp.h>
19 
20 #include <arch/x86/apic.h>
21 #include <arch/x86/arch_smp.h>
22 #include <arch/x86/smp_priv.h>
23 #include <arch/x86/timer.h>
24 
25 #include <string.h>
26 #include <stdio.h>
27 
28 
29 //#define TRACE_ARCH_SMP
30 #ifdef TRACE_ARCH_SMP
31 #	define TRACE(x) dprintf x
32 #else
33 #	define TRACE(x) ;
34 #endif
35 
36 
37 static uint32 sCPUAPICIds[B_MAX_CPU_COUNT];
38 static uint32 sAPICVersions[B_MAX_CPU_COUNT];
39 
40 
41 static int32
42 x86_ici_interrupt(void *data)
43 {
44 	// genuine inter-cpu interrupt
45 	int cpu = smp_get_current_cpu();
46 	TRACE(("inter-cpu interrupt on cpu %d\n", cpu));
47 	return smp_intercpu_int_handler(cpu);
48 }
49 
50 
51 static int32
52 x86_spurious_interrupt(void *data)
53 {
54 	// spurious interrupt
55 	TRACE(("spurious interrupt on cpu %" B_PRId32 "\n", smp_get_current_cpu()));
56 
57 	// spurious interrupts must not be acknowledged as it does not expect
58 	// a end of interrupt - if we still do it we would loose the next best
59 	// interrupt
60 	return B_HANDLED_INTERRUPT;
61 }
62 
63 
64 static int32
65 x86_smp_error_interrupt(void *data)
66 {
67 	// smp error interrupt
68 	TRACE(("smp error interrupt on cpu %" B_PRId32 "\n", smp_get_current_cpu()));
69 	return B_HANDLED_INTERRUPT;
70 }
71 
72 
73 status_t
74 arch_smp_init(kernel_args *args)
75 {
76 	TRACE(("%s: entry\n", __func__));
77 
78 	if (!apic_available()) {
79 		// if we don't have an apic we can't do smp
80 		TRACE(("%s: apic not available for smp\n", __func__));
81 		return B_OK;
82 	}
83 
84 	// setup some globals
85 	memcpy(sCPUAPICIds, args->arch_args.cpu_apic_id, sizeof(args->arch_args.cpu_apic_id));
86 	memcpy(sAPICVersions, args->arch_args.cpu_apic_version, sizeof(args->arch_args.cpu_apic_version));
87 
88 	// set up the local apic on the boot cpu
89 	arch_smp_per_cpu_init(args, 0);
90 
91 	if (args->num_cpus > 1) {
92 		// I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted
93 		reserve_io_interrupt_vectors(3, 0xfd - ARCH_INTERRUPT_BASE);
94 		install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &x86_ici_interrupt, NULL, B_NO_LOCK_VECTOR);
95 		install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &x86_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR);
96 		install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &x86_spurious_interrupt, NULL, B_NO_LOCK_VECTOR);
97 	}
98 
99 	return B_OK;
100 }
101 
102 
103 status_t
104 arch_smp_per_cpu_init(kernel_args *args, int32 cpu)
105 {
106 	// set up the local apic on the current cpu
107 	TRACE(("arch_smp_init_percpu: setting up the apic on cpu %" B_PRId32 "\n",
108 		cpu));
109 	apic_per_cpu_init(args, cpu);
110 
111 	// setup FPU and SSE if supported
112 	x86_init_fpu();
113 
114 	return B_OK;
115 }
116 
117 
118 void
119 arch_smp_send_broadcast_ici(void)
120 {
121 	uint32 config;
122 	cpu_status state = disable_interrupts();
123 
124 	config = apic_read(APIC_INTR_COMMAND_1) & APIC_INTR_COMMAND_1_MASK;
125 	apic_write(APIC_INTR_COMMAND_1, config | 0xfd | APIC_DELIVERY_MODE_FIXED
126 		| APIC_INTR_COMMAND_1_ASSERT
127 		| APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL
128 		| APIC_INTR_COMMAND_1_DEST_ALL_BUT_SELF);
129 
130 	restore_interrupts(state);
131 }
132 
133 
134 void
135 arch_smp_send_ici(int32 target_cpu)
136 {
137 	uint32 config;
138 	uint32 timeout;
139 	cpu_status state;
140 
141 	state = disable_interrupts();
142 
143 	config = apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK;
144 	apic_write(APIC_INTR_COMMAND_2, config | sCPUAPICIds[target_cpu] << 24);
145 
146 	config = apic_read(APIC_INTR_COMMAND_1) & APIC_INTR_COMMAND_1_MASK;
147 	apic_write(APIC_INTR_COMMAND_1, config | 0xfd | APIC_DELIVERY_MODE_FIXED
148 		| APIC_INTR_COMMAND_1_ASSERT
149 		| APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL
150 		| APIC_INTR_COMMAND_1_DEST_FIELD);
151 
152 	timeout = 100000000;
153 	// wait for message to be sent
154 	while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0 && --timeout != 0)
155 		asm volatile ("pause;");
156 
157 	if (timeout == 0)
158 		panic("arch_smp_send_ici: timeout, target_cpu %" B_PRId32, target_cpu);
159 
160 	restore_interrupts(state);
161 }
162