Utils: Update the firmware to carry section physical addresses
[gstreamer-omap:sysbios-rpmsg.git] / src / utils / elfload / dlw_trgmem.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_trgmem.c                                                              */
36 /*                                                                           */
37 /* This source file contains the implementation of the client side's target  */
38 /* memory allocator.  The RIDL version of the dynamic loader will manage     */
39 /* target memory from a massive data object called "trg_mem_pool".  This     */
40 /* memory manager is derived from the RTS version of malloc()/free().        */
41 /*                                                                           */
42 /*---------------------------------------------------------------------------*/
43 /*                                                                           */
44 /*  This module contains the functions which implement the dynamic memory    */
45 /*  management routines. The following assumptions/rules apply:              */
46 /*                                                                           */
47 /*   1) Packets are allocated from host memory so they have no impact on     */
48 /*   the target memory heap.                                                 */
49 /*   2) The size of the heap is assumed to be 0x02000000, the size of the    */
50 /*   .blob section in the ELF dynamic loader executable file.                */
51 /*   3) The heap can be reset at any time by calling trg_minit()             */
52 /*                                                                           */
53 /*---------------------------------------------------------------------------*/
54 /* These functions constitute the target memory manager interface with the   */
55 /* rest of the dynamic loader:                                               */
56 /*                                                                           */
57 /*   DLTMM_malloc() : Allocate a chunk of target memory per request.         */
58 /*   DLTMM_free()   : Release target memory allocated to specified address.  */
59 /*   DLTMM_fwrite() : Write content of target memory to dump file.           */
60 /*   DLTMM_fread()  : Read core file into target memory area.                */
61 /*                                                                           */
62 /*---------------------------------------------------------------------------*/
63 /* These functions manage the target memory packet list and help the         */
64 /* interface functions carry out a target memory allocation:                 */
65 /*                                                                           */
66 /*   trg_minit()     : Initialize target memory packet list.                 */
67 /*   trg_align()     : Find next address within packet that is aligned.      */
68 /*   trg_free_pkt()  : Free a used packet and merge it with free neighbors.  */
69 /*   trg_alloc_pkt() : Allocate chunk of free packet and slit packet into    */
70 /*                     used and available pieces.                            */
71 /*   trg_malloc()    : Serve DLTMM_malloc(), set actual request size to      */
72 /*                     multiple of MIN_BLOCK and find a free packet to       */
73 /*                     allocate from.                                        */
74 /*                                                                           */
75 /*****************************************************************************/
76 #include "ArrayList.h"
77 #include "dload_api.h"
78 #include "dload4430.h"
79 #include <stdarg.h>
80 #include <stdlib.h>
81 #include <string.h>
82 #include "dlw_trgmem.h"
83
84 /*---------------------------------------------------------------------------*/
85 /* Function declarations                                                     */
86 /*---------------------------------------------------------------------------*/
87 static void       trg_minit(void* client_handle, uint32_t dyn_seg,
88                             uint32_t size);
89 static void       trg_mdeinit(void* client_handle);
90 static uint32_t   trg_align(uint32_t orig_addr, int alignment);
91 static void       trg_free_pkt(void* client_handle, TRG_PACKET *);
92 static uint32_t   trg_alloc_pkt(TRG_PACKET *, size_t, int, uint32_t);
93 static BOOL       trg_malloc(void* client_handle, uint32_t *req_addr,
94                              size_t size, int alignment);
95
96 /*****************************************************************************/
97 /* TRG_MINIT() - Initialize target memory management data structures.        */
98 /*   Set up initial free list.                                               */
99 /*****************************************************************************/
100 static void trg_minit(void* client_handle, uint32_t dyn_seg, uint32_t size)
101 {
102     DLoad4430_Object *clientObj = (DLoad4430_Object *)client_handle;
103
104     clientObj->trg_mem_head = (TRG_PACKET *)DLIF_malloc(sizeof(TRG_PACKET));
105     if (clientObj->trg_mem_head) {
106         clientObj->trg_mem_head->packet_addr = dyn_seg;
107         clientObj->trg_mem_head->packet_size = size;
108         clientObj->trg_mem_head->prev_packet = NULL;
109         clientObj->trg_mem_head->next_packet = NULL;
110         clientObj->trg_mem_head->used_packet = FALSE;
111     }
112 }
113
114 /*****************************************************************************/
115 /* TRG_MDEINIT() - De-Initialize target memory management data structures.   */
116 /*   Free up initial free list.                                              */
117 /*****************************************************************************/
118 static void trg_mdeinit(void* client_handle)
119 {
120     DLoad4430_Object *clientObj = (DLoad4430_Object *)client_handle;
121
122     DLIF_free(clientObj->trg_mem_head);
123 }
124
125 /*****************************************************************************/
126 /* TRG_ALIGN() - If given origin address is aligned, return it.  Otherwise,  */
127 /*   find next aligned address and return it.                                */
128 /*****************************************************************************/
129 static uint32_t trg_align(uint32_t orig_addr, int alignment)
130 {
131     if (alignment <= 1) return orig_addr;
132     return ((orig_addr + (alignment - 1)) & ~(alignment - 1));
133 }
134
135 /*****************************************************************************/
136 /* TRG_FREE_PKT() - Move packet from used state to free state and merge it   */
137 /*   with any free neighbors on the target memory packet list.               */
138 /*****************************************************************************/
139 static void trg_free_pkt(void* client_handle, TRG_PACKET *ptr)
140 {
141     DLoad4430_Object *clientObj = (DLoad4430_Object *)client_handle;
142
143     if (ptr)
144     {
145         TRG_PACKET *prev_pkt = ptr->prev_packet;
146         TRG_PACKET *next_pkt = ptr->next_packet;
147
148         if (prev_pkt && !prev_pkt->used_packet)
149         {
150             ptr->packet_addr  = prev_pkt->packet_addr;
151             ptr->packet_size += prev_pkt->packet_size;
152             ptr->prev_packet  = prev_pkt->prev_packet;
153             if (prev_pkt->prev_packet)
154                 prev_pkt->prev_packet->next_packet = ptr;
155             DLIF_free(prev_pkt);
156         }
157
158         if (next_pkt && !next_pkt->used_packet)
159         {
160             ptr->packet_size += next_pkt->packet_size;
161             ptr->next_packet  = next_pkt->next_packet;
162             if (next_pkt->next_packet)
163                 next_pkt->next_packet->prev_packet = ptr;
164             DLIF_free(next_pkt);
165         }
166
167         if (!ptr->prev_packet) clientObj->trg_mem_head = ptr;
168
169         ptr->used_packet = FALSE;
170     }
171 }
172
173 /*****************************************************************************/
174 /* TRG_ALLOC_PKT() - Allocate size bytes into given free packet at next      */
175 /*   aligned address in the packet.  Split packet into used and free         */
176 /*   pieces, updating the target memory list along the way.                  */
177 /*****************************************************************************/
178 static uint32_t trg_alloc_pkt(TRG_PACKET *ptr, size_t size, int alignment,
179                               uint32_t req_addr)
180 {
181     uint32_t align_addr;
182     uint32_t align_pad;
183
184     /*-----------------------------------------------------------------------*/
185     /* Split given packet into used and unused pieces.                       */
186     /*-----------------------------------------------------------------------*/
187     TRG_PACKET *used_pkt = ptr;
188     size_t      orig_sz  = 0;
189     TRG_PACKET *free_pkt = NULL;
190
191     /*-----------------------------------------------------------------------*/
192     /* If the requested address is not equal to the packet address, we need  */
193     /* to break the packet in two by inserting a free packet before the      */
194     /* the used packet.  This assumes that the requested address has already */
195     /* been verified to lie within the packet.                               */
196     /*-----------------------------------------------------------------------*/
197     if (req_addr > used_pkt->packet_addr)
198     {
199         free_pkt = (TRG_PACKET *)DLIF_malloc(sizeof(TRG_PACKET));
200         if(!free_pkt) {
201             return 0;
202         }
203         free_pkt->next_packet = used_pkt;
204         free_pkt->prev_packet = used_pkt->prev_packet;
205         used_pkt->prev_packet = free_pkt;
206
207         free_pkt->packet_size = req_addr - used_pkt->packet_addr;
208         free_pkt->packet_addr = used_pkt->packet_addr;
209         free_pkt->used_packet = FALSE;
210
211         used_pkt->packet_addr = req_addr;
212     }
213
214     /*-----------------------------------------------------------------------*/
215     /* Compute aligned address within given free packet where we want to     */
216     /* allocate.  Any alignment padding at the front will become a separate  */
217     /* free packet on the target memory list.                                */
218     /*-----------------------------------------------------------------------*/
219     align_addr = trg_align(used_pkt->packet_addr, alignment);
220     align_pad = align_addr - used_pkt->packet_addr;
221
222     /*-----------------------------------------------------------------------*/
223     /* If there is any padding at the front of the packet, then we'll build  */
224     /* a new packet to represent our allocated space.                        */
225     /*-----------------------------------------------------------------------*/
226     if (align_pad)
227     {
228         /*-------------------------------------------------------------------*/
229         /* If free_pkt is NULL, then we did not split ptr into two packets.  */
230         /* If this is the case we need to allocate a new packet for the      */
231         /* padding.  If we did split ptr into two packets, just merge the    */
232         /* padding into the free packet.                                     */
233         /*-------------------------------------------------------------------*/
234         if (!free_pkt)
235         {
236             free_pkt = (TRG_PACKET *)DLIF_malloc(sizeof(TRG_PACKET));
237             if(!free_pkt) {
238                 return 0;
239             }
240             free_pkt->next_packet = used_pkt;
241             free_pkt->prev_packet = used_pkt->prev_packet;
242             used_pkt->prev_packet = free_pkt;
243             free_pkt->packet_addr = used_pkt->packet_addr;
244             free_pkt->packet_size = 0;
245         }
246
247         free_pkt->packet_size += align_pad;
248         used_pkt->packet_size -= align_pad;
249         used_pkt->packet_addr = align_addr;
250
251     }
252
253     /*-----------------------------------------------------------------------*/
254     /* Preserve original size of used packet so that we can compute size of  */
255     /* unused space when we split the used packet.  Then set size of used    */
256     /* packet.                                                               */
257     /*-----------------------------------------------------------------------*/
258     orig_sz = used_pkt->packet_size;
259     used_pkt->packet_size = size;
260     used_pkt->used_packet = TRUE;
261
262     /*-----------------------------------------------------------------------*/
263     /* If there is unused space at the end of our allocated packet, then     */
264     /* we'll build up a new packet to represent this free space and at it    */
265     /* into the target memory list.                                          */
266     /*-----------------------------------------------------------------------*/
267     if (orig_sz > size)
268     {
269         free_pkt = (TRG_PACKET *)DLIF_malloc(sizeof(TRG_PACKET));
270         if(!free_pkt) {
271             return 0;
272         }
273         free_pkt->next_packet = used_pkt->next_packet;
274         free_pkt->prev_packet = used_pkt;
275         used_pkt->next_packet = free_pkt;
276
277         free_pkt->packet_size = orig_sz - size;
278
279         free_pkt->packet_addr = used_pkt->packet_addr + size;
280
281         free_pkt->used_packet = FALSE;
282     }
283
284     return (used_pkt->packet_addr);
285 }
286
287 /*****************************************************************************/
288 /* TRG_MALLOC() - Allocate target memory from the free list (which manages   */
289 /*   available target memory in .blob section).  The free list keeps         */
290 /*   track of available and used target memory.                              */
291 /*****************************************************************************/
292 static BOOL trg_malloc(void* client_handle, uint32_t *req_addr, size_t size,
293                        int alignment)
294 {
295     DLoad4430_Object *clientObj = (DLoad4430_Object *)client_handle;
296
297     TRG_PACKET   *current  = NULL;
298     TRG_PACKET   *best_fit = NULL;
299
300     if (size <= 0) return FALSE;
301
302     /*-----------------------------------------------------------------------*/
303     /* If we did not get a request for a specific target address from the    */
304     /* client, then find the best fit available packet, incorporating any    */
305     /* alignment constraints imposed by the client.                          */
306     /*-----------------------------------------------------------------------*/
307     if (*req_addr == (uint32_t)-1)
308     {
309         /*-------------------------------------------------------------------*/
310         /* Find best free packet on the target memory list.                  */
311         /*-------------------------------------------------------------------*/
312         for (current = clientObj->trg_mem_head;
313              current;
314              current = current->next_packet)
315         {
316             /*---------------------------------------------------------------*/
317             /* Account for alignment constraint on current packet.           */
318             /*---------------------------------------------------------------*/
319             uint32_t align_addr = trg_align(current->packet_addr, alignment);
320             uint32_t align_pad = align_addr - current->packet_addr;
321
322             /*---------------------------------------------------------------*/
323             /* Skip over any packets that are already allocated.             */
324             /*---------------------------------------------------------------*/
325             if (current->used_packet) continue;
326
327             /*---------------------------------------------------------------*/
328             /* Best fit will be smallest free packet that is >= size.        */
329             /*---------------------------------------------------------------*/
330             if ((current->packet_size > align_pad) &&
331                 ((current->packet_size - align_pad) >= size))
332             {
333                 if (best_fit && (current->packet_size >= best_fit->packet_size))
334                     continue;
335                 best_fit = current;
336             }
337         }
338
339         if (!best_fit) return FALSE;
340
341         *req_addr = trg_alloc_pkt(best_fit, size, alignment,
342                                    best_fit->packet_addr);
343
344         return TRUE;
345     }
346
347     /*-----------------------------------------------------------------------*/
348     /* Otherwise, we do have a request for a specific target address from the*/
349     /* client.  So we need to find the free packet that contains that target */
350     /* address.                                                              */
351     /*-----------------------------------------------------------------------*/
352     else
353     {
354         /*-------------------------------------------------------------------*/
355         /* Find the free packet that contains the requested address.         */
356         /*-------------------------------------------------------------------*/
357         for (current = clientObj->trg_mem_head;
358              current;
359              current = current->next_packet)
360         {
361             /*---------------------------------------------------------------*/
362             /* If we have a requested address, we must make sure that the    */
363             /* requested address falls on an alignment boundary, if it does  */
364             /* not report an error.                                          */
365             /* --------------------------------------------------------------*/
366             uint32_t align_addr = trg_align(*req_addr, alignment);
367             if (align_addr != *req_addr)
368             {
369                 DLIF_error(DLET_TRGMEM, "requested address is not aligned\n");
370                 return FALSE;
371             }
372
373             /*---------------------------------------------------------------*/
374             /* Does the requested address fall inside the packet?            */
375             /*---------------------------------------------------------------*/
376             if (*req_addr < current->packet_addr ||
377                 ((current->packet_addr + current->packet_size) <= *req_addr))
378                 continue;
379
380             /*---------------------------------------------------------------*/
381             /* Is the current packet big enough for the request?             */
382             /*---------------------------------------------------------------*/
383             if ((current->packet_size) >= size)
384             {
385                 uint32_t alloc_addr = trg_alloc_pkt(current, size, alignment,
386                                                     *req_addr);
387                 if (alloc_addr != *req_addr)
388                 {
389                     DLIF_error(DLET_TRGMEM, "Problem with trg_alloc_pkt\n");
390                     exit(1);
391                 }
392
393                 return TRUE;
394             }
395
396             break;
397         }
398     }
399
400     return FALSE;
401 }
402
403 /*****************************************************************************/
404 /* DLTMM_INIT() - Externally accessible interface to initialize the target   */
405 /*   memory allocator.                                                       */
406 /*****************************************************************************/
407 BOOL DLTMM_init(void* client_handle, uint32_t dynMemAddr, uint32_t size)
408 {
409     DLoad4430_Object *clientObj = (DLoad4430_Object *)client_handle;
410
411     if (dynMemAddr == 0)
412         return FALSE;
413
414     if (!clientObj->trg_minit)
415     {
416         trg_minit(client_handle, dynMemAddr, size);
417         clientObj->trg_minit = TRUE;
418     }
419
420     return TRUE;
421 }
422
423 /*****************************************************************************/
424 /* DLTMM_DEINIT() - Externally accessible interface to de-initialize the     */
425 /*   target memory allocator.                                                */
426 /*****************************************************************************/
427 BOOL DLTMM_deinit(void* client_handle)
428 {
429     DLoad4430_Object *clientObj = (DLoad4430_Object *)client_handle;
430
431     if (clientObj->trg_minit)
432     {
433         trg_mdeinit(client_handle);
434         clientObj->trg_minit = FALSE;
435     }
436
437     return TRUE;
438 }
439
440 /*****************************************************************************/
441 /* DLTMM_MALLOC() - Externally accessible interface into target memory       */
442 /*   allocator.  This function will use the core target memory manager       */
443 /*   to find available space per requested and update target memory list     */
444 /*   to reflect new status of used and free target memory.                   */
445 /*****************************************************************************/
446 BOOL DLTMM_malloc(void* client_handle,
447                   struct DLOAD_MEMORY_REQUEST *targ_req,
448                   struct DLOAD_MEMORY_SEGMENT *obj_desc)
449 {
450     /*-----------------------------------------------------------------------*/
451     /* Set up alignment constraint and request for specific address, if      */
452     /* there is one.                                                         */
453     /*-----------------------------------------------------------------------*/
454     int      alignment = (targ_req->align) ? targ_req->align : 1;
455     uint32_t req_addr  = (targ_req->flags & DLOAD_SF_relocatable) ?
456         (uint32_t)-1 : (uint32_t)obj_desc->target_address;
457
458     /*-----------------------------------------------------------------------*/
459     /* Ask for free space from the target memory allocator.                  */
460     /*-----------------------------------------------------------------------*/
461     if (trg_malloc(client_handle,
462                    &req_addr,
463                    obj_desc->memsz_in_bytes,
464                    alignment))
465     {
466         obj_desc->target_address = targ_req->host_address = (void *)req_addr;
467         return TRUE;
468     }
469
470     /*-----------------------------------------------------------------------*/
471     /* Something went wrong.  Target memory allocation failed.               */
472     /*-----------------------------------------------------------------------*/
473     return FALSE;
474 }
475
476 /*****************************************************************************/
477 /* DLTMM_FREE() - Find packet in target memory list associated with given    */
478 /*   target address and change its state from used to free.               */
479 /*****************************************************************************/
480 void DLTMM_free(void* client_handle, TARGET_ADDRESS ptr)
481 {
482     DLoad4430_Object *clientObj = (DLoad4430_Object *)client_handle;
483
484     uint32_t      pkt_addr = (uint32_t)ptr;
485     TRG_PACKET   *prev     = NULL;
486     TRG_PACKET   *current  = NULL;
487
488     /*-----------------------------------------------------------------------*/
489     /* Find free packet on the target memory list that contains the specified*/
490     /* address that we are trying to free.                                   */
491     /*-----------------------------------------------------------------------*/
492     for (current = clientObj->trg_mem_head;
493          current;
494          current = current->next_packet)
495     {
496         /*-------------------------------------------------------------------*/
497         /* Skip over any packets that are already free.                      */
498         /*-------------------------------------------------------------------*/
499         if (!current->used_packet) continue;
500
501         /*-------------------------------------------------------------------*/
502         /* Find used packet associated with given address.                   */
503         /*-------------------------------------------------------------------*/
504         if (current->packet_addr <= pkt_addr) prev = current;
505         else break;
506     }
507
508     if (prev) trg_free_pkt(client_handle, prev);
509
510     else
511     {
512         DLIF_error(DLET_TRGMEM,
513                    "Did not find free packet associated with given target "
514                    "address, 0x%lx\n", pkt_addr);
515         exit(1);
516     }
517 }
518
519 /*****************************************************************************/
520 /* DLTMM_FWRITE_TRG_MEM() - Write content of target memory area to a file.   */
521 /*****************************************************************************/
522 void DLTMM_fwrite_trg_mem(FILE *fp)
523 {
524     /*if (fp) fwrite(trg_mem_pool, trg_mem_pool_sz, 1, fp);*/
525 }
526
527 /*****************************************************************************/
528 /* DLTMM_FREAD_TRG_MEM() - Read file content into target memory area.        */
529 /*****************************************************************************/
530 void DLTMM_fread_trg_mem(FILE *fp)
531 {
532     /*if (fp) fread(trg_mem_pool, trg_mem_pool_sz, 1, fp);*/
533 }
534
535 /*****************************************************************************/
536 /* DLTMM_DUMP_TRG_MEM() - Dump the contents of target memory into a file.    */
537 /*****************************************************************************/
538 void DLTMM_dump_trg_mem(uint32_t offset, uint32_t nbytes,
539                         FILE* fp)
540 {
541 #if 0
542     uint8_t* ptr = trg_mem_pool + offset;
543
544     if (!fp)
545     {
546         DLIF_error(DLET_TRGMEM, "NULL file pointer given to dump_trgmem\n");
547         return;
548     }
549
550     /*-----------------------------------------------------------------------*/
551     /* Make sure the request is in range.                                    */
552     /*-----------------------------------------------------------------------*/
553     if ((ptr + nbytes) > (trg_mem_pool + trg_mem_pool_sz ))
554     {
555         DLIF_error(DLET_TRGMEM, "Invalid range given to dump_trgmem\n");
556         return;
557     }
558
559     fwrite(ptr, 1, nbytes, fp);
560 #endif
561 }