1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
9bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
11bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
14bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
23bf215546Sopenharmony_ci */
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci/**
26bf215546Sopenharmony_ci * \file glapi_entrypoint.c
27bf215546Sopenharmony_ci *
28bf215546Sopenharmony_ci * Arch-specific code for manipulating GL API entrypoints (dispatch stubs).
29bf215546Sopenharmony_ci */
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include <string.h>
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci#include "c11/threads.h"
35bf215546Sopenharmony_ci#include "glapi/glapi_priv.h"
36bf215546Sopenharmony_ci#include "u_execmem.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#ifdef USE_X86_ASM
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ciextern       GLubyte gl_dispatch_functions_start[];
42bf215546Sopenharmony_ciextern       GLubyte gl_dispatch_functions_end[];
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci#endif /* USE_X86_ASM */
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_ci#if defined(DISPATCH_FUNCTION_SIZE)
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci_glapi_proc
50bf215546Sopenharmony_ciget_entrypoint_address(unsigned int functionOffset)
51bf215546Sopenharmony_ci{
52bf215546Sopenharmony_ci   return (_glapi_proc) (gl_dispatch_functions_start
53bf215546Sopenharmony_ci                         + (DISPATCH_FUNCTION_SIZE * functionOffset));
54bf215546Sopenharmony_ci}
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci#endif
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci#if defined(USE_X86_ASM)
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci/**
62bf215546Sopenharmony_ci * Perform platform-specific GL API entry-point fixups.
63bf215546Sopenharmony_ci */
64bf215546Sopenharmony_cistatic void
65bf215546Sopenharmony_ciinit_glapi_relocs( void )
66bf215546Sopenharmony_ci{
67bf215546Sopenharmony_ci#if !defined(GLX_X86_READONLY_TEXT)
68bf215546Sopenharmony_ci    extern unsigned long _x86_get_dispatch(void);
69bf215546Sopenharmony_ci    char run_time_patch[] = {
70bf215546Sopenharmony_ci       0x65, 0xa1, 0, 0, 0, 0 /* movl %gs:0,%eax */
71bf215546Sopenharmony_ci    };
72bf215546Sopenharmony_ci    GLuint *offset = (GLuint *) &run_time_patch[2]; /* 32-bits for x86/32 */
73bf215546Sopenharmony_ci    const GLubyte * const get_disp = (const GLubyte *) run_time_patch;
74bf215546Sopenharmony_ci    GLubyte * curr_func = (GLubyte *) gl_dispatch_functions_start;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci    *offset = _x86_get_dispatch();
77bf215546Sopenharmony_ci    while ( curr_func != (GLubyte *) gl_dispatch_functions_end ) {
78bf215546Sopenharmony_ci	(void) memcpy( curr_func, get_disp, sizeof(run_time_patch));
79bf215546Sopenharmony_ci	curr_func += DISPATCH_FUNCTION_SIZE;
80bf215546Sopenharmony_ci    }
81bf215546Sopenharmony_ci#endif
82bf215546Sopenharmony_ci}
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci/**
86bf215546Sopenharmony_ci * Generate a dispatch function (entrypoint) which jumps through
87bf215546Sopenharmony_ci * the given slot number (offset) in the current dispatch table.
88bf215546Sopenharmony_ci * We need assembly language in order to accomplish this.
89bf215546Sopenharmony_ci */
90bf215546Sopenharmony_ci_glapi_proc
91bf215546Sopenharmony_cigenerate_entrypoint(unsigned int functionOffset)
92bf215546Sopenharmony_ci{
93bf215546Sopenharmony_ci   /* 32 is chosen as something of a magic offset.  For x86, the dispatch
94bf215546Sopenharmony_ci    * at offset 32 is the first one where the offset in the
95bf215546Sopenharmony_ci    * "jmp OFFSET*4(%eax)" can't be encoded in a single byte.
96bf215546Sopenharmony_ci    */
97bf215546Sopenharmony_ci   const GLubyte * const template_func = gl_dispatch_functions_start
98bf215546Sopenharmony_ci     + (DISPATCH_FUNCTION_SIZE * 32);
99bf215546Sopenharmony_ci   GLubyte * const code = (GLubyte *) u_execmem_alloc(DISPATCH_FUNCTION_SIZE);
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci   if ( code != NULL ) {
103bf215546Sopenharmony_ci      (void) memcpy(code, template_func, DISPATCH_FUNCTION_SIZE);
104bf215546Sopenharmony_ci      fill_in_entrypoint_offset( (_glapi_proc) code, functionOffset );
105bf215546Sopenharmony_ci   }
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   return (_glapi_proc) code;
108bf215546Sopenharmony_ci}
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci/**
112bf215546Sopenharmony_ci * This function inserts a new dispatch offset into the assembly language
113bf215546Sopenharmony_ci * stub that was generated with the preceeding function.
114bf215546Sopenharmony_ci */
115bf215546Sopenharmony_civoid
116bf215546Sopenharmony_cifill_in_entrypoint_offset(_glapi_proc entrypoint, unsigned int offset)
117bf215546Sopenharmony_ci{
118bf215546Sopenharmony_ci   GLubyte * const code = (GLubyte *) entrypoint;
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   *((unsigned int *)(code +  8)) = 4 * offset;
121bf215546Sopenharmony_ci}
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci#elif defined(USE_SPARC_ASM)
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_ciextern void __glapi_sparc_icache_flush(unsigned int *);
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_cistatic void
129bf215546Sopenharmony_ciinit_glapi_relocs( void )
130bf215546Sopenharmony_ci{
131bf215546Sopenharmony_ci    static const unsigned int template[] = {
132bf215546Sopenharmony_ci	0x05000000, /* sethi %hi(_glapi_tls_Dispatch), %g2 */
133bf215546Sopenharmony_ci	0x8730e00a, /* srl %g3, 10, %g3 */
134bf215546Sopenharmony_ci	0x8410a000, /* or %g2, %lo(_glapi_tls_Dispatch), %g2 */
135bf215546Sopenharmony_ci#ifdef __arch64__
136bf215546Sopenharmony_ci	0xc259c002, /* ldx [%g7 + %g2], %g1 */
137bf215546Sopenharmony_ci	0xc2584003, /* ldx [%g1 + %g3], %g1 */
138bf215546Sopenharmony_ci#else
139bf215546Sopenharmony_ci	0xc201c002, /* ld [%g7 + %g2], %g1 */
140bf215546Sopenharmony_ci	0xc2004003, /* ld [%g1 + %g3], %g1 */
141bf215546Sopenharmony_ci#endif
142bf215546Sopenharmony_ci	0x81c04000, /* jmp %g1 */
143bf215546Sopenharmony_ci	0x01000000, /* nop  */
144bf215546Sopenharmony_ci    };
145bf215546Sopenharmony_ci    extern unsigned int __glapi_sparc_tls_stub;
146bf215546Sopenharmony_ci    extern unsigned long __glapi_sparc_get_dispatch(void);
147bf215546Sopenharmony_ci    unsigned int *code = &__glapi_sparc_tls_stub;
148bf215546Sopenharmony_ci    unsigned long dispatch = __glapi_sparc_get_dispatch();
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci    code[0] = template[0] | (dispatch >> 10);
151bf215546Sopenharmony_ci    code[1] = template[1];
152bf215546Sopenharmony_ci    __glapi_sparc_icache_flush(&code[0]);
153bf215546Sopenharmony_ci    code[2] = template[2] | (dispatch & 0x3ff);
154bf215546Sopenharmony_ci    code[3] = template[3];
155bf215546Sopenharmony_ci    __glapi_sparc_icache_flush(&code[2]);
156bf215546Sopenharmony_ci    code[4] = template[4];
157bf215546Sopenharmony_ci    code[5] = template[5];
158bf215546Sopenharmony_ci    __glapi_sparc_icache_flush(&code[4]);
159bf215546Sopenharmony_ci    code[6] = template[6];
160bf215546Sopenharmony_ci    __glapi_sparc_icache_flush(&code[6]);
161bf215546Sopenharmony_ci}
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci_glapi_proc
165bf215546Sopenharmony_cigenerate_entrypoint(GLuint functionOffset)
166bf215546Sopenharmony_ci{
167bf215546Sopenharmony_ci   static const unsigned int template[] = {
168bf215546Sopenharmony_ci      0x07000000, /* sethi %hi(0), %g3 */
169bf215546Sopenharmony_ci      0x8210000f, /* mov  %o7, %g1 */
170bf215546Sopenharmony_ci      0x40000000, /* call */
171bf215546Sopenharmony_ci      0x9e100001, /* mov  %g1, %o7 */
172bf215546Sopenharmony_ci   };
173bf215546Sopenharmony_ci   extern unsigned int __glapi_sparc_tls_stub;
174bf215546Sopenharmony_ci   unsigned long call_dest = (unsigned long ) &__glapi_sparc_tls_stub;
175bf215546Sopenharmony_ci   unsigned int *code = (unsigned int *) u_execmem_alloc(sizeof(template));
176bf215546Sopenharmony_ci   if (code) {
177bf215546Sopenharmony_ci      code[0] = template[0] | (functionOffset & 0x3fffff);
178bf215546Sopenharmony_ci      code[1] = template[1];
179bf215546Sopenharmony_ci      __glapi_sparc_icache_flush(&code[0]);
180bf215546Sopenharmony_ci      code[2] = template[2] |
181bf215546Sopenharmony_ci         (((call_dest - ((unsigned long) &code[2]))
182bf215546Sopenharmony_ci	   >> 2) & 0x3fffffff);
183bf215546Sopenharmony_ci      code[3] = template[3];
184bf215546Sopenharmony_ci      __glapi_sparc_icache_flush(&code[2]);
185bf215546Sopenharmony_ci   }
186bf215546Sopenharmony_ci   return (_glapi_proc) code;
187bf215546Sopenharmony_ci}
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_civoid
191bf215546Sopenharmony_cifill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset)
192bf215546Sopenharmony_ci{
193bf215546Sopenharmony_ci   unsigned int *code = (unsigned int *) entrypoint;
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci   code[0] &= ~0x3fffff;
196bf215546Sopenharmony_ci   code[0] |= (offset * sizeof(void *)) & 0x3fffff;
197bf215546Sopenharmony_ci   __glapi_sparc_icache_flush(&code[0]);
198bf215546Sopenharmony_ci}
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci#else /* USE_*_ASM */
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_cistatic void
204bf215546Sopenharmony_ciinit_glapi_relocs( void )
205bf215546Sopenharmony_ci{
206bf215546Sopenharmony_ci}
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_ci_glapi_proc
210bf215546Sopenharmony_cigenerate_entrypoint(GLuint functionOffset)
211bf215546Sopenharmony_ci{
212bf215546Sopenharmony_ci   (void) functionOffset;
213bf215546Sopenharmony_ci   return NULL;
214bf215546Sopenharmony_ci}
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_civoid
218bf215546Sopenharmony_cifill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset)
219bf215546Sopenharmony_ci{
220bf215546Sopenharmony_ci   /* an unimplemented architecture */
221bf215546Sopenharmony_ci   (void) entrypoint;
222bf215546Sopenharmony_ci   (void) offset;
223bf215546Sopenharmony_ci}
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci#endif /* USE_*_ASM */
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_civoid
229bf215546Sopenharmony_ciinit_glapi_relocs_once( void )
230bf215546Sopenharmony_ci{
231bf215546Sopenharmony_ci   static once_flag flag = ONCE_FLAG_INIT;
232bf215546Sopenharmony_ci   call_once(&flag, init_glapi_relocs);
233bf215546Sopenharmony_ci}
234