[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / procMgr / hlos / knl / loaders / Elf / Qnx / DLOAD / DLWRAPPER / dlw_trgmem.c
1 /*
2 * dlw_trgmem.c
3 *
4 * This source file contains the implementation of the client side's target
5 * memory allocator. The RIDL version of the dynamic loader will manage
6 * target memory from a massive data object called "trg_mem_pool". This
7 * memory manager is derived from the RTS version of malloc()/free().
8 *
9 *---------------------------------------------------------------------------
10 * This module contains the functions which implement the dynamic memory
11 * management routines. The following assumptions/rules apply:
12 *
13 * 1) Packets are allocated from host memory so they have no impact on
14 * the target memory heap.
15 * 2) The size of the heap is assumed to be 0x02000000 (the size of the
16 * .blob section in the ELF dynamic loader executable file).
17 * 3) The heap can be reset at any time by calling trg_minit()
18 *
19 *---------------------------------------------------------------------------
20 * These functions constitute the target memory manager interface with the
21 * rest of the dynamic loader:
22 *
23 * DLTMM_malloc() : Allocate a chunk of target memory per request.
24 * DLTMM_free() : Release target memory allocated to specified address.
25 * DLTMM_fwrite() : Write content of target memory to dump file.
26 * DLTMM_fread() : Read core file into target memory area.
27 *
28 *---------------------------------------------------------------------------
29 * These functions manage the target memory packet list and help the
30 * interface functions carry out a target memory allocation:
31 *
32 * trg_minit() : Initialize target memory packet list.
33 * trg_align() : Find next address within packet that is aligned.
34 * trg_free_pkt() : Free a used packet and merge it with free neighbors.
35 * trg_alloc_pkt() : Allocate chunk of free packet and split packet into
36 * used and available pieces.
37 * trg_malloc() : Serve DLTMM_malloc(), set actual request size to
38 * multiple of MIN_BLOCK and find a free packet to
39 * allocate from.
40 *
41 *---------------------------------------------------------------------------
42 *
43 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
44 *
45 *
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 *
50 * Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 *
53 * Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the
56 * distribution.
57 *
58 * Neither the name of Texas Instruments Incorporated nor the names of
59 * its contributors may be used to endorse or promote products derived
60 * from this software without specific prior written permission.
61 *
62 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
63 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
64 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
65 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
66 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
67 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
68 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
69 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
70 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
72 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 */
76 #include "ArrayList.h"
77 #include "dload_api.h"
78 #include <stdarg.h>
79 #include <stdlib.h>
80 #include <string.h>
81 #include "dlw_trgmem.h"
83 /*---------------------------------------------------------------------------*/
84 /* Definition and placement of target memory pool (defined in ".blob" */
85 /* section of ELF dynamic loader executable object file). */
86 /*---------------------------------------------------------------------------*/
87 #define trg_mem_pool_sz 0x02000000
89 #pragma DATA_SECTION(trg_mem_pool,".blob");
90 #pragma DATA_ALIGN(trg_mem_pool, 8)
91 uint8_t trg_mem_pool[trg_mem_pool_sz];
92 const uint32_t trg_mem_pool_addr = (uint32_t)trg_mem_pool;
93 static BOOL need_trg_minit = TRUE;
95 /*---------------------------------------------------------------------------*/
96 /* Target Memory Manager - is allocated from host memory to manage available */
97 /* target memory space. trg_memory is the first, and initially the */
98 /* only, element on the target memory list. */
99 /*---------------------------------------------------------------------------*/
100 static TRG_PACKET *trg_mem_head = NULL;
102 /*---------------------------------------------------------------------------*/
103 /* Function declarations */
104 /*---------------------------------------------------------------------------*/
105 static void trg_minit(void);
106 static uint32_t trg_align(uint32_t orig_addr, int alignment);
107 static void trg_free_pkt(TRG_PACKET *);
108 static uint32_t trg_alloc_pkt(TRG_PACKET *, size_t, int, uint32_t);
109 static BOOL trg_malloc(uint32_t *req_addr, size_t size, int alignment);
111 /*****************************************************************************/
112 /* TRG_MINIT() - Initialize target memory management data structures. */
113 /* Set up initial free list. */
114 /*****************************************************************************/
115 static void trg_minit(void)
116 {
117 trg_mem_head = (TRG_PACKET *)malloc(sizeof(TRG_PACKET));
119 trg_mem_head->packet_addr = trg_mem_pool_addr;
120 trg_mem_head->packet_size = trg_mem_pool_sz;
121 trg_mem_head->prev_packet = NULL;
122 trg_mem_head->next_packet = NULL;
123 trg_mem_head->used_packet = FALSE;
124 }
126 /*****************************************************************************/
127 /* TRG_ALIGN() - If given origin address is aligned, return it. Otherwise, */
128 /* find next aligned address and return it. */
129 /*****************************************************************************/
130 static uint32_t trg_align(uint32_t orig_addr, int alignment)
131 {
132 if (alignment <= 1) return orig_addr;
133 return ((orig_addr + (alignment - 1)) & ~(alignment - 1));
134 }
136 /*****************************************************************************/
137 /* TRG_FREE_PKT() - Move packet from used state to free state and merge it */
138 /* with any free neighbors on the target memory packet list. */
139 /*****************************************************************************/
140 static void trg_free_pkt(TRG_PACKET *ptr)
141 {
142 if (ptr)
143 {
144 TRG_PACKET *prev_pkt = ptr->prev_packet;
145 TRG_PACKET *next_pkt = ptr->next_packet;
147 if (prev_pkt && !prev_pkt->used_packet)
148 {
149 ptr->packet_addr = prev_pkt->packet_addr;
150 ptr->packet_size += prev_pkt->packet_size;
151 ptr->prev_packet = prev_pkt->prev_packet;
152 if (prev_pkt->prev_packet)
153 prev_pkt->prev_packet->next_packet = ptr;
154 free(prev_pkt);
155 }
157 if (next_pkt && !next_pkt->used_packet)
158 {
159 ptr->packet_size += next_pkt->packet_size;
160 ptr->next_packet = next_pkt->next_packet;
161 if (next_pkt->next_packet)
162 next_pkt->next_packet->prev_packet = ptr;
163 free(next_pkt);
164 }
166 if (!ptr->prev_packet) trg_mem_head = ptr;
168 ptr->used_packet = FALSE;
169 }
170 }
172 /*****************************************************************************/
173 /* TRG_ALLOC_PKT() - Allocate size bytes into given free packet at next */
174 /* aligned address in the packet. Split packet into used and free */
175 /* pieces, updating the target memory list along the way. */
176 /*****************************************************************************/
177 static uint32_t trg_alloc_pkt(TRG_PACKET *ptr, size_t size, int alignment,
178 uint32_t req_addr)
179 {
180 uint32_t align_addr;
181 uint32_t align_pad;
183 /*------------------------------------------------------------------------*/
184 /* Split given packet into used and unused pieces. */
185 /*------------------------------------------------------------------------*/
186 TRG_PACKET *used_pkt = ptr;
187 size_t orig_sz = 0;
188 TRG_PACKET *free_pkt = NULL;
190 /*------------------------------------------------------------------------*/
191 /* If the requested address is not equal to the packet address, we need */
192 /* to break the packet in two by inserting a free packet before the */
193 /* the used packet. This assumes that the requested address has already */
194 /* been verified to lie within the packet. */
195 /*------------------------------------------------------------------------*/
196 if (req_addr > used_pkt->packet_addr)
197 {
198 free_pkt = (TRG_PACKET *)malloc(sizeof(TRG_PACKET));
199 free_pkt->next_packet = used_pkt;
200 free_pkt->prev_packet = used_pkt->prev_packet;
201 used_pkt->prev_packet = free_pkt;
203 free_pkt->packet_size = req_addr - used_pkt->packet_addr;
204 free_pkt->packet_addr = used_pkt->packet_addr;
205 free_pkt->used_packet = FALSE;
207 used_pkt->packet_addr = req_addr;
208 }
210 /*------------------------------------------------------------------------*/
211 /* Compute aligned address within given free packet where we want to */
212 /* allocate. Any alignment padding at the front will become a separate */
213 /* free packet on the target memory list. */
214 /*------------------------------------------------------------------------*/
215 align_addr = trg_align(used_pkt->packet_addr, alignment);
216 align_pad = align_addr - used_pkt->packet_addr;
218 /*------------------------------------------------------------------------*/
219 /* If there is any padding at the front of the packet, then we'll build */
220 /* a new packet to represent our allocated space. */
221 /*------------------------------------------------------------------------*/
222 if (align_pad)
223 {
224 /*---------------------------------------------------------------------*/
225 /* If free_pkt is NULL, then we did not split ptr into two packets. */
226 /* If this is the case we need to allocate a new packet for the */
227 /* padding. If we did split ptr into two packets, just merge the */
228 /* padding into the free packet. */
229 /*---------------------------------------------------------------------*/
230 if (!free_pkt)
231 {
232 free_pkt = (TRG_PACKET *)malloc(sizeof(TRG_PACKET));
233 free_pkt->next_packet = used_pkt;
234 free_pkt->prev_packet = used_pkt->prev_packet;
235 used_pkt->prev_packet = free_pkt;
236 free_pkt->packet_addr = used_pkt->packet_addr;
237 free_pkt->packet_size = 0;
238 }
240 free_pkt->packet_size += align_pad;
241 used_pkt->packet_size -= align_pad;
242 used_pkt->packet_addr = align_addr;
244 }
246 /*------------------------------------------------------------------------*/
247 /* Preserve original size of used packet so that we can compute size of */
248 /* unused space when we split the used packet. Then set size of used */
249 /* packet. */
250 /*------------------------------------------------------------------------*/
251 orig_sz = used_pkt->packet_size;
252 used_pkt->packet_size = size;
253 used_pkt->used_packet = TRUE;
255 /*------------------------------------------------------------------------*/
256 /* If there is unused space at the end of our allocated packet, then */
257 /* we'll build up a new packet to represent this free space and at it */
258 /* into the target memory list. */
259 /*------------------------------------------------------------------------*/
260 if (orig_sz > size)
261 {
262 free_pkt = (TRG_PACKET *)malloc(sizeof(TRG_PACKET));
263 free_pkt->next_packet = used_pkt->next_packet;
264 free_pkt->prev_packet = used_pkt;
265 used_pkt->next_packet = free_pkt;
267 free_pkt->packet_size = orig_sz - size;
269 free_pkt->packet_addr = used_pkt->packet_addr + size;
271 free_pkt->used_packet = FALSE;
272 }
274 return (used_pkt->packet_addr);
275 }
277 /*****************************************************************************/
278 /* TRG_MALLOC() - Allocate target memory from the free list (which manages */
279 /* available target memory in .blob section). The free list keeps */
280 /* track of available and used target memory. */
281 /*****************************************************************************/
282 static BOOL trg_malloc(uint32_t *req_addr, size_t size, int alignment)
283 {
284 TRG_PACKET *current = NULL;
285 TRG_PACKET *best_fit = NULL;
287 if (size <= 0) return FALSE;
289 if (need_trg_minit)
290 {
291 trg_minit();
292 need_trg_minit = FALSE;
293 }
295 /*------------------------------------------------------------------------*/
296 /* If we did not get a request for a specific target address from the */
297 /* client, then find the best fit available packet, incorporating any */
298 /* alignment constraints imposed by the client. */
299 /*------------------------------------------------------------------------*/
300 if (*req_addr == (uint32_t)-1)
301 {
302 /*---------------------------------------------------------------------*/
303 /* Find best free packet on the target memory list. */
304 /*---------------------------------------------------------------------*/
305 for (current = trg_mem_head; current; current = current->next_packet)
306 {
307 /*------------------------------------------------------------------*/
308 /* Account for alignment constraint on current packet. */
309 /*------------------------------------------------------------------*/
310 uint32_t align_addr = trg_align(current->packet_addr, alignment);
311 uint32_t align_pad = align_addr - current->packet_addr;
313 /*------------------------------------------------------------------*/
314 /* Skip over any packets that are already allocated. */
315 /*------------------------------------------------------------------*/
316 if (current->used_packet) continue;
318 /*------------------------------------------------------------------*/
319 /* Best fit will be smallest free packet that is >= size. */
320 /*------------------------------------------------------------------*/
321 if ((current->packet_size > align_pad) &&
322 ((current->packet_size - align_pad) >= size))
323 {
324 if (best_fit && (current->packet_size >= best_fit->packet_size))
325 continue;
326 best_fit = current;
327 }
328 }
330 if (!best_fit) return FALSE;
332 *req_addr = trg_alloc_pkt(best_fit, size, alignment,
333 best_fit->packet_addr);
335 return TRUE;
336 }
338 /*------------------------------------------------------------------------*/
339 /* Otherwise, we do have a request for a specific target address from the */
340 /* client. So we need to find the free packet that contains that target */
341 /* address. */
342 /*------------------------------------------------------------------------*/
343 else
344 {
345 /*---------------------------------------------------------------------*/
346 /* Find the free packet that contains the requested address. */
347 /*---------------------------------------------------------------------*/
348 for (current = trg_mem_head; current; current = current->next_packet)
349 {
350 /*------------------------------------------------------------------*/
351 /* If we have a requested address, we must make sure that the */
352 /* requested address falls on an alignment boundary, if it does not */
353 /* report an error. */
354 /* -----------------------------------------------------------------*/
355 uint32_t align_addr = trg_align(*req_addr, alignment);
356 if (align_addr != *req_addr)
357 {
358 DLIF_error(DLET_TRGMEM, "requested address is not aligned\n");
359 return FALSE;
360 }
362 /*------------------------------------------------------------------*/
363 /* Does the requested address fall inside the packet? */
364 /*------------------------------------------------------------------*/
365 if (*req_addr < current->packet_addr ||
366 ((current->packet_addr + current->packet_size) <= *req_addr))
367 continue;
369 /*------------------------------------------------------------------*/
370 /* Is the current packet big enough for the request? */
371 /*------------------------------------------------------------------*/
372 if ((current->packet_size) >= size)
373 {
374 uint32_t alloc_addr = trg_alloc_pkt(current, size, alignment,
375 *req_addr);
376 if (alloc_addr != *req_addr)
377 {
378 DLIF_error(DLET_TRGMEM, "Problem with trg_alloc_pkt\n");
379 exit(1);
380 }
382 return TRUE;
383 }
385 break;
386 }
387 }
389 return FALSE;
390 }
392 /*****************************************************************************/
393 /* DLTMM_MALLOC() - Externally accessible interface into target memory */
394 /* allocator. This function will use the core target memory manager */
395 /* to find available space per requested and update target memory list */
396 /* to reflect new status of used and free target memory. */
397 /*****************************************************************************/
398 BOOL DLTMM_malloc(struct DLOAD_MEMORY_REQUEST *targ_req,
399 struct DLOAD_MEMORY_SEGMENT *obj_desc)
400 {
401 /*------------------------------------------------------------------------*/
402 /* Set up alignment constraint and request for specific address, if */
403 /* there is one. */
404 /*------------------------------------------------------------------------*/
405 int alignment = (targ_req->align) ? targ_req->align : 1;
406 uint32_t req_addr = (targ_req->flags & DLOAD_SF_relocatable) ?
407 (uint32_t)-1 : (uint32_t)obj_desc->target_address;
409 /*------------------------------------------------------------------------*/
410 /* Ask for free space from the target memory allocator. */
411 /*------------------------------------------------------------------------*/
412 if (trg_malloc(&req_addr, obj_desc->memsz_in_bytes, alignment))
413 {
414 obj_desc->target_address = targ_req->host_address = (void *)req_addr;
415 return TRUE;
416 }
418 /*------------------------------------------------------------------------*/
419 /* Something went wrong. Target memory allocation failed. */
420 /*------------------------------------------------------------------------*/
421 return FALSE;
422 }
424 /*****************************************************************************/
425 /* DLTMM_FREE() - Find packet in target memory list associated with given */
426 /* target address and change its state from used to free. */
427 /*****************************************************************************/
428 void DLTMM_free(TARGET_ADDRESS ptr)
429 {
430 uint32_t pkt_addr = (uint32_t)ptr;
431 TRG_PACKET *prev = NULL;
432 TRG_PACKET *current = NULL;
434 /*------------------------------------------------------------------------*/
435 /* Find free packet on the target memory list that contains the specified */
436 /* address that we are trying to free. */
437 /*------------------------------------------------------------------------*/
438 for (current = trg_mem_head; current; current = current->next_packet)
439 {
440 /*---------------------------------------------------------------------*/
441 /* Skip over any packets that are already free. */
442 /*---------------------------------------------------------------------*/
443 if (!current->used_packet) continue;
445 /*---------------------------------------------------------------------*/
446 /* Find used packet associated with given address. */
447 /*---------------------------------------------------------------------*/
448 if (current->packet_addr <= pkt_addr) prev = current;
449 else break;
450 }
452 if (prev) trg_free_pkt(prev);
454 else
455 {
456 DLIF_error(DLET_TRGMEM,
457 "Did not find free packet associated with given target "
458 "address, 0x%lx\n", pkt_addr);
459 exit(1);
460 }
461 }
463 /*****************************************************************************/
464 /* DLTMM_FWRITE_TRG_MEM() - Write content of target memory area to a file. */
465 /*****************************************************************************/
466 void DLTMM_fwrite_trg_mem(FILE *fp)
467 {
468 if (fp) fwrite(trg_mem_pool, trg_mem_pool_sz, 1, fp);
469 }
471 /*****************************************************************************/
472 /* DLTMM_FREAD_TRG_MEM() - Read file content into target memory area. */
473 /*****************************************************************************/
474 void DLTMM_fread_trg_mem(FILE *fp)
475 {
476 if (fp) fread(trg_mem_pool, trg_mem_pool_sz, 1, fp);
477 }
479 /*****************************************************************************/
480 /* DLTMM_DUMP_TRG_MEM() - Dump the contents of target memory into a file. */
481 /*****************************************************************************/
482 void DLTMM_dump_trg_mem(uint32_t offset, uint32_t nbytes,
483 FILE* fp)
484 {
485 uint8_t* ptr = trg_mem_pool + offset;
487 if (!fp)
488 {
489 DLIF_error(DLET_TRGMEM, "NULL file pointer given to dump_trgmem\n");
490 return;
491 }
493 /*-----------------------------------------------------------------------*/
494 /* Make sure the request is in range. */
495 /*-----------------------------------------------------------------------*/
496 if ((ptr + nbytes) > (trg_mem_pool + trg_mem_pool_sz ))
497 {
498 DLIF_error(DLET_TRGMEM, "Invalid range given to dump_trgmem\n");
499 return;
500 }
502 fwrite(ptr, 1, nbytes, fp);
503 }