00001 /* 00002 + * QuickThreads -- Threads-building toolkit. 00003 + * Copyright (c) 1993 by David Keppel 00004 + * 00005 + * Permission to use, copy, modify and distribute this software and 00006 + * its documentation for any purpose and without fee is hereby 00007 + * granted, provided that the above copyright notice and this notice 00008 + * appear in all copies. This software is provided as a 00009 + * proof-of-concept and for demonstration purposes; there is no 00010 + * representation about the suitability of this software for any 00011 + * purpose. 00012 + * 00013 00014 + * PowerPC-Mach thread switching module. 00015 + * 00016 + * This software is largely based on the original PowerPC-Linux porting 00017 + * developed by Ken Aaker <kenaaker@silverbacksystems.com> 00018 + * 00019 + * Marco Bucci <marco.bucci@inwind.it> 00020 + * December 2002 00021 + * 00022 + */ 00023 00024 00025 #ifndef QUICKTHREADS_POWERPC_H 00026 #define QUICKTHREADS_POWERPC_H 00027 00028 00029 /***************************************************************************** 00030 * 00031 * DESCRIPTION 00032 * 00033 * This is the QuickThreads switching module implementation for PowerPC 00034 * running under Mach kernel. It was developed and tested under MacOS X, that 00035 * is under Darwin (the UNIX-BSD fundation of MacOS X). 00036 * 00037 * Notice that the Mach PowerPC ABI (Application Binary Interface) [1] is 00038 * not the same than System V ABI [2] used by most of the LINUX PowerPC 00039 * implementations. 00040 * 00041 * IMPLEMENTATION NOTES 00042 * 00043 * 1) Porting on System V ABI 00044 * Excluding the variant argument calling convention, Mach and System V ABI 00045 * are enough similar and it could be possible to use some simple macro, to 00046 * adapt the code for both the ABIs. Actually, the only relevant difference 00047 * is in the linkage area structure and in the position where the Link and 00048 * the Condition registers are saved. As to the calling conventions, there 00049 * are differences with floating points argument passing and with variant 00050 * argument lists. Notice that, on Mach, the caller's stack frame allocates 00051 * space to hold all arguments ([1] p.51), while on System V, the caller's 00052 * stack frame allocates space to hold just the arguments that don't fit into 00053 * registers ([2] p.3.18). 00054 * 00055 * 2) Variant argument list implementation 00056 * Variant argument calling on a RISC machine is not easy to implement since 00057 * parameters are passed via registers instead of via stack. In a general 00058 * variant argument implementation, the caller's stack must map the whole 00059 * parameter list following the rules related to the use of the GPR and FPR 00060 * parameter registers and the stack alignment ([1] p.54). 00061 * This implementation is quite simple and not general. It works under the 00062 * hypothesis that arguments are 4-bytes aligned integers. 00063 * 00064 * 3) This heather file organisation 00065 * I preferred to not make confusion between macros that are needed (i.e. 00066 * directly used) by QuickThreads and internal "implementation" macros. You 00067 * will find QuickThreds macros in the end of this header. Sometime they just 00068 * refer to an analogous "internal" macro. On the top, there are the macros 00069 * that I used to make more clean (I hope) the implementation. I could include 00070 * some system heather (as to stack layout definitions, prologs and epilogs, 00071 * etc.), but I preferred to have a self-contained heather in order to make 00072 * all more clear for mantaining and for possible porting on another ABI. 00073 * 00074 * 00075 * REFERENCES 00076 * 00077 * [1] - Mach-O Runtime Architecture 00078 * Runtime Concepts and Conventions for Mac OS X Programs 00079 * Preliminary July 2002 00080 * 00081 * [2] - SYSTEM V APPLICATION BINARY INTERFACE 00082 * PowerPC Processor Supplement 00083 * September 1995 00084 * 00085 * On MacOS X, more documentation is available by installing the "Developer 00086 * Tools". Useful macros and documentation can be found in the system headers 00087 * files such as asm.h, asm_help.h etc. (see /usr/architecture/ppc/ or 00088 * /System/Library/Frameworks/Kernel.framework/Headers/architecture/ppc/). 00089 00090 *****************************************************************************/ 00091 00092 /***************************************************************************** 00093 * 00094 * PowerPC Mach-O Stack frame (see [1]) 00095 * 00096 00097 ................ 00098 + + 00099 | | reserved 00100 + CALLER'S LINKAGE AREA + 00101 | | Caller's LR 00102 + + 00103 | | Caller's CR 00104 + + 00105 backchain -> | | Caller's backchain 00106 +==========================+ 00107 | | FPR31 00108 + FPR SAVE AREA + 00109 .............. 00110 + + 00111 | | FPRn 00112 +--------------------------+ 00113 | | GPR31 00114 + GPR SAVE AREA + 00115 .............. 00116 + + 00117 | | GPRn 00118 +--------------------------+ 00119 | | 00120 + ALIGNMEBNT PAD + 00121 .............. 00122 + (if needed) + 00123 | | 00124 +--------------------------+ 00125 | | 00126 + LOCAL VARIABLES AREA + 00127 .............. 00128 + + 00129 | | 00130 +--------------------------+ 00131 | | PAR(n) 00132 + + 00133 | | 00134 + PARAMETER AREA + 00135 .............. 00136 + for FUTURE call + 00137 | | PAR(1) 00138 + + 00139 SP + 24 -> | | PAR(0) 00140 +--------------------------+ 00141 SP + 20 -> | | Caller's TOC 00142 + + 00143 SP + 16 -> | | reserved 00144 + + 00145 SP + 12 -> | | reserved 00146 + LINKAGE AREA + 00147 SP + 8 -> | | LR callee-save for FUTURE call 00148 + + 00149 SP + 4 -> | | CR callee-save for FUTURE call 00150 + + 00151 SP -> | | backchain 00152 +==========================+ 00153 STACK TOP (lower address) 00154 00155 Stack grows down 00156 | 00157 V 00158 * NOTE: 00159 * 00160 * 1) Parameter are allocated in the CALLER's parameter area. This area must 00161 * be large enough to hold all parameters regardless if they are or not passed 00162 * in registers. 00163 * 00164 * The caller parameter area is used: 00165 * - by the caller, to store parameters to the callee that cannot fit in 00166 * registers (no more parameter registers are available); 00167 * - by the callee, to save parameter registers (for istance because they are 00168 * needed for a further call). 00169 * 00170 * Obviously, the callee saves parameter registers, in the location in which 00171 * they are mapped on the caller's stack frame. So, be aware that, if 00172 * something else is stored in that location, it could be deleted after a call. 00173 * 00174 * 2) The callee saves LR and CR in the caller's linkage area. All other 00175 * callee's state are saved in its own stack frame. 00176 * 00177 00178 *****************************************************************************/ 00179 00180 00181 /***************************************************************************** 00182 * 00183 * Stack initialization for a single argument thread 00184 * 00185 00186 00187 top + QUICKTHREADS_STKBASE -> STACK BOTTOM (higher address) 00188 +==========================+ 00189 | | 00190 + + 00191 .............. 00192 + + 00193 | | 00194 +--------------------------+ 00195 top + QUICKTHREADS_ONLY_INDEX * 4 -> | only param | PAR(3) 00196 + + 00197 top + QUICKTHREADS_USER_INDEX * 4 -> | userf param | PAR(2) 00198 + + 00199 top + QUICKTHREADS_ARGT_INDEX * 4 -> | t param | PAR(1) 00200 + + 00201 top + QUICKTHREADS_ARGU_INDEX * 4 -> | u param | PAR(0) 00202 +--------------------------+ 00203 | | 00204 + + 00205 .............. 00206 + + 00207 top + QUICKTHREADS_RETURN_INDEX * 4 -> | qt_start | LR save 00208 + + 00209 .............. 00210 + + 00211 top + QUICKTHREADS_BLOCKI_FRAME_SIZE -> | top + QUICKTHREADS_STKBASE | backchain 00212 +==========================+ 00213 | | 00214 + + 00215 .............. 00216 + + 00217 | | 00218 +--------------------------+ 00219 | | 00220 + + 00221 .............. 00222 + + 00223 top -> |top + QUICKTHREADS_BLOCKI_FRAME_SIZE| backchain 00224 +==========================+ 00225 STACK TOP (lower address) 00226 00227 Stack grows down 00228 | 00229 V 00230 00231 ***************************************************************************** 00232 * 00233 * Stack initialization for a variant argument thread 00234 * 00235 00236 bottom -> STACK BOTTOM (higher address) 00237 +==========================+ 00238 | | 00239 + + 00240 .............. 00241 + + 00242 top + QUICKTHREADS_VSTKBASE -> | arg(0) | PAR(4) 00243 +--------------------------+ 00244 top + QUICKTHREADS_CLEANUP_INDEX * 4 -> | cleanup param | PAR(3) 00245 + + 00246 top + QUICKTHREADS_USER_INDEX * 4 -> | userf param | PAR(2) 00247 + + 00248 top + QUICKTHREADS_VSTARTUP_INDEX * 4 ->| startup param | PAR(1) 00249 + + 00250 top + QUICKTHREADS_ARGT_INDEX * 4 -> | t param | PAR(0) 00251 +--------------------------+ 00252 | | 00253 + + 00254 .............. 00255 + + 00256 top + QUICKTHREADS_RETURN_INDEX * 4 -> | qt_start | LR save 00257 + + 00258 .............. 00259 top + QUICKTHREADS_BLOCKI_FRAME_SIZE -> | top + QUICKTHREADS_STKBASE | backchain 00260 +==========================+ 00261 | | 00262 + + 00263 .............. 00264 + + 00265 | | 00266 +--------------------------+ 00267 | | 00268 + + 00269 .............. 00270 + + 00271 top -> |top + QUICKTHREADS_BLOCKI_FRAME_SIZE| backchain 00272 +==========================+ 00273 STACK TOP (lower address) 00274 00275 Stack grows down 00276 | 00277 V 00278 00279 * NOTE: 00280 * 00281 * Parameters are passed to "qt_start" or to "qt_vstart" putting them into 00282 * the stack frames of "qt_start" or "qt_vstart" themselves. This not a 00283 * conventional parameter passing because parameters should be put into the 00284 * caller's stack, not into the callee's one. Actually we must consider 00285 * that as a preload of the parameter area that "qt_start" or "qt_vstart" 00286 * will use for their own calls. 00287 * Be aware of the fact that, during a call, the caller's parameter area is, 00288 * in a certain sense, volatile. In facts, the callee can save parameter 00289 * registers on the caller's parameter area. 00290 * 00291 *****************************************************************************/ 00292 00293 00294 /***************************************************************************** 00295 00296 Define PowerPC Mach-O related macros 00297 00298 *****************************************************************************/ 00299 00300 00301 00302 typedef unsigned long PPC_W; 00303 00304 /* Stack pointer must always be a multiple of 16 */ 00305 #define PPC_STACK_INCR 16 00306 #define PPC_ROUND_STACK(length) \ 00307 (((length)+PPC_STACK_INCR-1) & ~(PPC_STACK_INCR-1)) 00308 00309 00310 #define PPC_LINKAGE_AREA 24 00311 #define PPC_CR_SAVE 4 00312 #define PPC_LR_SAVE 8 00313 00314 #define PPC_PARAM_AREA(n) (4*(n)) 00315 00316 #define PPC_GPR_SAVE_AREA (4*19) /* GPR13-GPR31 must be saved */ 00317 #define PPC_FPR_SAVE_AREA (8*18) /* FPR14-FPR31 must be saved */ 00318 00319 /* Define parameter offset on the stack. 00320 * NOTICE: Parameters are numbered 0, 1, ..., n. 00321 */ 00322 #define PPC_PAR(i) (PPC_LINKAGE_AREA+(i)*4) 00323 00324 /***************************************************************************** 00325 00326 Define stack frames 00327 00328 *****************************************************************************/ 00329 00330 00331 /* Define the "qt_blocki" and "qt_abort" stack frame. We use the same stack 00332 * frame for both. 00333 * 00334 00335 top + S -> 00336 +==========================+ 00337 top + S - 4 -> | | GPR31 00338 + GPR SAVE AREA + 00339 .............. 00340 + + 00341 top + S - 19 * 4 -> | | GPR13 00342 +--------------------------+ 00343 | | 00344 + ALIGNMEBNT PAD + 00345 .............. 00346 + (if needed) + 00347 | | 00348 +--------------------------+ 00349 | | 00350 + + 00351 | | 00352 + PARAMETER AREA + 00353 | | 00354 + + 00355 top + 24 -> | | 00356 +--------------------------+ 00357 | | 00358 + LINKAGE AREA + 00359 top -> | | 00360 +==========================+ 00361 */ 00362 00363 #define QUICKTHREADS_BLOCKI_FRAME_SIZE \ 00364 PPC_ROUND_STACK(PPC_LINKAGE_AREA+PPC_PARAM_AREA(4)+PPC_GPR_SAVE_AREA) 00365 00366 /* Offset to the base of the GPR save area. Save from GPR13 to GPR31 00367 * increasing address. 00368 */ 00369 #define QUICKTHREADS_BLOCKI_GPR_SAVE(i) (QUICKTHREADS_BLOCKI_FRAME_SIZE-4+(i-31)*4) 00370 00371 00372 00373 /* Define the "qt_block" stack frame. Notice that since "qt_black" calls 00374 * "qt_blocki", GPR registers are saved into "qt_blocki" stack frame. 00375 * 00376 00377 top + S -> 00378 +==========================+ 00379 top + S - 8 -> | | FPR31 00380 + FPR SAVE AREA + 00381 .............. 00382 + + 00383 top + S - 18 * 8 -> | | FPR14 00384 +--------------------------+ 00385 | | 00386 + ALIGNMEBNT PAD + 00387 .............. 00388 + (if needed) + 00389 | | 00390 +--------------------------+ 00391 | | 00392 + + 00393 | | 00394 + PARAMETER AREA + 00395 | | 00396 + + 00397 top + 24 -> | | 00398 +--------------------------+ 00399 | | 00400 + LINKAGE AREA + 00401 top -> | | 00402 +==========================+ 00403 */ 00404 00405 #define QUICKTHREADS_BLOCK_FRAME_SIZE \ 00406 PPC_ROUND_STACK(PPC_LINKAGE_AREA+PPC_PARAM_AREA(4)+PPC_FPR_SAVE_AREA) 00407 00408 /* Offset to the location where registers are saved. 00409 */ 00410 #define QUICKTHREADS_BLOCK_FPR_SAVE(i) (QUICKTHREADS_BLOCK_FRAME_SIZE-8+(i-31)*8) 00411 00412 00413 /* Define the "qt_start" frame size. It consists just of the linkage area and 00414 * the parameter area. 00415 * 00416 00417 +==========================+ 00418 | | 00419 + ALIGNMEBNT PAD + 00420 .............. 00421 + (if needed) + 00422 | | 00423 +--------------------------+ 00424 | | only par 00425 + + 00426 | | userf par 00427 + PARAMETER AREA + 00428 | | t par 00429 + + 00430 top + 24 -> | | u par 00431 +--------------------------+ 00432 | | 00433 + LINKAGE AREA + 00434 top -> | | 00435 +==========================+ 00436 00437 */ 00438 #define QUICKTHREADS_START_FRAME_SIZE PPC_ROUND_STACK(PPC_LINKAGE_AREA+PPC_PARAM_AREA(4)) 00439 00440 00441 00442 /* Define the "qt_vstart" frame. It consists of the linkage area, the fix parameter 00443 * area, the variant argument list and a local variable area used in "qt_vstart" 00444 * implementation. 00445 * 00446 00447 backchain -> 00448 +==========================+ 00449 backchain - 4 -> | | 00450 + LOCAL VARIABLES AREA + 00451 .............. 00452 + + 00453 | | 00454 +--------------------------+ 00455 | | 00456 + ALIGNMEBNT PAD + 00457 .............. 00458 + (if needed) + 00459 | | 00460 +--------------------------+ 00461 | | arg(n) 00462 + + 00463 | | 00464 + VARIABLE ARGUMENT LIST + 00465 .............. 00466 + for userf call + 00467 | | arg(1) 00468 + + 00469 top + 24 + 16 -> | | arg(0) 00470 +--------------------------+ 00471 | | cleanup par 00472 + + 00473 | | userf par 00474 + PARAMETER AREA + 00475 | | startup par 00476 + + 00477 top + 24 -> | | t par 00478 +--------------------------+ 00479 | | 00480 + LINKAGE AREA + 00481 top -> | | 00482 +==========================+ 00483 00484 */ 00485 #define QUICKTHREADS_VARGS_LOCAL_AREA (4*4) /* local variable area */ 00486 00487 /* The offset the stack will be moved back before to call "userf(...)". 00488 * The linckage area must be moved to be adiacent to the part of the variant 00489 * argument list that is in the stack. 00490 */ 00491 #define QUICKTHREADS_VARGS_BKOFF PPC_PARAM_AREA(4) 00492 00493 #define QUICKTHREADS_VSTART_FRAME_SIZE(varbytes) \ 00494 PPC_ROUND_STACK(PPC_LINKAGE_AREA+PPC_PARAM_AREA(4)+(varbytes)+ \ 00495 QUICKTHREADS_VARGS_LOCAL_AREA) 00496 00497 /* Offset to the base of the varian argument list */ 00498 #define QUICKTHREADS_VSTART_LIST_BASE (PPC_LINKAGE_AREA+PPC_PARAM_AREA(4)) 00499 00500 00501 /* Notice that qt_start and qt_vstart have no parameters, actually their 00502 * parameters are written in their stack frame during thread initialization 00503 */ 00504 extern void qt_start(void); 00505 extern void qt_vstart(void); 00506 00507 00508 00509 /* Offset (in words) of the location where the block routine saves its return 00510 * address (i.e. LR). SP points the top of the block routine stack and, 00511 * following ppc calling conventions, the return address is saved in the 00512 * previous (caller's) stack frame. 00513 */ 00514 #define QUICKTHREADS_RETURN_INDEX ((QUICKTHREADS_BLOCKI_FRAME_SIZE+PPC_LR_SAVE)/sizeof(PPC_W)) 00515 00516 /* static variable used to get the stack bottom in "VARGS" initialization */ 00517 // static void *qt_sp_bottom_save; 00518 00519 #define QUICKTHREADS_ARG_INDEX(i) ((QUICKTHREADS_BLOCKI_FRAME_SIZE+PPC_PAR(i))/sizeof(PPC_W)) 00520 00521 /***************************************************************************** 00522 00523 QuickThreads needed definitions 00524 00525 *****************************************************************************/ 00526 00527 00528 #define QUICKTHREADS_GROW_DOWN 00529 #define QUICKTHREADS_STKALIGN PPC_STACK_INCR 00530 typedef PPC_W qt_word_t; 00531 00532 00533 /* This macro is used by "QUICKTHREADS_ARGS" to initialize a single argument thread. 00534 * - set "qt_start" as the "qt_block" or "qt_blocki" return address; 00535 * - set the top of the stack backchain; 00536 * - set the next backchain (not needed, but just to be "clean"). 00537 */ 00538 #define QUICKTHREADS_ARGS_MD(sp) \ 00539 (QUICKTHREADS_SPUT (sp, QUICKTHREADS_RETURN_INDEX, qt_start), \ 00540 QUICKTHREADS_SPUT (sp, 0, sp+QUICKTHREADS_BLOCKI_FRAME_SIZE), \ 00541 QUICKTHREADS_SPUT (sp, QUICKTHREADS_BLOCKI_FRAME_SIZE/sizeof(PPC_W), \ 00542 sp+QUICKTHREADS_BLOCKI_FRAME_SIZE+QUICKTHREADS_START_FRAME_SIZE)) 00543 00544 00545 /* This macro is used by "QUICKTHREADS_VARGS" to initialize a variant argument thread. 00546 * It returns the pointer to the top of the argument list. 00547 * We also use it to get the stack bottom via a static variable. This is a bit 00548 * "dirty", it could be better to do it in "qt_vargs", but we don't want change 00549 * anything out of this file. 00550 * We need the stack bottom to allocate a local variable area used by 00551 * "qt_vstart". 00552 */ 00553 #define QUICKTHREADS_VARGS_MD0(sp, varbytes) \ 00554 ((qt_sp_bottom_save = sp), \ 00555 ((qt_t *)(((char *)(sp)) - \ 00556 (QUICKTHREADS_VSTART_FRAME_SIZE(varbytes)-QUICKTHREADS_VSTART_LIST_BASE)))) 00557 00558 00559 /* This macro is used by "QUICKTHREADS_VARGS" to initialize a variant argument thread. 00560 * - set "qt_start" as the "qt_block" or "qt_blocki" return address; 00561 * - set the top of the stackback chain; 00562 * - set the next backchain (it points the stack botton). 00563 */ 00564 #define QUICKTHREADS_VARGS_MD1(sp) \ 00565 (QUICKTHREADS_SPUT (sp, QUICKTHREADS_RETURN_INDEX, qt_vstart), \ 00566 QUICKTHREADS_SPUT (sp, 0, sp+QUICKTHREADS_BLOCKI_FRAME_SIZE), \ 00567 QUICKTHREADS_SPUT (sp, (QUICKTHREADS_BLOCKI_FRAME_SIZE)/sizeof(PPC_W), \ 00568 qt_sp_bottom_save)) 00569 00570 00571 /* Activate "qt_vargs" as the initialization routine for the variant 00572 * argument threads 00573 */ 00574 #define QUICKTHREADS_VARGS_DEFAULT 00575 00576 /* Override "qt_vargs" with "qt_vargs_stdarg". 00577 * On LinuxPPC "qt_vargs" doesn't work, "qt_vargs_stdarg" uses a more 00578 * standard way to retrieve arguments from the variant list. 00579 */ 00580 #define QUICKTHREADS_VARGS(sp, nbytes, vargs, pt, startup, vuserf, cleanup) \ 00581 ((qt_t *)qt_vargs_stdarg (sp, nbytes, vargs, pt, startup, vuserf, cleanup)) 00582 00583 00584 /* This macro is used by "QUICKTHREADS_ADJ(sp)" to get the stack top form the stack 00585 * bottom during a single argument thread initialization. 00586 * It is the space we need to allocate for a single argument thread: the stack 00587 * frame for the block routine ("qt_block" or "qt_blocki") and for "qt_start". 00588 */ 00589 #define QUICKTHREADS_STKBASE \ 00590 (QUICKTHREADS_BLOCKI_FRAME_SIZE+QUICKTHREADS_START_FRAME_SIZE) 00591 00592 /* This macro is used by "QUICKTHREADS_VADJ(sp)" to get the stack top from the base 00593 * of the variant argument list during a variant argument thread initialization. 00594 */ 00595 #define QUICKTHREADS_VSTKBASE (QUICKTHREADS_BLOCKI_FRAME_SIZE+QUICKTHREADS_VSTART_LIST_BASE) 00596 00597 /* The *index* (positive offset) of where to put each value. */ 00598 00599 #define QUICKTHREADS_ARGU_INDEX QUICKTHREADS_ARG_INDEX(0) 00600 #define QUICKTHREADS_ARGT_INDEX QUICKTHREADS_ARG_INDEX(1) 00601 #define QUICKTHREADS_USER_INDEX QUICKTHREADS_ARG_INDEX(2) 00602 #define QUICKTHREADS_ONLY_INDEX QUICKTHREADS_ARG_INDEX(3) 00603 00604 00605 #define QUICKTHREADS_VARGT_INDEX QUICKTHREADS_ARG_INDEX(0) 00606 #define QUICKTHREADS_VSTARTUP_INDEX QUICKTHREADS_ARG_INDEX(1) 00607 #define QUICKTHREADS_VUSERF_INDEX QUICKTHREADS_ARG_INDEX(2) 00608 #define QUICKTHREADS_VCLEANUP_INDEX QUICKTHREADS_ARG_INDEX(3) 00609 00610 #endif /* ndef QUICKTHREADS_POWERPC_H */ 00611
1.2.18