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