Utils: Update the firmware to carry section physical addresses
[gstreamer-omap:sysbios-rpmsg.git] / src / utils / elfload / dlw_client.c
1 /*
2  *  Syslink-IPC for TI OMAP Processors
3  *
4  *  Copyright (c) 2008-2011, 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_client.c                                                              */
36 /*                                                                           */
37 /* DLW implementation of client functions required by dynamic loader API.    */
38 /* Please see list of client-required API functions in dload_api.h.          */
39 /*                                                                           */
40 /* DLW is expected to run on the DSP.  It uses C6x RTS functions for file    */
41 /* I/O and memory management (both host and target memory).                  */
42 /*                                                                           */
43 /* A loader that runs on a GPP for the purposes of loading C6x code onto a   */
44 /* DSP will likely need to re-write all of the functions contained in this   */
45 /* module.                                                                   */
46 /*                                                                           */
47 /*****************************************************************************/
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <stdarg.h>
52 #include <string.h>
53
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <unistd.h>
57 #include <dload_api.h>
58
59 #include "../rprcfmt.h"
60
61 extern FILE * out_file;
62 extern unsigned int tag_addr[];
63 extern char *tag_name[];
64 extern int num_tags;
65
66 /*
67  * insert data at the beginning of an open, existing file
68  * note that file needs to be opened with "w+b"
69  */
70 static int finsert(unsigned char * newData, int numBytes, FILE * fp)
71 {
72     struct stat statBuf;
73     off_t size;
74     char * data;
75     int n;
76
77     /* get size of current data in file and alloc buffer to hold it */
78     fseek(fp, 0, SEEK_SET);
79     fstat(fileno(fp), &statBuf);
80     size = statBuf.st_size;
81
82     data = malloc(size);
83     fread(data, 1, size, fp);
84
85     /* back to the beginning of file */
86     fseek(fp, 0, SEEK_SET);
87
88     /* write the new data */
89     n = fwrite(newData, 1, numBytes, fp);
90     if (!n || ferror(fp)) {
91         perror("first fwrite: ");
92     }
93
94     /* write the original data */
95     n = fwrite(data, 1, size, fp);
96     if (!n || ferror(fp)) {
97         perror("second fwrite: ");
98     }
99
100     fseek(fp, 0, SEEK_END);
101
102     free(data);
103
104     return size + numBytes;
105 }
106
107 static void patchup_resources(struct rproc_fw_resource *res,
108                               unsigned int res_size)
109 {
110     int i;
111     struct rproc_fw_resource *res_end;
112
113     printf("resource size: %d\n", sizeof(struct rproc_fw_resource));
114
115     res_end = (struct rproc_fw_resource *)((unsigned int)res + res_size);
116
117     while (res < res_end) {
118         printf("resource: %d, da: %llx, pa: %llx, len: %d, name: %s\n",
119                 res->type, res->da, res->pa, res->len, res->name);
120         switch (res->type) {
121         case RSC_TRACE:
122             printf("found TRACE resource, looking for corresponding tag...\n");
123
124             for (i = 0; i < num_tags; i++) {
125                 if (!strncmp(tag_name[i], "trace", 5)) {
126                     if (res->da == atoi(&tag_name[i][5])) {
127                         printf("...found tag %s\n", tag_name[i]);
128                         printf("patching address 0x%x\n", tag_addr[i]);
129                         res->da = tag_addr[i];
130                         break;
131                     }
132                 }
133             }
134
135             if (i == num_tags) {
136                 printf("...no tag found, ignoring resource\n");
137             }
138             break;
139
140         case RSC_BOOTADDR:
141             printf("found ENTRYPOINT resource, looking for corresponding tag...\n");
142
143             for (i = 0; i < num_tags; i++) {
144                 if (!strncmp(tag_name[i], "entry", 5)) {
145                     if (res->da == atoi(&tag_name[i][5])) {
146                         printf("...found tag %s\n", tag_name[i]);
147                         printf("patching address 0x%x\n", tag_addr[i]);
148                         res->da = tag_addr[i];
149                         break;
150                     }
151                 }
152             }
153
154             if (i == num_tags) {
155                 printf("...no tag found, ignoring resource\n");
156             }
157             break;
158
159         case RSC_CARVEOUT:
160         case RSC_DEVMEM:
161         case RSC_IRQ:
162         case RSC_DEVICE:
163             printf("found M/I/D/S resource, nothing to do\n");
164             break;
165
166         default:
167             fprintf(stderr, "unknown resource type %d\n", res->type);
168             break;
169         }
170         res++;
171     }
172 }
173
174 /*---------------------------------------------------------------------------*/
175 /* Target Memory Access / Write Services                                     */
176 /*                                                                           */
177 /*    The client side's target memory allocator infrastructure communicates  */
178 /*    with the core loader through the DLOAD_MEMORY_REQUEST and              */
179 /*    DLOAD_MEMORY_SEGMENT data structures defined above.  To complete the   */
180 /*    loading of an object segment, the segment may need to be relocated     */
181 /*    before it is actually written to target memory in the space that was   */
182 /*    allocated for it by DLIF_allocate().                                   */
183 /*                                                                           */
184 /*    The client side of the dynamic loader provides two functions to help   */
185 /*    complete the process of loading an object segment, DLIF_copy() and     */
186 /*    DLIF_write().                                                          */
187 /*                                                                           */
188 /*    These functions help to make the core loader truly independent of      */
189 /*    whether it is running on the host or target architecture and how the   */
190 /*    client provides for reading/writing from/to target memory.             */
191 /*                                                                           */
192 /*---------------------------------------------------------------------------*/
193 /*---------------------------------------------------------------------------*/
194 /* DLIF_copy()                                                               */
195 /*                                                                           */
196 /*    Copy segment data from the object file described in the 'fp' and       */
197 /*    'offset' of the DLOAD_MEMORY_REQUEST into host accessible memory so    */
198 /*    that it can relocated or otherwise manipulated by the core loader.     */
199 /*                                                                           */
200 /*---------------------------------------------------------------------------*/
201 BOOL     DLIF_copy(void* client_handle, struct DLOAD_MEMORY_REQUEST* targ_req)
202 {
203     struct DLOAD_MEMORY_SEGMENT* obj_desc = targ_req->segment;
204     FILE * f = targ_req->fp;
205     unsigned int dst_addr = 0;
206     struct rproc_fw_section * fwsect;
207     void * buf;
208     void * fwbuf;
209     unsigned int buf_size;
210     unsigned int fwbuf_size;
211     unsigned int type;
212     int i;
213
214     if (obj_desc->objsz_in_bytes == 0) {
215         printf("skipping empty section at %p\n", obj_desc->target_address);
216         return TRUE;
217     }
218
219     dst_addr = (unsigned int)obj_desc->target_address;
220
221     /* insure all sections are word-multiples for easier loading */
222     buf_size = (obj_desc->objsz_in_bytes + 3) & ~0x3;
223     fwbuf_size = buf_size + 16;
224     fwbuf = calloc(4, fwbuf_size / 4);
225     buf = fwbuf + 16;
226     fseek(f, targ_req->offset, SEEK_SET);
227     fread(buf, obj_desc->objsz_in_bytes, 1, f);
228
229     type = FW_DATA;        // default
230     for (i = 0; i < num_tags; i++) {
231         type = FW_DATA;        // default
232         if (dst_addr == tag_addr[i]) {
233             printf("  matched destination addr w/ specified tag addr\n");
234             if (!strcmp(tag_name[i], "restab")) {
235                 printf("  found 'restab' section\n");
236                 type = FW_RESOURCE;
237                 patchup_resources((struct rproc_fw_resource *)buf, buf_size);
238                 break;
239             }
240             else if (!strcmp(tag_name[i], "text")) {
241                 printf("  found 'text' section\n");
242                 type = FW_TEXT;
243                 break;
244             }
245             else if (!strcmp(tag_name[i], "data")) {
246                 printf("  found 'data' section\n");
247                 type = FW_DATA;
248                 break;
249             }
250         }
251     }
252
253     fwsect = (struct rproc_fw_section *)fwbuf;
254
255     fwsect->type = type;
256     fwsect->da = dst_addr;
257     fwsect->len = buf_size;
258     if (type == FW_RESOURCE) {
259         finsert(fwbuf, fwbuf_size, out_file);
260     }
261     else {
262         fwrite(fwbuf, 1, fwbuf_size, out_file);
263     }
264
265     free(fwbuf);
266
267     return 1;
268 }
269
270 /*---------------------------------------------------------------------------*/
271 /* File I/O                                                                  */
272 /*                                                                           */
273 /*    The client side of the dynamic loader must provide basic file I/O      */
274 /*    capabilities so that the core loader has random access into any        */
275 /*    object file that it is asked to load.                                  */
276 /*                                                                           */
277 /*    The client side of the dynamic loader must provide a definition of     */
278 /*    the LOADER_FILE_DESC in dload_filedefs.h.  This allows the core loader */
279 /*    to be independent of how the client accesses raw data in an object     */
280 /*    file.                                                                  */
281 /*                                                                           */
282 /*---------------------------------------------------------------------------*/
283
284 /*---------------------------------------------------------------------------*/
285 /* DLIF_fseek()                                                              */
286 /*                                                                           */
287 /*    Seek to a position in a file (accessed via 'stream') based on the      */
288 /*    values for offset and origin.                                          */
289 /*                                                                           */
290 /*---------------------------------------------------------------------------*/
291 int      DLIF_fseek(LOADER_FILE_DESC *stream, int32_t offset, int origin)
292 {
293     return fseek(stream, offset, origin);
294 }
295
296 /*---------------------------------------------------------------------------*/
297 /* DLIF_ftell()                                                              */
298 /*                                                                           */
299 /*    Return the current file position in the file identified in the         */
300 /*    LOADER_FILE_DESC pointed to by 'stream'.                               */
301 /*                                                                           */
302 /*---------------------------------------------------------------------------*/
303 int32_t  DLIF_ftell(LOADER_FILE_DESC *stream)
304 {
305     return ftell(stream);
306 }
307
308 /*---------------------------------------------------------------------------*/
309 /* DLIF_fread()                                                              */
310 /*                                                                           */
311 /*    Read 'size' * 'nmemb' bytes of data from the file identified in the    */
312 /*    LOADER_FILE_DESC object pointed to by 'stream', and write that data    */
313 /*    into the memory accessed via 'ptr'.                                    */
314 /*                                                                           */
315 /*---------------------------------------------------------------------------*/
316 size_t   DLIF_fread(void *ptr, size_t size, size_t nmemb,
317                     LOADER_FILE_DESC *stream)
318 {
319     return fread(ptr, size, nmemb, stream);
320 }
321
322 /*---------------------------------------------------------------------------*/
323 /* DLIF_fclose()                                                             */
324 /*                                                                           */
325 /*    Close a file that was opened on behalf of the core loader. Ownership   */
326 /*    of the file pointer in question belongs to the core loader, but the    */
327 /*    client has exclusive access to the file system.                        */
328 /*                                                                           */
329 /*---------------------------------------------------------------------------*/
330 int      DLIF_fclose(LOADER_FILE_DESC *fd)
331 {
332     return fclose(fd);
333 }
334
335 /*---------------------------------------------------------------------------*/
336 /* Host Memory Management                                                    */
337 /*                                                                           */
338 /*    Allocate and free host memory as needed for the dynamic loader's       */
339 /*    internal data structures.  If the dynamic loader resides on the        */
340 /*    target architecture, then this memory is allocated from a target       */
341 /*    memory heap that must be managed separately from memory that is        */
342 /*    allocated for a dynamically loaded object file.                        */
343 /*                                                                           */
344 /*---------------------------------------------------------------------------*/
345
346 /*---------------------------------------------------------------------------*/
347 /* DLIF_malloc()                                                             */
348 /*                                                                           */
349 /*    Allocate 'size' bytes of memory space that is usable as scratch space  */
350 /*    (appropriate for the loader's internal data structures) by the dynamic */
351 /*    loader.                                                                */
352 /*                                                                           */
353 /*---------------------------------------------------------------------------*/
354 void*    DLIF_malloc(size_t size)
355 {
356     return malloc(size);
357 }
358
359 /*---------------------------------------------------------------------------*/
360 /* DLIF_free()                                                               */
361 /*                                                                           */
362 /*    Free memory space that was previously allocated by DLIF_malloc().      */
363 /*                                                                           */
364 /*---------------------------------------------------------------------------*/
365 void     DLIF_free(void* ptr)
366 {
367     free(ptr);
368 }
369
370 /*****************************************************************************/
371 /* DLIF_LOAD_DEPENDENT() - Perform whatever maintenance is needed in the     */
372 /*      client when loading of a dependent file is initiated by the core     */
373 /*      loader.  Open the dependent file on behalf of the core loader,       */
374 /*      then invoke the core loader to get it into target memory. The core   */
375 /*      loader assumes ownership of the dependent file pointer and must ask  */
376 /*      the client to close the file when it is no longer needed.            */
377 /*                                                                           */
378 /*      If debug support is needed under the Braveheart model, then create   */
379 /*      a host version of the debug module record for this object.  This     */
380 /*      version will get updated each time we allocate target memory for a   */
381 /*      segment that belongs to this module.  When the load returns, the     */
382 /*      client will allocate memory for the debug module from target memory  */
383 /*      and write the host version of the debug module into target memory    */
384 /*      at the appropriate location.  After this takes place the new debug   */
385 /*      module needs to be added to the debug module list.  The client will  */
386 /*      need to update the tail of the DLModules list to link the new debug  */
387 /*      module onto the end of the list.                                     */
388 /*                                                                           */
389 /*****************************************************************************/
390 int DLIF_load_dependent(void* client_handle, const char* so_name)
391 {
392     printf("%s: unexpected call\n", __func__);
393     return 0;
394 }
395
396 /*****************************************************************************/
397 /* DLIF_UNLOAD_DEPENDENT() - Perform whatever maintenance is needed in the   */
398 /*      client when unloading of a dependent file is initiated by the core   */
399 /*      loader.  Invoke the DLOAD_unload() function to get the core loader   */
400 /*      to release any target memory that is associated with the dependent   */
401 /*      file's segments.                                                     */
402 /*****************************************************************************/
403 void DLIF_unload_dependent(void* client_handle, uint32_t file_handle)
404 {
405     printf("%s: unexpected call\n", __func__);
406 }
407
408
409 /*****************************************************************************/
410 /* DLIF_WARNING() - Write out a warning message from the core loader.        */
411 /*****************************************************************************/
412 void DLIF_warning(LOADER_WARNING_TYPE wtype, const char *fmt, ...)
413 {
414     va_list ap;
415     va_start(ap,fmt);
416     printf("<< D L O A D >> WARNING: ");
417     vprintf(fmt,ap);
418     va_end(ap);
419 }
420
421 /*****************************************************************************/
422 /* DLIF_ERROR() - Write out an error message from the core loader.           */
423 /*****************************************************************************/
424 void DLIF_error(LOADER_ERROR_TYPE etype, const char *fmt, ...)
425 {
426     va_list ap;
427     va_start(ap,fmt);
428     printf("<< D L O A D >> ERROR: ");
429     vprintf(fmt,ap);
430     va_end(ap);
431 }
432
433 /*****************************************************************************/
434 /* DLIF_trace() - Write out a trace from the core loader.                    */
435 /*****************************************************************************/
436 void DLIF_trace(const char *fmt, ...)
437 {
438     va_list ap;
439     va_start(ap,fmt);
440     vprintf(fmt,ap);
441     va_end(ap);
442 }
443
444 /*---------------------------------------------------------------------------*/
445 /* DLIF_allocate()                                                           */
446 /*                                                                           */
447 /*    Given a DLOAD_MEMORY_REQUEST created by the core loader, allocate      */
448 /*    target memory to fulfill the request using the target memory           */
449 /*    management infrastrucutre on the client side of the dynamic loader.    */
450 /*    The contents of the DLOAD_MEMORY_REQUEST will be updated per the       */
451 /*    details of a successful allocation.  The allocated page and address    */
452 /*    can be found in the DLOAD_MEMORY_SEGMENT attached to the request.      */
453 /*    The boolean return value reflects whether the allocation was           */
454 /*    successful or not.                                                     */
455 /*                                                                           */
456 /*---------------------------------------------------------------------------*/
457 BOOL     DLIF_allocate(void * client_handle, struct DLOAD_MEMORY_REQUEST *req)
458 {
459 //    printf("%s: %p, %p\n", __func__, client_handle, req);
460
461     return 1;
462 }
463
464 /*---------------------------------------------------------------------------*/
465 /* DLIF_release()                                                            */
466 /*                                                                           */
467 /*    Given a DLOAD_MEMORY_SEGMENT description, free the target memory       */
468 /*    associated with the segment using the target memory management         */
469 /*    infrastructure on the client side of the dynamic loader.               */
470 /*                                                                           */
471 /*---------------------------------------------------------------------------*/
472 BOOL     DLIF_release(void* client_handle, struct DLOAD_MEMORY_SEGMENT* ptr)
473 {
474     printf("%s: %p, %p\n", __func__, client_handle, ptr);
475
476     return 1;
477 }
478
479 /*---------------------------------------------------------------------------*/
480 /* DLIF_write()                                                              */
481 /*                                                                           */
482 /*    Once the segment data described in the DLOAD_MEMORY_REQUEST is ready   */
483 /*    (relocated, if needed), write the segment contents to the target       */
484 /*    memory identified in the DLOAD_MEMORY_SEGMENT attached to the request. */
485 /*                                                                           */
486 /*    After the segment contents have been written to target memory, the     */
487 /*    core loader should discard the DLOAD_MEMORY_REQUEST object, but retain */
488 /*    the DLOAD_MEMORY_SEGMENT object so that the target memory associated   */
489 /*    with the segment can be releases when the segment is unloaded.         */
490 /*                                                                           */
491 /*---------------------------------------------------------------------------*/
492 BOOL     DLIF_write(void* client_handle, struct DLOAD_MEMORY_REQUEST* req)
493 {
494 //    printf("%s: %p, %p\n", __func__, client_handle, req);
495
496     return 1;
497 }
498
499 /*---------------------------------------------------------------------------*/
500 /* DLIF_read()                                                               */
501 /*                                                                           */
502 /*    Given a host accessible buffer, read content of indicated target       */
503 /*    memory address into the buffer.                                        */
504 /*---------------------------------------------------------------------------*/
505 BOOL     DLIF_read(void* client_handle, void *ptr, size_t size, size_t nmemb,
506                    TARGET_ADDRESS src)
507 {
508     printf("%s: %p, %p, %d, %d, %p\n", __func__, client_handle, ptr, size, nmemb, src);
509
510     return 1;
511 }
512
513 /*---------------------------------------------------------------------------*/
514 /* DLIF_execute()                                                            */
515 /*                                                                           */
516 /*    Start execution on the target architecture from given 'exec_addr'.     */
517 /*    If the dynamic loader is running on the target architecture, this can  */
518 /*    be effected as a simple function call.                                 */
519 /*                                                                           */
520 /*---------------------------------------------------------------------------*/
521 int32_t  DLIF_execute(void* client_handle, TARGET_ADDRESS exec_addr)
522 {
523     printf("%s: %p, %p\n", __func__, client_handle, exec_addr);
524
525     return 1;
526 }