1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 /** 26 * \file glapi_entrypoint.c 27 * 28 * Arch-specific code for manipulating GL API entrypoints (dispatch stubs). 29 */ 30 31 32 #include "glapi/glapi_priv.h" 33 #include "mapi/u_execmem.h" 34 35 36 #ifdef USE_X86_ASM 37 38 #if defined( GLX_USE_TLS ) 39 extern GLubyte gl_dispatch_functions_start[]; 40 extern GLubyte gl_dispatch_functions_end[]; 41 #else 42 extern const GLubyte gl_dispatch_functions_start[]; 43 #endif 44 45 #endif /* USE_X86_ASM */ 46 47 48 #if defined(DISPATCH_FUNCTION_SIZE) 49 50 _glapi_proc 51 get_entrypoint_address(unsigned int functionOffset) 52 { 53 return (_glapi_proc) (gl_dispatch_functions_start 54 + (DISPATCH_FUNCTION_SIZE * functionOffset)); 55 } 56 57 #endif 58 59 60 #if defined(USE_X86_ASM) 61 62 /** 63 * Perform platform-specific GL API entry-point fixups. 64 */ 65 static void 66 init_glapi_relocs( void ) 67 { 68 #if defined(GLX_USE_TLS) && !defined(GLX_X86_READONLY_TEXT) 69 extern unsigned long _x86_get_dispatch(void); 70 char run_time_patch[] = { 71 0x65, 0xa1, 0, 0, 0, 0 /* movl %gs:0,%eax */ 72 }; 73 GLuint *offset = (GLuint *) &run_time_patch[2]; /* 32-bits for x86/32 */ 74 const GLubyte * const get_disp = (const GLubyte *) run_time_patch; 75 GLubyte * curr_func = (GLubyte *) gl_dispatch_functions_start; 76 77 *offset = _x86_get_dispatch(); 78 while ( curr_func != (GLubyte *) gl_dispatch_functions_end ) { 79 (void) memcpy( curr_func, get_disp, sizeof(run_time_patch)); 80 curr_func += DISPATCH_FUNCTION_SIZE; 81 } 82 #endif 83 } 84 85 86 /** 87 * Generate a dispatch function (entrypoint) which jumps through 88 * the given slot number (offset) in the current dispatch table. 89 * We need assembly language in order to accomplish this. 90 */ 91 _glapi_proc 92 generate_entrypoint(unsigned int functionOffset) 93 { 94 /* 32 is chosen as something of a magic offset. For x86, the dispatch 95 * at offset 32 is the first one where the offset in the 96 * "jmp OFFSET*4(%eax)" can't be encoded in a single byte. 97 */ 98 const GLubyte * const template_func = gl_dispatch_functions_start 99 + (DISPATCH_FUNCTION_SIZE * 32); 100 GLubyte * const code = (GLubyte *) u_execmem_alloc(DISPATCH_FUNCTION_SIZE); 101 102 103 if ( code != NULL ) { 104 (void) memcpy(code, template_func, DISPATCH_FUNCTION_SIZE); 105 fill_in_entrypoint_offset( (_glapi_proc) code, functionOffset ); 106 } 107 108 return (_glapi_proc) code; 109 } 110 111 112 /** 113 * This function inserts a new dispatch offset into the assembly language 114 * stub that was generated with the preceeding function. 115 */ 116 void 117 fill_in_entrypoint_offset(_glapi_proc entrypoint, unsigned int offset) 118 { 119 GLubyte * const code = (GLubyte *) entrypoint; 120 121 #if defined(GLX_USE_TLS) 122 *((unsigned int *)(code + 8)) = 4 * offset; 123 #elif defined(THREADS) 124 *((unsigned int *)(code + 11)) = 4 * offset; 125 *((unsigned int *)(code + 22)) = 4 * offset; 126 #else 127 *((unsigned int *)(code + 7)) = 4 * offset; 128 #endif 129 } 130 131 132 #elif defined(USE_SPARC_ASM) 133 134 extern void __glapi_sparc_icache_flush(unsigned int *); 135 136 static void 137 init_glapi_relocs( void ) 138 { 139 #if defined(HAVE_PTHREAD) || defined(GLX_USE_TLS) 140 static const unsigned int template[] = { 141 #ifdef GLX_USE_TLS 142 0x05000000, /* sethi %hi(_glapi_tls_Dispatch), %g2 */ 143 0x8730e00a, /* srl %g3, 10, %g3 */ 144 0x8410a000, /* or %g2, %lo(_glapi_tls_Dispatch), %g2 */ 145 #ifdef __arch64__ 146 0xc259c002, /* ldx [%g7 + %g2], %g1 */ 147 0xc2584003, /* ldx [%g1 + %g3], %g1 */ 148 #else 149 0xc201c002, /* ld [%g7 + %g2], %g1 */ 150 0xc2004003, /* ld [%g1 + %g3], %g1 */ 151 #endif 152 0x81c04000, /* jmp %g1 */ 153 0x01000000, /* nop */ 154 #else 155 #ifdef __arch64__ 156 0x03000000, /* 64-bit 0x00 --> sethi %hh(_glapi_Dispatch), %g1 */ 157 0x05000000, /* 64-bit 0x04 --> sethi %lm(_glapi_Dispatch), %g2 */ 158 0x82106000, /* 64-bit 0x08 --> or %g1, %hm(_glapi_Dispatch), %g1 */ 159 0x8730e00a, /* 64-bit 0x0c --> srl %g3, 10, %g3 */ 160 0x83287020, /* 64-bit 0x10 --> sllx %g1, 32, %g1 */ 161 0x82004002, /* 64-bit 0x14 --> add %g1, %g2, %g1 */ 162 0xc2586000, /* 64-bit 0x18 --> ldx [%g1 + %lo(_glapi_Dispatch)], %g1 */ 163 #else 164 0x03000000, /* 32-bit 0x00 --> sethi %hi(_glapi_Dispatch), %g1 */ 165 0x8730e00a, /* 32-bit 0x04 --> srl %g3, 10, %g3 */ 166 0xc2006000, /* 32-bit 0x08 --> ld [%g1 + %lo(_glapi_Dispatch)], %g1 */ 167 #endif 168 0x80a06000, /* --> cmp %g1, 0 */ 169 0x02800005, /* --> be +4*5 */ 170 0x01000000, /* --> nop */ 171 #ifdef __arch64__ 172 0xc2584003, /* 64-bit --> ldx [%g1 + %g3], %g1 */ 173 #else 174 0xc2004003, /* 32-bit --> ld [%g1 + %g3], %g1 */ 175 #endif 176 0x81c04000, /* --> jmp %g1 */ 177 0x01000000, /* --> nop */ 178 #ifdef __arch64__ 179 0x9de3bf80, /* 64-bit --> save %sp, -128, %sp */ 180 #else 181 0x9de3bfc0, /* 32-bit --> save %sp, -64, %sp */ 182 #endif 183 0xa0100003, /* --> mov %g3, %l0 */ 184 0x40000000, /* --> call _glapi_get_dispatch */ 185 0x01000000, /* --> nop */ 186 0x82100008, /* --> mov %o0, %g1 */ 187 0x86100010, /* --> mov %l0, %g3 */ 188 0x10bffff7, /* --> ba -4*9 */ 189 0x81e80000, /* --> restore */ 190 #endif 191 }; 192 #ifdef GLX_USE_TLS 193 extern unsigned int __glapi_sparc_tls_stub; 194 extern unsigned long __glapi_sparc_get_dispatch(void); 195 unsigned int *code = &__glapi_sparc_tls_stub; 196 unsigned long dispatch = __glapi_sparc_get_dispatch(); 197 #else 198 extern unsigned int __glapi_sparc_pthread_stub; 199 unsigned int *code = &__glapi_sparc_pthread_stub; 200 unsigned long dispatch = (unsigned long) &_glapi_Dispatch; 201 unsigned long call_dest = (unsigned long ) &_glapi_get_dispatch; 202 int idx; 203 #endif 204 205 #ifdef GLX_USE_TLS 206 code[0] = template[0] | (dispatch >> 10); 207 code[1] = template[1]; 208 __glapi_sparc_icache_flush(&code[0]); 209 code[2] = template[2] | (dispatch & 0x3ff); 210 code[3] = template[3]; 211 __glapi_sparc_icache_flush(&code[2]); 212 code[4] = template[4]; 213 code[5] = template[5]; 214 __glapi_sparc_icache_flush(&code[4]); 215 code[6] = template[6]; 216 __glapi_sparc_icache_flush(&code[6]); 217 #else 218 #if defined(__arch64__) 219 code[0] = template[0] | (dispatch >> (32 + 10)); 220 code[1] = template[1] | ((dispatch & 0xffffffff) >> 10); 221 __glapi_sparc_icache_flush(&code[0]); 222 code[2] = template[2] | ((dispatch >> 32) & 0x3ff); 223 code[3] = template[3]; 224 __glapi_sparc_icache_flush(&code[2]); 225 code[4] = template[4]; 226 code[5] = template[5]; 227 __glapi_sparc_icache_flush(&code[4]); 228 code[6] = template[6] | (dispatch & 0x3ff); 229 idx = 7; 230 #else 231 code[0] = template[0] | (dispatch >> 10); 232 code[1] = template[1]; 233 __glapi_sparc_icache_flush(&code[0]); 234 code[2] = template[2] | (dispatch & 0x3ff); 235 idx = 3; 236 #endif 237 code[idx + 0] = template[idx + 0]; 238 __glapi_sparc_icache_flush(&code[idx - 1]); 239 code[idx + 1] = template[idx + 1]; 240 code[idx + 2] = template[idx + 2]; 241 __glapi_sparc_icache_flush(&code[idx + 1]); 242 code[idx + 3] = template[idx + 3]; 243 code[idx + 4] = template[idx + 4]; 244 __glapi_sparc_icache_flush(&code[idx + 3]); 245 code[idx + 5] = template[idx + 5]; 246 code[idx + 6] = template[idx + 6]; 247 __glapi_sparc_icache_flush(&code[idx + 5]); 248 code[idx + 7] = template[idx + 7]; 249 code[idx + 8] = template[idx + 8] | 250 (((call_dest - ((unsigned long) &code[idx + 8])) 251 >> 2) & 0x3fffffff); 252 __glapi_sparc_icache_flush(&code[idx + 7]); 253 code[idx + 9] = template[idx + 9]; 254 code[idx + 10] = template[idx + 10]; 255 __glapi_sparc_icache_flush(&code[idx + 9]); 256 code[idx + 11] = template[idx + 11]; 257 code[idx + 12] = template[idx + 12]; 258 __glapi_sparc_icache_flush(&code[idx + 11]); 259 code[idx + 13] = template[idx + 13]; 260 __glapi_sparc_icache_flush(&code[idx + 13]); 261 #endif 262 #endif 263 } 264 265 266 _glapi_proc 267 generate_entrypoint(GLuint functionOffset) 268 { 269 #if defined(HAVE_PTHREAD) || defined(GLX_USE_TLS) 270 static const unsigned int template[] = { 271 0x07000000, /* sethi %hi(0), %g3 */ 272 0x8210000f, /* mov %o7, %g1 */ 273 0x40000000, /* call */ 274 0x9e100001, /* mov %g1, %o7 */ 275 }; 276 #ifdef GLX_USE_TLS 277 extern unsigned int __glapi_sparc_tls_stub; 278 unsigned long call_dest = (unsigned long ) &__glapi_sparc_tls_stub; 279 #else 280 extern unsigned int __glapi_sparc_pthread_stub; 281 unsigned long call_dest = (unsigned long ) &__glapi_sparc_pthread_stub; 282 #endif 283 unsigned int *code = (unsigned int *) u_execmem_alloc(sizeof(template)); 284 if (code) { 285 code[0] = template[0] | (functionOffset & 0x3fffff); 286 code[1] = template[1]; 287 __glapi_sparc_icache_flush(&code[0]); 288 code[2] = template[2] | 289 (((call_dest - ((unsigned long) &code[2])) 290 >> 2) & 0x3fffffff); 291 code[3] = template[3]; 292 __glapi_sparc_icache_flush(&code[2]); 293 } 294 return (_glapi_proc) code; 295 #endif 296 } 297 298 299 void 300 fill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset) 301 { 302 unsigned int *code = (unsigned int *) entrypoint; 303 304 code[0] &= ~0x3fffff; 305 code[0] |= (offset * sizeof(void *)) & 0x3fffff; 306 __glapi_sparc_icache_flush(&code[0]); 307 } 308 309 310 #else /* USE_*_ASM */ 311 312 static void 313 init_glapi_relocs( void ) 314 { 315 } 316 317 318 _glapi_proc 319 generate_entrypoint(GLuint functionOffset) 320 { 321 (void) functionOffset; 322 return NULL; 323 } 324 325 326 void 327 fill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset) 328 { 329 /* an unimplemented architecture */ 330 (void) entrypoint; 331 (void) offset; 332 } 333 334 #endif /* USE_*_ASM */ 335 336 337 void 338 init_glapi_relocs_once( void ) 339 { 340 #if defined(HAVE_PTHREAD) || defined(GLX_USE_TLS) 341 static pthread_once_t once_control = PTHREAD_ONCE_INIT; 342 pthread_once( & once_control, init_glapi_relocs ); 343 #endif 344 } 345