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