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