[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / procMgr / hlos / knl / loaders / Elf / Qnx / dlw_client / dlw_dsbt.c
1 /*
2 * dlw_dsbt.c
3 *
4 * RIDL implementation of client functions required by dynamic loader API
5 * to support the Dynamic Static Base Table (DSBT) model.
6 * Please see list of client-required API functions in dload_api.h.
7 *
8 * This version of RIDL is expected to run on the DSP. It uses RTS
9 * functions for file I/O and memory management (both host and target
10 * memory).
11 *
12 * A loader that runs on a GPP for the purposes of loading C6x code onto a
13 * DSP will likely need to re-write all of the functions contained in this
14 * module.
15 *
16 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
17 *
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 *
23 * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 *
26 * Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the
29 * distribution.
30 *
31 * Neither the name of Texas Instruments Incorporated nor the names of
32 * its contributors may be used to endorse or promote products derived
33 * from this software without specific prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 *
47 */
49 #include "Queue.h"
50 #include "ArrayList.h"
51 #include "dload_api.h"
52 #include "dload.h" // Needed for LOADER_DEBUG def.
53 #include <string.h>
54 #include "dlw_dsbt.h"
55 #undef LOADER_DEBUG
56 #define LOADER_DEBUG 1
58 /*****************************************************************************/
59 /* DSBT_index_request_queue - This is a holding area for DSBT index requests */
60 /* while allocation and relocation of symbols is in progress for the top- */
61 /* level module and all of its dependents. Items will be pulled off the */
62 /* queue when we are ready to make actual DSBT index assignments in */
63 /* DLIF_assign_dsbt_indices(). */
64 /*****************************************************************************/
65 TYPE_QUEUE_IMPLEMENTATION(DSBT_Index_Request*, dsbt_index_request_ptr)
66 dsbt_index_request_ptr_Queue DSBT_index_request_queue;
68 /*****************************************************************************/
69 /* DSBT_Master - This is the master copy of the DSBT created by the client */
70 /* after all object modules have been allocated and their symbols have */
71 /* been relocated. */
72 /*****************************************************************************/
73 static int32_t DSBT_first_avail_index = 0;
74 Array_List DSBT_master;
76 #if LOADER_DEBUG
77 static void dump_master_dsbt(void);
78 #endif
80 /*****************************************************************************/
81 /* DLIF_register_dsbt_index_request() */
82 /* */
83 /* Register a request for a DSBT index from a dynamic executable or a */
84 /* dynamic library. An executable must make a specific request for the */
85 /* 0th slot in the DSBT. Dynamic libraries can make a specific index */
86 /* request or have the client assign an index on its behalf when the */
87 /* allocation and relocation of symbols is completed for a top-level */
88 /* load (load invoked by client's "load" command, for example). */
89 /* */
90 /* If a specific request is made for an index that has already been */
91 /* assigned or specifically requested by an earlier request, then an */
92 /* error will be emitted and the loader core should fail the load. */
93 /* */
94 /* The information provided with the request will include the requesting */
95 /* module's so_name and file handle, along with the index requested and */
96 /* the index assigned. */
97 /* */
98 /*---------------------------------------------------------------------------*/
99 /* */
100 /* It is assumed that AL_initialize has been called to set up the initial */
101 /* state of the client's model of the DSBT master. */
102 /* */
103 /*****************************************************************************/
104 BOOL DLIF_register_dsbt_index_request(DLOAD_HANDLE handle,
105 const char *requestor_name,
106 int32_t requestor_file_handle,
107 int32_t requested_dsbt_index)
108 {
109 DSBT_Index_Request *new_request = NULL;
111 /*------------------------------------------------------------------------*/
112 /* If requesting a specific DSBT index, check existing list of DSBT index */
113 /* requests to see if we've already seen a request for the specified */
114 /* DSBT index or if a request has already been received on behalf of the */
115 /* specified file. Both cases constitute an error and will abort the */
116 /* load. */
117 /*------------------------------------------------------------------------*/
118 if (requested_dsbt_index != DSBT_INDEX_INVALID)
119 {
120 dsbt_index_request_ptr_Queue_Node *ptr;
122 /*---------------------------------------------------------------------*/
123 /* If the client's master DSBT model already has content, then check */
124 /* to see if the requested DSBT index is available in the master DSBT. */
125 /*---------------------------------------------------------------------*/
126 if (AL_size(&DSBT_master) > requested_dsbt_index)
127 {
128 DSBT_Entry *client_dsbt = (DSBT_Entry *)(DSBT_master.buf);
129 if (client_dsbt[requested_dsbt_index].index_request != NULL)
130 {
131 DLIF_error(DLET_MISC,
132 "%s is requesting a DSBT index, %d, that is already "
133 "being used by an active module, %s",
134 requestor_name, requested_dsbt_index,
135 client_dsbt[requested_dsbt_index].index_request->name);
136 return FALSE;
137 }
138 }
140 for (ptr = DSBT_index_request_queue.front_ptr;
141 ptr != NULL; ptr = ptr->next_ptr)
142 {
143 DSBT_Index_Request *existing_request = ptr->value;
145 /*------------------------------------------------------------------*/
146 /* Have we seen a request for this file already? That would be a */
147 /* problem (likely internal). */
148 /*------------------------------------------------------------------*/
149 if (requestor_file_handle == existing_request->file_handle)
150 {
151 DLIF_error(DLET_MISC,
152 "A DSBT index has already been requested on behalf "
153 "of %s; cannot make a second DSBT index request for "
154 "the same module", existing_request->name);
155 return FALSE;
156 }
158 /*------------------------------------------------------------------*/
159 /* Have we seen a specific request for this DSBT index already? */
160 /* Report a conflict among specific requests in the same load. */
161 /*------------------------------------------------------------------*/
162 if (requested_dsbt_index == existing_request->requested_index)
163 {
164 DLIF_error(DLET_MISC,
165 "Requested DSBT index, %d, requested by %s has "
166 "already been requested by %s; load aborted",
167 requested_dsbt_index,
168 requestor_name,
169 existing_request->name);
170 return FALSE;
171 }
172 }
173 }
175 /*------------------------------------------------------------------------*/
176 /* If specified module is requesting a specific DSBT index that hasn't */
177 /* been encountered yet, or if it is making a general DSBT index request */
178 /* (to be assigned by the client when the current top-level load is */
179 /* sucessfully completed), make a DSBT index request entry for the */
180 /* current module and add it to the DSBT_Index_Request_List. */
181 /*------------------------------------------------------------------------*/
182 new_request = (DSBT_Index_Request *)DLIF_malloc(sizeof(DSBT_Index_Request));
183 if (NULL == new_request) {
184 DLIF_error(DLET_MISC,
185 "Could not allocate memory for DSBT index request");
186 return FALSE;
187 }
188 new_request->name = (char *)DLIF_malloc(strlen(requestor_name) + 1);
189 if (NULL == new_request->name) {
190 DLIF_free(new_request);
191 DLIF_error(DLET_MISC,
192 "Could not allocate memory for DSBT index request name");
193 return FALSE;
194 }
195 strcpy(new_request->name, requestor_name);
196 new_request->file_handle = requestor_file_handle;
198 new_request->dsbt_size = DLOAD_get_dsbt_size(handle, requestor_file_handle);
199 if (!DLOAD_get_dsbt_base(handle, requestor_file_handle, &new_request->dsbt_base))
200 {
201 DLIF_error(DLET_MISC,
202 "Could not resolve DSBT base value for %s",
203 requestor_name);
204 DLIF_free(new_request->name);
205 new_request->name = NULL;
206 DLIF_free(new_request);
207 new_request = NULL;
208 return FALSE;
209 }
211 if (!DLOAD_get_static_base(handle, requestor_file_handle, &new_request->static_base))
212 {
213 DLIF_error(DLET_MISC,
214 "Could not resolve static base value for %s",
215 requestor_name);
216 DLIF_free(new_request->name);
217 new_request->name = NULL;
218 DLIF_free(new_request);
219 new_request = NULL;
220 return FALSE;
221 }
223 new_request->requested_index = requested_dsbt_index;
224 new_request->assigned_index = DSBT_INDEX_INVALID;
226 dsbt_index_request_ptr_enqueue(&DSBT_index_request_queue, new_request);
228 return TRUE;
229 }
231 /*****************************************************************************/
232 /* new_DSBT_Entry() */
233 /* */
234 /* Construct a DSBT_Entry data structure and initialize it with specified */
235 /* DSBT_Index_Request pointer. */
236 /* */
237 /*****************************************************************************/
238 static void add_dsbt_entry(DSBT_Index_Request *request)
239 {
240 DSBT_Entry new_entry;
241 new_entry.index_request = request;
242 AL_append(&DSBT_master, &new_entry);
243 }
245 /*****************************************************************************/
246 /* assign_dsbt_entry() */
247 /* */
248 /* Assign an entry in the client's model of the DSBT master to the */
249 /* given DSBT index request. If the DSBT master needs to grow in order */
250 /* to accommodate the request, then it will do so. */
251 /* */
252 /*****************************************************************************/
253 static void assign_dsbt_entry(DSBT_Index_Request *request)
254 {
255 DSBT_Entry *client_dsbt = NULL;
257 /*------------------------------------------------------------------------*/
258 /* For a specific DSBT index request, assign the specified slot in the */
259 /* DSBT master to the given request. If we need to, we will grow the */
260 /* master DSBT to a size that can accommodate the specific request. */
261 /*------------------------------------------------------------------------*/
262 if (request->requested_index != DSBT_INDEX_INVALID)
263 {
264 while (AL_size(&DSBT_master) <= request->requested_index)
265 add_dsbt_entry(NULL);
267 client_dsbt = (DSBT_Entry *)(DSBT_master.buf);
268 client_dsbt[request->requested_index].index_request = request;
269 request->assigned_index = request->assigned_index;
270 }
272 /*------------------------------------------------------------------------*/
273 /* For a general DSBT index request, find the first available slot in the */
274 /* master DSBT and assign it to the request, or grow the master DSBT and */
275 /* assign the new slot to the request. */
276 /*------------------------------------------------------------------------*/
277 else
278 {
279 int i;
280 client_dsbt = (DSBT_Entry *)(DSBT_master.buf);
281 for (i = DSBT_first_avail_index; i < AL_size(&DSBT_master); i++)
282 {
283 if (client_dsbt[i].index_request == NULL)
284 {
285 client_dsbt[i].index_request = request;
286 break;
287 }
289 DSBT_first_avail_index++;
290 }
292 if (i == AL_size(&DSBT_master))
293 add_dsbt_entry(request);
295 request->assigned_index = i;
296 }
297 }
299 /*****************************************************************************/
300 /* DLIF_assign_dsbt_indices() */
301 /* */
302 /* When the core loader completes allocation of the top-level object */
303 /* being loaded and the allocation for all dependent files, this function */
304 /* is called to bind objects that have just been allocated to their DSBT */
305 /* index (as determined by the client). We will first honor any specific */
306 /* index requests that have been made. Then remaining DSBT entries will */
307 /* be assigned in the order that they were encountered during the load */
308 /* to each available slot in the master DSBT. */
309 /* */
310 /*---------------------------------------------------------------------------*/
311 /* */
312 /* It is assumed that AL_initialize has been called to set up the initial */
313 /* state of the client's model of the DSBT master. */
314 /* */
315 /* Error conditions should have been detected during registration of each */
316 /* DSBT index request. I don't think there are any error/warning */
317 /* situations that need to be handled within this function. */
318 /* */
319 /*****************************************************************************/
320 void DLIF_assign_dsbt_indices(void)
321 {
322 /*------------------------------------------------------------------------*/
323 /* Spin through DSBT index request queue, processing any specific DSBT */
324 /* index requests. If we need to grow the DSBT master model to handle a */
325 /* request, then do so. */
326 /*------------------------------------------------------------------------*/
327 dsbt_index_request_ptr_Queue_Node *ptr = DSBT_index_request_queue.front_ptr;
328 dsbt_index_request_ptr_Queue_Node *next_ptr = NULL;
329 DSBT_Index_Request *curr_req = NULL;
331 for (; ptr != NULL; ptr = next_ptr)
332 {
333 curr_req = ptr->value;
334 next_ptr = ptr->next_ptr;
336 if (curr_req->requested_index == DSBT_INDEX_INVALID) continue;
338 assign_dsbt_entry(curr_req);
339 dsbt_index_request_ptr_remove(&DSBT_index_request_queue, curr_req);
340 }
342 /*------------------------------------------------------------------------*/
343 /* Spin through what remains of the DSBT index request queue to process */
344 /* all general DSBT index requests. This time we can dequeue entries */
345 /* off the index request queue as we proceed. */
346 /*------------------------------------------------------------------------*/
347 curr_req = dsbt_index_request_ptr_dequeue(&DSBT_index_request_queue);
348 while (curr_req != NULL)
349 {
350 assign_dsbt_entry(curr_req);
351 curr_req = dsbt_index_request_ptr_dequeue(&DSBT_index_request_queue);
352 }
354 #if LOADER_DEBUG
355 if (debugging_on)
356 {
357 DLIF_trace("After completed assignment of DSBT indices ...\n");
358 dump_master_dsbt();
359 }
360 #endif
361 }
363 /*****************************************************************************/
364 /* DLIF_get_dsbt_index() */
365 /* */
366 /* Find specified file handle among the list of DSBT request entries. */
367 /* Then return the DSBT index that has been assigned to that file */
368 /* handle. Emit an error if the file handle is not found among the list */
369 /* of DSBT request entries or if a DSBT assignment has not been made */
370 /* for the specified file yet. */
371 /* */
372 /*****************************************************************************/
373 int32_t DLIF_get_dsbt_index(int32_t file_handle)
374 {
375 /*------------------------------------------------------------------------*/
376 /* Find specified file handle among client's model of the DSBT master. */
377 /*------------------------------------------------------------------------*/
378 int32_t i;
379 DSBT_Entry *client_dsbt = (DSBT_Entry *)(DSBT_master.buf);
380 for (i = 0; i < AL_size(&DSBT_master); i++)
381 {
382 DSBT_Index_Request *curr_req = client_dsbt[i].index_request;
384 if (curr_req == NULL) continue;
386 if (curr_req->file_handle == file_handle)
387 return curr_req->assigned_index;
388 }
390 /*------------------------------------------------------------------------*/
391 /* Otherwise, we either did not find the specified file handle, or a */
392 /* valid DSBT index has not yet been assigned to the file handle. */
393 /*------------------------------------------------------------------------*/
394 return DSBT_INDEX_INVALID;
395 }
397 /*****************************************************************************/
398 /* DLIF_update_all_dsbts() */
399 /* */
400 /* Update all DSBTs for the application and all libraries that use the */
401 /* DSBT model. Each DSBT index request entry was provided with the */
402 /* address and size of the DSBT contained in the loaded application. */
403 /* The client simply needs to copy the content of its master copy of the */
404 /* DSBT to each module's own DSBT. The client will check the size of */
405 /* each module's DSBT to see if it is big enough to hold the master copy */
406 /* of the DSBT before actually copying the master to the module's DSBT. */
407 /* An error will be emitted if a module's allocated DSBT is not big */
408 /* enough to hold the master DSBT. */
409 /* */
410 /*****************************************************************************/
411 BOOL DLIF_update_all_dsbts()
412 {
413 /*------------------------------------------------------------------------*/
414 /* Spin through the client's master copy of the DSBT. For each entry in */
415 /* the table: */
416 /* */
417 /* 1. Check the DSBT size for the module that is associated with the */
418 /* current slot in the DSBT to see if its DSBT size is large enough */
419 /* to hold a copy of the master DSBT. */
420 /* */
421 /* 2. Query the core loader for the static base value associated with */
422 /* the module that has been assigned to the current index in the */
423 /* DSBT. This static base value is recorded in the client's DSBT */
424 /* model. */
425 /* */
426 /* 3. Query the core loader for the DSBT base value associated with */
427 /* the module that has been assigned to the current index in the */
428 /* master DSBT. We should only look this value up once while the */
429 /* file is still open and its dynamic module object is still */
430 /* available. */
431 /* */
432 /*------------------------------------------------------------------------*/
433 int32_t i;
434 int32_t master_dsbt_size = AL_size(&DSBT_master);
435 DSBT_Entry *client_dsbt = (DSBT_Entry *)(DSBT_master.buf);
436 DSBT_Index_Request *curr_req = NULL;
438 #if LOADER_DEBUG
439 if (debugging_on)
440 {
441 DLIF_trace("Starting DLIF_update_all_dsbts() ... \n");
442 DLIF_trace("Size of master DSBT is %d\n", master_dsbt_size);
443 dump_master_dsbt();
444 }
445 #endif
447 /*------------------------------------------------------------------------*/
448 /* Spin through the master DSBT model and fill in details about the DSBT */
449 /* base and the static base associated with each module that has been */
450 /* assigned a slot in the master DSBT. */
451 /*------------------------------------------------------------------------*/
452 for (i = 0; i < master_dsbt_size; i++)
453 {
454 curr_req = client_dsbt[i].index_request;
456 /*---------------------------------------------------------------------*/
457 /* We only need to worry about filling in details for slots that have */
458 /* actually been assigned to an object module (if this slot doesn't */
459 /* have a DSBT index request record associated with it, then it is */
460 /* "available"). */
461 /*---------------------------------------------------------------------*/
462 if (curr_req != NULL)
463 {
464 /*------------------------------------------------------------------*/
465 /* If the DSBT size has not been filled in for the module that is */
466 /* assigned to this slot, look it up in the local symbol table of */
467 /* the module. We have to do this while the dynamic module object */
468 /* for the module is still open (it has a copy of the local symbol */
469 /* table). */
470 /*------------------------------------------------------------------*/
471 uint32_t curr_dsbt_size = curr_req->dsbt_size;
472 if (curr_dsbt_size < master_dsbt_size)
473 {
474 DLIF_error(DLET_MISC,
475 "DSBT allocated for %s is not large enough to hold "
476 "entire DSBT", curr_req->name);
477 return FALSE;
478 }
479 }
480 }
482 /*------------------------------------------------------------------------*/
483 /* Now write a copy of the DSBT for each module that uses the DSBT model. */
484 /* We need to find the DSBT base for each module represented in the */
485 /* master DSBT, then we can write the content of the master DSBT to each */
486 /* DSBT base location. */
487 /*------------------------------------------------------------------------*/
488 for (i = 0; i < master_dsbt_size; i++)
489 {
490 curr_req = client_dsbt[i].index_request;
492 /*---------------------------------------------------------------------*/
493 /* Write content of master DSBT to location of module's DSBT. */
494 /*---------------------------------------------------------------------*/
495 if (curr_req != NULL)
496 {
497 int j;
498 #if LOADER_DEBUG
499 if (debugging_on)
500 DLIF_trace("Writing master DSBT to 0x%08lx for module: %s\n",
501 curr_req->dsbt_base, curr_req->name);
502 #endif
504 for (j = 0; j < master_dsbt_size; j++)
505 {
506 DSBT_Index_Request *j_req = client_dsbt[j].index_request;
508 if (j_req != NULL)
509 *((TARGET_ADDRESS *)(curr_req->dsbt_base) + j) =
510 (j_req != NULL) ? j_req->static_base : 0;
511 }
512 }
513 }
515 #if LOADER_DEBUG
516 if (debugging_on) dump_master_dsbt();
517 #endif
519 return TRUE;
520 }
522 /*****************************************************************************/
523 /* dump_master_dsbt() */
524 /*****************************************************************************/
525 #if LOADER_DEBUG
526 static void dump_master_dsbt(void)
527 {
528 int i;
529 DSBT_Entry *client_dsbt = (DSBT_Entry *)(DSBT_master.buf);
530 DLIF_trace("Dumping master DSBT ...\n");
531 for (i = 0; i < AL_size(&DSBT_master); i++)
532 {
533 DSBT_Index_Request *i_req = client_dsbt[i].index_request;
534 if (i_req != NULL)
535 {
536 DLIF_trace(" slot %d has dsbt_base: 0x%08lx; static base: 0x%08lx;\n"
537 " index request from: %s\n",
538 i, i_req->dsbt_base, i_req->static_base, i_req->name);
539 }
540 else
541 {
542 DLIF_trace(" slot %d is AVAILABLE\n", i);
543 }
544 }
545 }
546 #endif
548 /*****************************************************************************/
549 /* DSBT_release_entry() */
550 /* */
551 /* Once a file is unloaded from the target, make its DSBT entry in the */
552 /* master DSBT available to objects that may be subsequently loaded. If */
553 /* we don't find the file handle among the master DSBT, then we assume */
554 /* that the file does not use the DSBT model. */
555 /* */
556 /*****************************************************************************/
557 void DSBT_release_entry(int32_t file_handle)
558 {
559 int32_t i;
560 DSBT_Entry *client_dsbt = (DSBT_Entry *)(DSBT_master.buf);
561 for (i = 0; i < AL_size(&DSBT_master); i++)
562 {
563 DSBT_Index_Request *curr_req = client_dsbt[i].index_request;
565 if (curr_req && (curr_req->file_handle == file_handle))
566 {
567 client_dsbt[i].index_request = NULL;
568 if (i < DSBT_first_avail_index) DSBT_first_avail_index = i;
569 DLIF_free(curr_req);
570 }
571 }
572 }