]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/mp.h
3b3861e647bfb22336dcc8cc7ae5789d0d958ff1
[apple/xnu.git] / osfmk / i386 / mp.h
1 /*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * @OSF_COPYRIGHT@
25 */
26 /*
27 * Mach Operating System
28 * Copyright (c) 1991,1990 Carnegie Mellon University
29 * All Rights Reserved.
30 *
31 * Permission to use, copy, modify and distribute this software and its
32 * documentation is hereby granted, provided that both the copyright
33 * notice and this permission notice appear in all copies of the
34 * software, derivative works or modified versions, and any portions
35 * thereof, and that both notices appear in supporting documentation.
36 *
37 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
38 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
39 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 *
41 * Carnegie Mellon requests users of this software to return to
42 *
43 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
44 * School of Computer Science
45 * Carnegie Mellon University
46 * Pittsburgh PA 15213-3890
47 *
48 * any improvements or extensions that they make and grant Carnegie Mellon
49 * the rights to redistribute these changes.
50 */
51
52 /*
53 */
54 #ifdef KERNEL_PRIVATE
55
56 #ifndef _I386AT_MP_H_
57 #define _I386AT_MP_H_
58
59 #ifndef DEBUG
60 #include <debug.h>
61 #endif
62 //#define MP_DEBUG 1
63
64 #include <i386/apic.h>
65 #include <i386/mp_events.h>
66
67 #define LAPIC_ID_MAX (LAPIC_ID_MASK)
68
69 #define MAX_CPUS (LAPIC_ID_MAX + 1)
70
71 #ifndef ASSEMBLER
72 #include <sys/cdefs.h>
73 #include <mach/boolean.h>
74 #include <mach/kern_return.h>
75
76 __BEGIN_DECLS
77
78 extern kern_return_t intel_startCPU(int slot_num);
79 extern void i386_init_slave(void);
80 extern void smp_init(void);
81
82 extern void cpu_interrupt(int cpu);
83
84 extern void lapic_init(void);
85 extern void lapic_shutdown(void);
86 extern void lapic_smm_restore(void);
87 extern boolean_t lapic_probe(void);
88 extern void lapic_dump(void);
89 extern int lapic_interrupt(int interrupt, void *state);
90 extern void lapic_end_of_interrupt(void);
91 extern int lapic_to_cpu[];
92 extern int cpu_to_lapic[];
93 extern int lapic_interrupt_base;
94 extern void lapic_cpu_map(int lapic, int cpu_num);
95
96 extern void lapic_set_timer(
97 boolean_t interrupt,
98 lapic_timer_mode_t mode,
99 lapic_timer_divide_t divisor,
100 lapic_timer_count_t initial_count);
101
102 extern void lapic_get_timer(
103 lapic_timer_mode_t *mode,
104 lapic_timer_divide_t *divisor,
105 lapic_timer_count_t *initial_count,
106 lapic_timer_count_t *current_count);
107
108 typedef void (*i386_intr_func_t)(void *);
109 extern void lapic_set_timer_func(i386_intr_func_t func);
110 extern void lapic_set_pmi_func(i386_intr_func_t func);
111
112 __END_DECLS
113
114 #endif /* ASSEMBLER */
115
116 #define CPU_NUMBER(r) \
117 movl %gs:CPU_NUMBER_GS,r
118
119 #define CPU_NUMBER_FROM_LAPIC(r) \
120 movl EXT(lapic_id),r; \
121 movl 0(r),r; \
122 shrl $(LAPIC_ID_SHIFT),r; \
123 andl $(LAPIC_ID_MASK),r; \
124 movl EXT(lapic_to_cpu)(,r,4),r
125
126
127 /* word describing the reason for the interrupt, one per cpu */
128
129 #ifndef ASSEMBLER
130 #include <kern/lock.h>
131
132 extern unsigned int real_ncpus; /* real number of cpus */
133 extern unsigned int max_ncpus; /* max number of cpus */
134 decl_simple_lock_data(extern,kdb_lock) /* kdb lock */
135
136 __BEGIN_DECLS
137
138 extern void console_init(void);
139 extern void *console_cpu_alloc(boolean_t boot_cpu);
140 extern void console_cpu_free(void *console_buf);
141
142 extern int kdb_cpu; /* current cpu running kdb */
143 extern int kdb_debug;
144 extern int kdb_is_slave[];
145 extern int kdb_active[];
146
147 extern volatile boolean_t mp_kdp_trap;
148 extern void mp_kdp_enter(void);
149 extern void mp_kdp_exit(void);
150
151 /*
152 * All cpu rendezvous:
153 */
154 extern void mp_rendezvous(void (*setup_func)(void *),
155 void (*action_func)(void *),
156 void (*teardown_func)(void *),
157 void *arg);
158
159 __END_DECLS
160
161 #if MP_DEBUG
162 typedef struct {
163 uint64_t time;
164 int cpu;
165 mp_event_t event;
166 } cpu_signal_event_t;
167
168 #define LOG_NENTRIES 100
169 typedef struct {
170 uint64_t count[MP_LAST];
171 int next_entry;
172 cpu_signal_event_t entry[LOG_NENTRIES];
173 } cpu_signal_event_log_t;
174
175 extern cpu_signal_event_log_t *cpu_signal[];
176 extern cpu_signal_event_log_t *cpu_handle[];
177
178 #define DBGLOG(log,_cpu,_event) { \
179 boolean_t spl = ml_set_interrupts_enabled(FALSE); \
180 cpu_signal_event_log_t *logp = log[cpu_number()]; \
181 int next = logp->next_entry; \
182 cpu_signal_event_t *eventp = &logp->entry[next]; \
183 \
184 logp->count[_event]++; \
185 \
186 eventp->time = rdtsc64(); \
187 eventp->cpu = _cpu; \
188 eventp->event = _event; \
189 if (next == (LOG_NENTRIES - 1)) \
190 logp->next_entry = 0; \
191 else \
192 logp->next_entry++; \
193 \
194 (void) ml_set_interrupts_enabled(spl); \
195 }
196
197 #define DBGLOG_CPU_INIT(cpu) { \
198 cpu_signal_event_log_t **sig_logpp = &cpu_signal[cpu]; \
199 cpu_signal_event_log_t **hdl_logpp = &cpu_handle[cpu]; \
200 \
201 if (*sig_logpp == NULL && \
202 kmem_alloc(kernel_map, \
203 (vm_offset_t *) sig_logpp, \
204 sizeof(cpu_signal_event_log_t)) != KERN_SUCCESS)\
205 panic("DBGLOG_CPU_INIT cpu_signal allocation failed\n");\
206 bzero(*sig_logpp, sizeof(cpu_signal_event_log_t)); \
207 if (*hdl_logpp == NULL && \
208 kmem_alloc(kernel_map, \
209 (vm_offset_t *) hdl_logpp, \
210 sizeof(cpu_signal_event_log_t)) != KERN_SUCCESS)\
211 panic("DBGLOG_CPU_INIT cpu_handle allocation failed\n");\
212 bzero(*sig_logpp, sizeof(cpu_signal_event_log_t)); \
213 }
214 #else /* MP_DEBUG */
215 #define DBGLOG(log,_cpu,_event)
216 #define DBGLOG_CPU_INIT(cpu)
217 #endif /* MP_DEBUG */
218
219 #endif /* ASSEMBLER */
220
221 #define i_bit(bit, word) ((long)(*(word)) & ((long)1 << (bit)))
222
223
224 /*
225 * Device driver synchronization.
226 *
227 * at386_io_lock(op) and at386_io_unlock() are called
228 * by device drivers when accessing H/W. The underlying
229 * Processing is machine dependant. But the op argument
230 * to the at386_io_lock is generic
231 */
232
233 #define MP_DEV_OP_MAX 4
234 #define MP_DEV_WAIT MP_DEV_OP_MAX /* Wait for the lock */
235
236 /*
237 * If the caller specifies an op value different than MP_DEV_WAIT, the
238 * at386_io_lock function must return true if lock was successful else
239 * false
240 */
241
242 #define MP_DEV_OP_START 0 /* If lock busy, register a pending start op */
243 #define MP_DEV_OP_INTR 1 /* If lock busy, register a pending intr */
244 #define MP_DEV_OP_TIMEO 2 /* If lock busy, register a pending timeout */
245 #define MP_DEV_OP_CALLB 3 /* If lock busy, register a pending callback */
246
247 #if MACH_RT
248 #define _DISABLE_PREEMPTION \
249 incl %gs:CPU_PREEMPTION_LEVEL
250
251 #define _ENABLE_PREEMPTION \
252 decl %gs:CPU_PREEMPTION_LEVEL ; \
253 jne 9f ; \
254 pushl %eax ; \
255 pushl %ecx ; \
256 pushl %edx ; \
257 call EXT(kernel_preempt_check) ; \
258 popl %edx ; \
259 popl %ecx ; \
260 popl %eax ; \
261 9:
262
263 #define _ENABLE_PREEMPTION_NO_CHECK \
264 decl %gs:CPU_PREEMPTION_LEVEL
265
266 #if MACH_ASSERT
267 #define DISABLE_PREEMPTION \
268 pushl %eax; \
269 pushl %ecx; \
270 pushl %edx; \
271 call EXT(_disable_preemption); \
272 popl %edx; \
273 popl %ecx; \
274 popl %eax
275 #define ENABLE_PREEMPTION \
276 pushl %eax; \
277 pushl %ecx; \
278 pushl %edx; \
279 call EXT(_enable_preemption); \
280 popl %edx; \
281 popl %ecx; \
282 popl %eax
283 #define ENABLE_PREEMPTION_NO_CHECK \
284 pushl %eax; \
285 pushl %ecx; \
286 pushl %edx; \
287 call EXT(_enable_preemption_no_check); \
288 popl %edx; \
289 popl %ecx; \
290 popl %eax
291 #define MP_DISABLE_PREEMPTION \
292 pushl %eax; \
293 pushl %ecx; \
294 pushl %edx; \
295 call EXT(_mp_disable_preemption); \
296 popl %edx; \
297 popl %ecx; \
298 popl %eax
299 #define MP_ENABLE_PREEMPTION \
300 pushl %eax; \
301 pushl %ecx; \
302 pushl %edx; \
303 call EXT(_mp_enable_preemption); \
304 popl %edx; \
305 popl %ecx; \
306 popl %eax
307 #define MP_ENABLE_PREEMPTION_NO_CHECK \
308 pushl %eax; \
309 pushl %ecx; \
310 pushl %edx; \
311 call EXT(_mp_enable_preemption_no_check); \
312 popl %edx; \
313 popl %ecx; \
314 popl %eax
315 #else /* MACH_ASSERT */
316 #define DISABLE_PREEMPTION _DISABLE_PREEMPTION
317 #define ENABLE_PREEMPTION _ENABLE_PREEMPTION
318 #define ENABLE_PREEMPTION_NO_CHECK _ENABLE_PREEMPTION_NO_CHECK
319 #define MP_DISABLE_PREEMPTION _DISABLE_PREEMPTION
320 #define MP_ENABLE_PREEMPTION _ENABLE_PREEMPTION
321 #define MP_ENABLE_PREEMPTION_NO_CHECK _ENABLE_PREEMPTION_NO_CHECK
322 #endif /* MACH_ASSERT */
323
324 #else /* MACH_RT */
325 #define DISABLE_PREEMPTION
326 #define ENABLE_PREEMPTION
327 #define ENABLE_PREEMPTION_NO_CHECK
328 #define MP_DISABLE_PREEMPTION
329 #define MP_ENABLE_PREEMPTION
330 #define MP_ENABLE_PREEMPTION_NO_CHECK
331 #endif /* MACH_RT */
332
333 #endif /* _I386AT_MP_H_ */
334
335 #endif /* KERNEL_PRIVATE */