]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
d7e50217 | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
1c79356b | 7 | * |
d7e50217 A |
8 | * This file contains Original Code and/or Modifications of Original Code |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
d7e50217 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
1c79356b A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
26 | * @OSF_FREE_COPYRIGHT@ | |
27 | */ | |
28 | /* | |
29 | * @APPLE_FREE_COPYRIGHT@ | |
30 | */ | |
31 | ||
32 | /* | |
33 | MPinterfaces.s | |
34 | ||
35 | General interface to the MP hardware handlers anonymous | |
36 | ||
37 | Lovingly crafted by Bill Angell using traditional methods and only natural or recycled materials. | |
38 | No animal products are used other than rendered otter bile. | |
39 | ||
40 | */ | |
41 | ||
42 | #include <cpus.h> | |
43 | #include <ppc/asm.h> | |
44 | #include <ppc/proc_reg.h> | |
45 | #include <ppc/POWERMAC/mp/MPPlugIn.h> | |
46 | #include <mach/machine/vm_param.h> | |
47 | #include <assym.s> | |
48 | ||
49 | /* | |
50 | * This first section is the glue for the high level C code. | |
51 | * Anything that needs any kind of system services (e.g., VM) has to be done here. The firmware | |
52 | * code that implements the SC runs in real mode. | |
53 | */ | |
54 | ||
55 | ||
56 | ||
57 | /* #define MPI_DEBUGGING 0 */ | |
58 | #define MPI_DEBUGGING 0 | |
59 | ||
60 | /* | |
61 | * The routine that implements cpu_number. | |
62 | */ | |
63 | ||
64 | ENTRY(cpu_number, TAG_NO_FRAME_USED) | |
65 | ||
66 | mfmsr r9 /* Save the old MSR */ | |
67 | rlwinm r8,r9,0,17,15 /* Clear interruptions */ | |
68 | mtmsr r8 /* Interrupts off */ | |
69 | mfsprg r7,0 /* Get per-proc block */ | |
70 | lhz r3,PP_CPU_NUMBER(r7) /* Get CPU number */ | |
71 | mtmsr r9 /* Restore interruptions to entry */ | |
72 | blr /* Return... */ | |
73 | ||
74 | ||
75 | /* | |
76 | * The routine glues to the count CPU firmware call | |
77 | */ | |
78 | ||
79 | ENTRY(MPgetProcCount, TAG_NO_FRAME_USED) | |
80 | ||
81 | mr r12,r0 /* Keep R0 pristene */ | |
82 | lis r0,HIGH_ADDR(MPgetProcCountCall) /* Top half of MPgetProcCount firmware call number */ | |
83 | ori r0,r0,LOW_ADDR(MPgetProcCountCall) /* Bottom half */ | |
84 | sc /* Go see how many processors we have */ | |
85 | ||
86 | #if MPI_DEBUGGING | |
87 | lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */ | |
88 | ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */ | |
89 | sc /* Cut a backend trace entry */ | |
90 | #endif | |
91 | ||
92 | mr r0,r12 /* Restore R0 */ | |
93 | ||
94 | blr /* Return, pass back R3... */ | |
95 | ||
96 | /* | |
97 | * The routine glues to the start CPU firmware call - actually it's really a boot | |
98 | * The first parameter is the CPU number to start | |
99 | * The second parameter is the real address of the code used to boot the processor | |
100 | * The third parameter is the real addess of the CSA for the subject processor | |
101 | */ | |
102 | ||
103 | ENTRY(MPstart, TAG_NO_FRAME_USED) | |
104 | ||
105 | mr r12,r0 /* Keep R0 pristene */ | |
106 | lis r0,HIGH_ADDR(MPstartCall) /* Top half of MPstartCall firmware call number */ | |
107 | ori r0,r0,LOW_ADDR(MPstartCall) /* Bottom half */ | |
108 | sc /* Go see how many processors we have */ | |
109 | ||
110 | #if MPI_DEBUGGING | |
111 | lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */ | |
112 | ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */ | |
113 | sc /* Cut a backend trace entry */ | |
114 | #endif | |
115 | ||
116 | mr r0,r12 /* Restore R0 */ | |
117 | blr /* Return... */ | |
118 | ||
119 | /* | |
120 | * This routine glues to the get external interrupt handler physical address | |
121 | */ | |
122 | ||
123 | ENTRY(MPexternalHook, TAG_NO_FRAME_USED) | |
124 | ||
125 | mr r12,r0 /* Keep R0 pristene */ | |
126 | lis r0,HIGH_ADDR(MPexternalHookCall) /* Top half of MPexternalHookCall firmware call number */ | |
127 | ori r0,r0,LOW_ADDR(MPexternalHookCall) /* Bottom half */ | |
128 | sc /* Go see how many processors we have */ | |
129 | ||
130 | #if MPI_DEBUGGING | |
131 | lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */ | |
132 | ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */ | |
133 | sc /* Cut a backend trace entry */ | |
134 | #endif | |
135 | ||
136 | mr r0,r12 /* Restore R0 */ | |
137 | blr /* Return... */ | |
138 | ||
139 | ||
140 | /* | |
141 | * This routine glues to the signal processor routine | |
142 | */ | |
143 | ||
144 | ENTRY(MPsignal, TAG_NO_FRAME_USED) | |
145 | ||
146 | mr r12,r0 /* Keep R0 pristene */ | |
147 | lis r0,HIGH_ADDR(MPsignalCall) /* Top half of MPsignalCall firmware call number */ | |
148 | ori r0,r0,LOW_ADDR(MPsignalCall) /* Bottom half */ | |
149 | sc /* Go kick the other guy */ | |
150 | ||
151 | #if MPI_DEBUGGING | |
152 | lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */ | |
153 | ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */ | |
154 | sc /* Cut a backend trace entry */ | |
155 | #endif | |
156 | ||
157 | mr r0,r12 /* Restore R0 */ | |
158 | blr /* Return... */ | |
159 | ||
160 | ||
161 | /* | |
162 | * This routine glues to the stop processor routine | |
163 | */ | |
164 | ||
165 | ENTRY(MPstop, TAG_NO_FRAME_USED) | |
166 | ||
167 | mr r12,r0 /* Keep R0 pristene */ | |
168 | lis r0,HIGH_ADDR(MPstopCall) /* Top half of MPsignalCall firmware call number */ | |
169 | ori r0,r0,LOW_ADDR(MPstopCall) /* Bottom half */ | |
170 | sc /* Stop the other guy cold */ | |
171 | ||
172 | #if MPI_DEBUGGING | |
173 | lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */ | |
174 | ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */ | |
175 | sc /* Cut a backend trace entry */ | |
176 | #endif | |
177 | ||
178 | mr r0,r12 /* Restore R0 */ | |
179 | blr /* Return... */ | |
180 | ||
181 | ||
182 | /* ************************************************************************************************************* | |
183 | * | |
184 | * This second section is the glue for the low level stuff directly into the MP plugin. | |
185 | * At this point every register in existence should be saved. Well, they're saved, | |
186 | * but R13 points to the savearea, and R20 to the trace entry. Please be careful | |
187 | * with these. You won't like what happens if they're different when you exit. | |
188 | * | |
189 | ***************************************************************************************************************/ | |
190 | ||
191 | ||
192 | /* | |
193 | * See how many physical processors we have | |
194 | */ | |
195 | ||
196 | ENTRY(MPgetProcCountLL, TAG_NO_FRAME_USED) | |
197 | ||
198 | lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */ | |
199 | ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */ | |
200 | lwz r10,kCountProcessors*4(r11) /* Get the routine entry point */ | |
201 | mflr r14 /* Save the return in an unused register */ | |
202 | mtlr r10 /* Set it */ | |
203 | blrl /* Call the routine */ | |
204 | mtlr r14 /* Restore firmware caller address */ | |
205 | blr /* Leave... */ | |
206 | ||
207 | /* | |
208 | * Start up a processor | |
209 | */ | |
210 | ||
211 | ENTRY(MPstartLL, TAG_NO_FRAME_USED) | |
212 | ||
213 | lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */ | |
214 | ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */ | |
215 | lwz r10,kStartProcessor*4(r11) /* Get the routine entry point */ | |
216 | mflr r14 /* Save the return in an unused register */ | |
217 | mtlr r10 /* Set it */ | |
218 | blrl /* Call the routine */ | |
219 | mtlr r14 /* Restore firmware caller address */ | |
220 | blr /* Leave... */ | |
221 | ||
222 | /* | |
223 | * Get physical address of SIGP external handler | |
224 | */ | |
225 | ||
226 | ENTRY(MPexternalHookLL, TAG_NO_FRAME_USED) | |
227 | ||
228 | lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */ | |
229 | ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */ | |
230 | lwz r10,kExternalHook*4(r11) /* Get the routine entry point */ | |
231 | mflr r14 /* Save the return in an unused register */ | |
232 | mtlr r10 /* Set it */ | |
233 | blrl /* Call the routine */ | |
234 | mtlr r14 /* Restore firmware caller address */ | |
235 | blr /* Leave... */ | |
236 | ||
237 | ||
238 | ||
239 | /* | |
240 | * Send a signal to another processor | |
241 | */ | |
242 | ||
243 | ENTRY(MPsignalLL, TAG_NO_FRAME_USED) | |
244 | ||
245 | lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */ | |
246 | ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */ | |
247 | lwz r10,kSignalProcessor*4(r11) /* Get the routine entry point */ | |
248 | mflr r14 /* Save the return in an unused register */ | |
249 | mtlr r10 /* Set it */ | |
250 | blrl /* Call the routine */ | |
251 | mtlr r14 /* Restore firmware caller address */ | |
252 | blr /* Leave... */ | |
253 | ||
254 | ||
255 | ||
256 | /* | |
257 | * Stop another processor | |
258 | */ | |
259 | ||
260 | ENTRY(MPstopLL, TAG_NO_FRAME_USED) | |
261 | ||
262 | lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */ | |
263 | ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */ | |
264 | lwz r10,kStopProcessor*4(r11) /* Get the routine entry point */ | |
265 | mflr r14 /* Save the return in an unused register */ | |
266 | mtlr r10 /* Set it */ | |
267 | blrl /* Call the routine */ | |
268 | mtlr r14 /* Restore firmware caller address */ | |
269 | blr /* Leave... */ | |
270 | ||
271 | ||
272 | /* | |
273 | * Third section: Miscellaneous MP related routines | |
274 | */ | |
275 | ||
276 | ||
277 | ||
278 | /* | |
279 | * All non-primary CPUs start here. | |
280 | * We are dispatched by the SMP driver. Addressing is real (no DR or IR), | |
281 | * interruptions disabled, etc. R3 points to the CPUStatusArea (CSA) which contains | |
282 | * most of the state for the processor. This is set up by the primary. Note that we | |
283 | * do not use everything in the CSA. Caches should be clear and coherent with | |
284 | * no paradoxies (well, maybe one doxie, a pair would be pushing it). | |
285 | */ | |
286 | ||
287 | ENTRY(start_secondary,TAG_NO_FRAME_USED) | |
288 | ||
289 | mr r31,r3 /* Get the pointer to the CSA */ | |
290 | ||
291 | lis r21,HIGH_ADDR(SpinTimeOut) /* Get the top part of the spin timeout */ | |
292 | ori r21,r21,LOW_ADDR(SpinTimeOut) /* Slam in the bottom part */ | |
293 | ||
294 | GetValid: lbz r10,CSAregsAreValid(r31) /* Get the CSA validity value */ | |
295 | ||
296 | ||
297 | mr. r10,r10 /* Is the area valid yet? */ | |
298 | bne GotValid /* Yeah... */ | |
299 | addic. r21,r21,-1 /* Count the try */ | |
300 | isync /* Make sure we don't prefetch the valid flag */ | |
301 | bge+ GetValid /* Still more tries left... */ | |
302 | blr /* Return and cancel startup request... */ | |
303 | ||
304 | GotValid: li r21,0 /* Set the valid flag off (the won't be after the RFI) */ | |
305 | lwz r10,CSAdec(r31) /* Get the decrimenter */ | |
306 | stb r21,CSAregsAreValid(r31) /* Clear that validity flag */ | |
307 | ||
308 | lwz r11,CSAdbat+(0*8)+0(r31) /* Get the first DBAT */ | |
309 | lwz r12,CSAdbat+(0*8)+4(r31) /* Get the first DBAT */ | |
310 | lwz r13,CSAdbat+(1*8)+0(r31) /* Get the second DBAT */ | |
311 | mtdec r10 /* Set the decrimenter */ | |
312 | lwz r14,CSAdbat+(1*8)+4(r31) /* Get the second DBAT */ | |
313 | mtdbatu 0,r11 /* Set top part of DBAT 0 */ | |
314 | lwz r15,CSAdbat+(2*8)+0(r31) /* Get the third DBAT */ | |
315 | mtdbatl 0,r12 /* Set lower part of DBAT 0 */ | |
316 | lwz r16,CSAdbat+(2*8)+4(r31) /* Get the third DBAT */ | |
317 | mtdbatu 1,r13 /* Set top part of DBAT 1 */ | |
318 | lwz r17,CSAdbat+(3*8)+0(r31) /* Get the fourth DBAT */ | |
319 | mtdbatl 1,r14 /* Set lower part of DBAT 1 */ | |
320 | lwz r18,CSAdbat+(3*8)+4(r31) /* Get the fourth DBAT */ | |
321 | mtdbatu 2,r15 /* Set top part of DBAT 2 */ | |
322 | lwz r11,CSAibat+(0*8)+0(r31) /* Get the first IBAT */ | |
323 | mtdbatl 2,r16 /* Set lower part of DBAT 2 */ | |
324 | lwz r12,CSAibat+(0*8)+4(r31) /* Get the first IBAT */ | |
325 | mtdbatu 3,r17 /* Set top part of DBAT 3 */ | |
326 | lwz r13,CSAibat+(1*8)+0(r31) /* Get the second IBAT */ | |
327 | mtdbatl 3,r18 /* Set lower part of DBAT 3 */ | |
328 | lwz r14,CSAibat+(1*8)+4(r31) /* Get the second IBAT */ | |
329 | mtibatu 0,r11 /* Set top part of IBAT 0 */ | |
330 | lwz r15,CSAibat+(2*8)+0(r31) /* Get the third IBAT */ | |
331 | mtibatl 0,r12 /* Set lower part of IBAT 0 */ | |
332 | lwz r16,CSAibat+(2*8)+4(r31) /* Get the third IBAT */ | |
333 | mtibatu 1,r13 /* Set top part of IBAT 1 */ | |
334 | lwz r17,CSAibat+(3*8)+0(r31) /* Get the fourth IBAT */ | |
335 | mtibatl 1,r14 /* Set lower part of IBAT 1 */ | |
336 | lwz r18,CSAibat+(3*8)+4(r31) /* Get the fourth IBAT */ | |
337 | mtibatu 2,r15 /* Set top part of IBAT 2 */ | |
338 | lwz r11,CSAsdr1(r31) /* Get the SDR1 value */ | |
339 | mtibatl 2,r16 /* Set lower part of IBAT 2 */ | |
340 | lwz r12,CSAsprg(r31) /* Get SPRG0 (the per_proc_info address) */ | |
341 | mtibatu 3,r17 /* Set top part of IBAT 3 */ | |
342 | lwz r13,CSAmsr(r31) /* Get the MSR */ | |
343 | mtibatl 3,r18 /* Set lower part of IBAT 3 */ | |
344 | lwz r14,CSApc(r31) /* Get the PC */ | |
345 | sync /* Sync up */ | |
346 | mtsdr1 r11 /* Set the SDR1 value */ | |
347 | sync /* Sync up */ | |
348 | ||
349 | la r10,CSAsr-4(r31) /* Point to SR 0 - 4 */ | |
350 | li r9,0 /* Start at SR 0 */ | |
351 | ||
352 | LoadSRs: lwz r8,4(r10) /* Get the next SR in line */ | |
353 | addi r10,r10,4 | |
354 | mtsrin r8,r9 /* Load up the SR */ | |
355 | addis r9,r9,0x1000 /* Bump to the next SR */ | |
356 | mr. r9,r9 /* See if we wrapped back to 0 */ | |
357 | bne+ LoadSRs /* Not yet... */ | |
358 | ||
359 | lwz r0,CSAgpr+(0*4)(r31) /* Get a GPR */ | |
360 | lwz r9,CSAsprg+(1*4)(r31) /* Get SPRG1 (the initial active savearea) */ | |
361 | mtsrr1 r13 /* Set the MSR to dispatch */ | |
362 | lwz r1,CSAgpr+(1*4)(r31) /* Get a GPR */ | |
363 | mtsprg 0,r12 /* Set the SPRG0 (per_proc_into) value */ | |
364 | lwz r2,CSAgpr+(2*4)(r31) /* Get a GPR */ | |
365 | mtsrr0 r14 /* Set the PC to dispatch */ | |
366 | lwz r3,CSAgpr+(3*4)(r31) /* Get a GPR */ | |
367 | mtsprg 1,r9 /* Set the SPRG1 (the initial active savearea) value */ | |
368 | lwz r4,CSAgpr+(4*4)(r31) /* Get a GPR */ | |
369 | lwz r5,CSAgpr+(5*4)(r31) /* Get a GPR */ | |
370 | lwz r6,CSAgpr+(6*4)(r31) /* Get a GPR */ | |
371 | lwz r7,CSAgpr+(7*4)(r31) /* Get a GPR */ | |
372 | lwz r8,CSAgpr+(8*4)(r31) /* Get a GPR */ | |
373 | lwz r9,CSAgpr+(9*4)(r31) /* Get a GPR */ | |
374 | lwz r10,CSAgpr+(10*4)(r31) /* Get a GPR */ | |
375 | lwz r11,CSAgpr+(11*4)(r31) /* Get a GPR */ | |
376 | lwz r12,CSAgpr+(12*4)(r31) /* Get a GPR */ | |
377 | lwz r13,CSAgpr+(13*4)(r31) /* Get a GPR */ | |
378 | lwz r14,CSAgpr+(14*4)(r31) /* Get a GPR */ | |
379 | lwz r15,CSAgpr+(15*4)(r31) /* Get a GPR */ | |
380 | lwz r16,CSAgpr+(16*4)(r31) /* Get a GPR */ | |
381 | lwz r17,CSAgpr+(17*4)(r31) /* Get a GPR */ | |
382 | lwz r18,CSAgpr+(18*4)(r31) /* Get a GPR */ | |
383 | lwz r19,CSAgpr+(19*4)(r31) /* Get a GPR */ | |
384 | lwz r20,CSAgpr+(20*4)(r31) /* Get a GPR */ | |
385 | lwz r21,CSAgpr+(21*4)(r31) /* Get a GPR */ | |
386 | lwz r22,CSAgpr+(22*4)(r31) /* Get a GPR */ | |
387 | lwz r23,CSAgpr+(23*4)(r31) /* Get a GPR */ | |
388 | lwz r24,CSAgpr+(24*4)(r31) /* Get a GPR */ | |
389 | lwz r25,CSAgpr+(25*4)(r31) /* Get a GPR */ | |
390 | lwz r26,CSAgpr+(26*4)(r31) /* Get a GPR */ | |
391 | lwz r27,CSAgpr+(27*4)(r31) /* Get a GPR */ | |
392 | lwz r28,CSAgpr+(28*4)(r31) /* Get a GPR */ | |
393 | lwz r29,CSAgpr+(29*4)(r31) /* Get a GPR */ | |
394 | lwz r30,CSAgpr+(30*4)(r31) /* Get a GPR */ | |
395 | lwz r31,CSAgpr+(31*4)(r31) /* Get a GPR */ | |
396 | ||
397 | sync /* Make sure we're sunk */ | |
398 | ||
399 | rfi /* Get the whole shebang going... */ | |
400 | ||
401 | .long 0 | |
402 | .long 0 | |
403 | .long 0 | |
404 | .long 0 | |
405 | .long 0 | |
406 | .long 0 | |
407 | .long 0 | |
408 | .long 0 | |
409 | ||
410 | ||
411 | ||
412 | ||
413 | /* | |
414 | * This routine handles requests to firmware from another processor. It is actually the second level | |
415 | * of a three level signaling protocol. The first level is handled in the physical MP driver. It is the | |
416 | * basic physical control for the processor, e.g., physical stop, reset, start. The second level (this | |
417 | * one) handles cross-processor firmware requests, e.g., complete TLB purges. The last are AST requests | |
418 | * which are handled directly by mach. | |
419 | * | |
420 | * If this code handles the request (based upon MPPICParm0BU which is valid until the next SIGP happens - | |
421 | * actually, don't count on it once you enable) it will RFI back to the | |
422 | * interrupted code. If not, it will return and let the higher level interrupt handler be called. | |
423 | * | |
424 | * We need to worry about registers we use here, check in lowmem_vectors to see what is boten and verboten. | |
425 | * | |
426 | * Note that there are no functions implemented yet. | |
427 | */ | |
428 | ||
429 | ||
430 | ENTRY(MPsignalFW, TAG_NO_FRAME_USED) | |
431 | ||
432 | ||
433 | mfspr r7,pir /* Get the processor address */ | |
434 | lis r6,HIGH_ADDR(EXT(MPPICPUs)) /* Get high part of CPU control block array */ | |
435 | rlwinm r7,r7,5,23,26 /* Get index into CPU array */ | |
436 | ori r6,r6,HIGH_ADDR(EXT(MPPICPUs)) /* Get low part of CPU control block array */ | |
437 | add r7,r7,r6 /* Point to the control block for this processor */ | |
438 | lwz r6,MPPICParm0BU(r7) /* Just pick this up for now */ | |
439 | blr /* Leave... */ | |
440 | ||
441 | ||
442 | /* | |
443 | * Make space for the maximum supported CPUs in the data section | |
444 | */ | |
445 | ||
446 | #ifdef __ELF__ | |
447 | .section ".data" | |
448 | #else | |
449 | .data | |
450 | #endif | |
451 | .align 5 | |
452 | EXT(CSA): | |
453 | .set ., .+(CSAsize*NCPUS) | |
454 | #ifndef __MACHO__ | |
455 | .type EXT(CSA), @object | |
456 | .size EXT(CSA), CSAsize*NCPUS | |
457 | #endif | |
458 | .globl EXT(CSA) |