source: svn/trunk/newcon3bcm2_21bu/magnum/portinginterface/xvd/7552/bxvd_relf.c

Last change on this file was 2, checked in by jglee, 11 years ago

first commit

  • Property svn:executable set to *
File size: 41.4 KB
Line 
1/***************************************************************************
2 * bxvd_relf.c
3 *
4 * ELF relocation functionality for VDEC ARC images.
5 *
6 * $brcm_Workfile: bxvd_relf.c $
7 * $brcm_Revision: Hydra_Software_Devel/50 $
8 * $brcm_Date: 7/20/11 3:05p $
9 *
10 * Module Description:
11 *   See module overview and code
12 *
13 * Revision History:
14 *
15 * $brcm_Log: /magnum/portinginterface/xvd/7401/bxvd_relf.c $
16 *
17 * Hydra_Software_Devel/50   7/20/11 3:05p davidp
18 * SW7420-2001: Reorder header file includes.
19 *
20 * Hydra_Software_Devel/49   9/20/10 6:03p davidp
21 * SW7340-207: Allow makefile to control the definition of
22 * BXVD_RELF_USE_KERNEL_MEMORY. If not defined, then define to 1.
23 *
24 * Hydra_Software_Devel/48   2/26/09 3:02p pblanco
25 * PR52516: Fix non-const static global variable issues.
26 *
27 * Hydra_Software_Devel/47   10/20/08 1:46p pblanco
28 * PR48050: Fix memory leak found by Coverity.
29 *
30 * Hydra_Software_Devel/46   9/12/07 2:09p pblanco
31 * PR29915: Fixed memory addressing problem in WriteOutput that was
32 * causing FW failures when using kernel memory.
33 *
34 * Hydra_Software_Devel/45   9/12/07 7:54a pblanco
35 * PR29915: Cleaned up WriteOutput code
36 *
37 * Hydra_Software_Devel/44   9/7/07 12:48p pblanco
38 * PR29915: Set BXVD_RELF_USE_KERNEL_MEMORY to 0 until I can diagnose a
39 * strange interaction between using kernel memory, check and BMRC.
40 *
41 * Hydra_Software_Devel/43   9/6/07 5:35p nilesh
42 * PR29915: Added BERR_TRACE wrapper around all return codes
43 *
44 * Hydra_Software_Devel/42   9/6/07 9:15a pblanco
45 * PR29915: Added the ability to choose between using kernel or system
46 * heap memory for local allocations. This is compile time configurable
47 * and the default setting is to use kernel memory. Set
48 * BXVD_RELF_USE_KERNEL_MEMORY to 0 to use the system heap.
49 *
50 * Hydra_Software_Devel/41   5/31/07 3:03p pblanco
51 * PR27168: Added a compile time switchable option for additional memory
52 * caching. Off by default.
53 *
54 * Hydra_Software_Devel/40   5/14/07 11:30a nilesh
55 * PR30249: Merged UOD 2.x changes to mainline
56 *
57 * Hydra_Software_Devel/PR30249/3   5/8/07 2:35p nilesh
58 * PR30249: Fixed compilation on non-7440 platforms
59 *
60 * Hydra_Software_Devel/PR30249/2   5/7/07 3:08p vijeth
61 * PR 30249 : Fix for Warning messages
62 *
63 * Hydra_Software_Devel/PR30249/1   5/7/07 2:40p vijeth
64 * PR 30249: Fix for warning message
65 *
66 * Hydra_Software_Devel/39   3/12/07 4:35p pblanco
67 * PR26433: Added casts to fixup routine for picky compilers.
68 *
69 * Hydra_Software_Devel/38   3/12/07 10:35a pblanco
70 * PR26433: Cleaned up some compiler warnings that appear when using a
71 * very picky compiler set at a high warning level.
72 *
73 * Hydra_Software_Devel/37   3/6/07 12:14p nilesh
74 * PR26658: Changed logic for enabling/disabling cached memory to use
75 * compile time flag BXVD_USE_UNCACHED_MEMORY that can be set without
76 * modifying XVD
77 *
78 * Hydra_Software_Devel/36   3/5/07 3:11p pblanco
79 * PR26658: Made caching a compile time choice. See
80 * BXVD_USE_CACHED_MEMORY.
81 *
82 * Hydra_Software_Devel/35   3/5/07 12:23p pblanco
83 * PR26658: Made sure all cached heap free calls are preceeded by a cache
84 * flush.
85 *
86 * Hydra_Software_Devel/34   3/2/07 1:36p nilesh
87 * PR26188: Merged 7400B0 bring-up branch to mainline.  Cleaned up heap
88 * naming and usage.
89 *
90 * Hydra_Software_Devel/PR26188/1   2/27/07 4:05p nilesh
91 * PR26188: 7400B0 Bring-Up
92 *
93 * Hydra_Software_Devel/33   2/26/07 8:44p nilesh
94 * PR26188: Fixed memory heap used for temporary memory allocation on
95 * 7400B0
96 *
97 * Hydra_Software_Devel/32   2/21/07 1:10p pblanco
98 * PR26433: Set formatting to standard agreed upon within the XVD group on
99 * 2/20/07.
100 *
101 * Hydra_Software_Devel/31   1/8/07 1:52p pblanco
102 * PR26658: We don't support inline code at all in magnum so the three
103 * "bottleneck" inline functions have been converted to macros.
104 *
105 * Hydra_Software_Devel/30   12/21/06 3:26p pblanco
106 * PR26658: After scanning the gcc bug list, it appears that this was not
107 * a compiler bug (not sure I agree) but a usage issue. Changed the code
108 * and now it'll work regardless of the presence of an explicit -O0
109 * option.
110 *
111 * Hydra_Software_Devel/29   12/21/06 9:23a pblanco
112 * PR26658: An explicit -O0 compiler flag was causing the build failure.
113 * Removing the flag from the xvd_static_test Makefile fixed the problem
114 * although -O0 is the compiler default, so the original issue may be a
115 * compiler problem.
116 *
117 * Hydra_Software_Devel/28   12/20/06 3:10p pblanco
118 * PR26658: Temporarily removed inlines until I can determine why 7403
119 * build is having issues.
120 *
121 * Hydra_Software_Devel/27   12/20/06 2:04p pblanco
122 * PR26658: Significant performance enhancements including using cached
123 * memory for relocation engine work structures and inlining of some
124 * critical functions.
125 *
126 * Hydra_Software_Devel/26   12/18/06 10:44a pblanco
127 * PR26658: Write to FW memory directly instead of via BXVD_Mem_Write.
128 * Also, cache the converted virtual address and increment that instead
129 * of doing the conversion every time through the loop.
130 *
131 * Hydra_Software_Devel/25   12/13/06 3:08p pblanco
132 * PR26463: This fix supercedes the previous checkin. The relocation
133 * engine now uses the general FW heap instead of memory allocated with
134 * BKNI_Malloc.
135 *
136 * Hydra_Software_Devel/24   12/13/06 11:28a pblanco
137 * PR26463: Checkin of potential fix for flash write issue. This will
138 * require testing once the affected platform and build type is known.
139 *
140 * Hydra_Software_Devel/23   12/11/06 3:15p pblanco
141 * PR26433: Cleaned up code.
142 *
143 * Hydra_Software_Devel/22   9/22/06 9:30a pblanco
144 * PR23959: Added additional error check for EOC not found.
145 *
146 * Hydra_Software_Devel/21   9/19/06 9:36a pblanco
147 * PR23959: Added conditionalized debugging messages for secure FW
148 * development.
149 *
150 * Hydra_Software_Devel/20   8/21/06 3:32p pblanco
151 * PR22673: Add private tag ("P") to relocation engine names since they're
152 * only used internally.
153 *
154 * Hydra_Software_Devel/19   8/21/06 2:55p pblanco
155 * PR22673: Renamed relocation engine entry points to XVD standards.
156 *
157 * Hydra_Software_Devel/18   6/26/06 12:43p pblanco
158 * PR22302: Removed #include of stdio.h
159 *
160 * Hydra_Software_Devel/17   6/26/06 9:40a pblanco
161 * PR22302: Changed source to match new names in bxvd_relf.h
162 *
163 * Hydra_Software_Devel/16   6/22/06 2:12p pblanco
164 * PR22302: Changed code to use local XVD definitions of Elf data types.
165 *
166 * Hydra_Software_Devel/15   6/22/06 1:16p pblanco
167 * PR20017: Incorporate Roy Lewis' changes for BE systems. Verified on LE
168 * Linux and BE VxWorks.
169 *
170 * Hydra_Software_Devel/14   6/14/06 6:24a pblanco
171 * PR20017: Endian debug message changed per Roy Lewis' email.
172 *
173 * Hydra_Software_Devel/13   6/13/06 11:00a pblanco
174 * PR20091: Fixed endian test to check FW endianess against OS endianess
175 * and removed endian swap debug messages.
176 *
177 * Hydra_Software_Devel/12   6/12/06 6:09p davidp
178 * PR20017: Allocate memory for FW code out of framework heap.
179 *
180 * Hydra_Software_Devel/11   5/24/06 10:01a pblanco
181 * PR20017: Added code to detect and return end of code address.
182 *
183 * Hydra_Software_Devel/10   5/18/06 3:25p pblanco
184 * PR20017: Merged in Adam's change for allocated section only output.
185 *
186 * Hydra_Software_Devel/9   5/10/06 4:07p pblanco
187 * PR20017: More debugging messages.
188 *
189 * Hydra_Software_Devel/8   5/9/06 10:05a pblanco
190 * PR20017: Added more BDBG_MSGs to code.
191 *
192 * Hydra_Software_Devel/7   5/8/06 8:07a pblanco
193 * PR20017: Sanity checkin.
194 *
195 * Hydra_Software_Devel/6   5/4/06 2:53p pblanco
196 * PR20017: Real work started on relocatable FW to be tested on 7401a0.
197 * Added debug messages.
198 *
199 * Hydra_Software_Devel/5   4/13/06 8:40a pblanco
200 * PR20017: Code cleanup.
201 *
202 * Hydra_Software_Devel/4   4/6/06 9:35a pblanco
203 * PR20017: Removed or changed all references to stdio functions.
204 *
205 * Hydra_Software_Devel/3   4/5/06 11:27a pblanco
206 * PR20017: Added code to output QuickSim records instead of SRecords.
207 *
208 * Hydra_Software_Devel/2   4/5/06 9:32a pblanco
209 * PR20017: Sanity checkin.
210 *
211 * Hydra_Software_Devel/1   4/4/06 11:41a pblanco
212 * PR20017: Initial check in.
213 ***************************************************************************/
214
215/*=************************ Module Overview ********************************
216<verbatim>
217*
218* Our relocation strategy assumes that the program was linked in the
219* following fashion:
220*
221*    +------+
222*    |      | <-- code_base
223*    | text |   |
224*    |      |   | data_offset
225*    +------+   V
226*    |      |
227*    | data |
228*    |      |
229*    +------+
230*    |      |
231*    | bss  |
232*    |      |
233*    +------+
234*     ... other
235*
236* That is, the code (text) and data are linked more-or-less contiguously,
237* followed by bss.
238*
239* The layout is characterized by two values: code_base and data_offset.
240* The first gives the base of the link (typically 00000000, but it could
241* be anything), and the second gives the offset from code_base to the
242* beginning of the data section ( ** NOT ** the address of the data_section).
243*
244* We also need a third parameter (load_base), which tells us where in
245* physical memory you wish the image relocated/loaded.  We relocate the
246* image such that code_base --> load_base.
247*
248* Except...
249*
250* We relocate anything in code sections as though code_base --> 00000000.
251* The code gets loaded to locations starting at load_base, but relocation
252* is done as though code were being loaded to 00000000.
253*
254* When you run the ARC you must load:
255*
256*   DecCx_RegCodeBase <-- load_base
257*   DecCx_RegCodeEnd  <-- data_offset
258*   
259* Load the code at the addresses emitted by RelocateELF and then start the
260* ARC at location 00000000.
261*
262</verbatim>
263****************************************************************************/
264#include "bstd.h"                /* standard types */
265#include "bdbg.h"                /* Dbglib */
266#include "bkni.h"                /* malloc, free, snprintf */
267#include "bxvd.h"
268#include "bxvd_platform.h"
269#include "bxvd_priv.h"
270#include "bxvd_errors.h"
271#include "bxvd_relf.h"
272
273BDBG_MODULE(BXVD_RELF);
274
275#ifndef UINT32_C
276#define UINT32_C(value) ((uint_least32_t)(value ## UL))
277#endif
278
279#define BXVD_MAX_SHDR          128
280#define BXVD_OUTPUT_MAX_SIZE   32
281
282/* Set this to 1 if you want tons of debug output */
283#define BXVD_RELOC_DEBUG_DETAIL_MSGS 0
284
285/*
286 * Set this to 1 if you want BXVD_P_Relf_WriteOutput to use
287 * cached memory
288 */
289#define BXVD_RELF_WRITE_CACHED_MEMORY 0
290
291/*
292 * Set this to 0 if you want Relf to use system heap
293 * memory for temporary processing instead of kernel memory
294 */
295#ifndef BXVD_RELF_USE_KERNEL_MEMORY
296#define BXVD_RELF_USE_KERNEL_MEMORY 1
297#endif
298
299/* Working context structure */
300typedef struct
301{     
302      int32_t    swap_required;
303      uint32_t   code_base;
304      uint32_t   load_base;
305      Bxvd_Elf32_Ehdr header;
306      Bxvd_Elf32_Shdr section_header[BXVD_MAX_SHDR];
307      uint8_t     *section_data[BXVD_MAX_SHDR];
308      uint8_t     *uncached_section_data[BXVD_MAX_SHDR];
309      uint32_t   new_section_base[BXVD_MAX_SHDR];
310      Bxvd_Elf32_Sym  *symtab;
311      int32_t    symcount;
312      uint8_t    *image;
313      uint32_t   image_size;
314} ElfInfo;
315
316/* Local prototypes */
317static BERR_Code BXVD_P_Relf_ReadHeaders(BXVD_Handle hXvd, ElfInfo *info, 
318                                         uint32_t *allocCount, uint32_t *freeCount);
319static uint8_t   *BXVD_P_Relf_ReadSection(BXVD_Handle hXvd, 
320                                          ElfInfo *info, 
321                                          int32_t index, 
322                                          uint32_t *allocCount, 
323                                          uint32_t *freeCount);
324
325static void      BXVD_P_Relf_RelocateSections(ElfInfo *info);
326static void      BXVD_P_Relf_RelocateSymbols(ElfInfo *info);
327static int32_t   BXVD_P_Relf_FindRelocSection(ElfInfo *info, 
328                                              uint32_t prog_index);
329static void      BXVD_P_Relf_DoRelocationA(ElfInfo *info, 
330                                           int32_t prog_index, 
331                                           int32_t rel_index);
332static void      BXVD_P_Relf_Fixup(uint8_t *data, 
333                                   unsigned pc, 
334                                   unsigned targetAddress,
335                                   int32_t type, 
336                                   int32_t addend);
337static BERR_Code BXVD_P_Relf_ReadInput(ElfInfo *info, 
338                                       uint8_t *buffer,
339                                       uint32_t offset,
340                                       uint32_t length);
341
342/*
343 * Since we don't support the use of inline functions in magnum, the following
344 * three functions have been converted to macros. These functions were
345 * identified as bottlenecks during execution profiling.
346 */
347
348/* Get a 32 bit value and swap it if necessary. */
349#define BXVD_P_Relf_Get32(swap, n)      \
350do {                                    \
351      if (swap)                         \
352      {                                 \
353         n = ((n & 0xFF000000) >> 24) | \
354             ((n & 0x00FF0000) >>  8) | \
355             ((n & 0x0000FF00) <<  8) | \
356             ((n & 0x000000FF) << 24);  \
357      }                                 \
358} while(0)
359
360/* Get a 16 bit value and swap it if necessary. */
361#define BXVD_P_Relf_Get16(swap, n)                      \
362do {                                                    \
363      if (swap)                                         \
364      {                                                 \
365         n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); \
366      }                                                 \
367} while(0)
368
369/* Release a previously allocated section. */
370/* LSRAM start address. Nothing >= this address is processed */
371#if BXVD_RELF_USE_KERNEL_MEMORY
372#define BXVD_P_Relf_ReleaseSection(hXvd, info, index)   \
373do {                                                    \
374      if (info->section_data[index])                    \
375      {                                                 \
376         BKNI_Free(info->section_data[index]); \
377         info->section_data[index       ] = 0;          \
378         ++freeCount;                                   \
379      }                                                 \
380} while(0)     
381#else
382#if BXVD_USE_UNCACHED_MEMORY
383#define BXVD_P_Relf_ReleaseSection(hXvd, info, index)                   \
384do {                                                                             \
385      if (info->section_data[index])                                             \
386      {                                                                          \
387         BMEM_Heap_Free(hXvd->hSystemHeap, info->uncached_section_data[index]); \
388         info->section_data[index       ] = 0;                                   \
389         info->uncached_section_data[index] = 0;                                 \
390         ++freeCount;                                                            \
391      }                                                                          \
392} while(0)     
393#else
394#define BXVD_P_Relf_ReleaseSection(hXvd, info, index)                   \
395do {                                                                             \
396      if (info->section_data[index])                                             \
397      {                                                                          \
398         BMEM_Heap_FlushCache(hXvd->hSystemHeap,                                \
399                              info->section_data[index],                         \
400                              info->section_header[index].sh_size);              \
401         BMEM_Heap_Free(hXvd->hSystemHeap, info->uncached_section_data[index]); \
402         info->section_data[index       ] = 0;                                   \
403         info->uncached_section_data[index] = 0;                                 \
404         ++freeCount;                                                            \
405      }                                                                          \
406} while(0)     
407#endif
408#endif
409
410/* LSRAM start address. Nothing >= this address is processed */
411#define LSRAM 0x30000000
412
413/*----------------------------------------------------------------------*
414 *              Porting layer                                           *
415 *----------------------------------------------------------------------*/
416
417/* Format the block into QuickSim format (one word/line; no
418 * ranges).  Note that we byte-swap; the ELF files for the ARC
419 * appear to be little endian, and we want these 32-bit values
420 * to be bit-correct (i.e. bit 31 of a word in memory should be
421 * bit 31 of a word in the QuickSim output).
422 */
423static void BXVD_P_Relf_WriteOutput(BXVD_Handle hXvd, 
424                                    uint32_t addr,
425                                    uint8_t *block,
426                                    int32_t size)
427{
428   void *temp;
429#if BXVD_RELF_WRITE_CACHED_MEMORY
430   void *ctemp;
431#endif
432   uint32_t virt_addr, word;
433
434   BDBG_MSG(("BXVD_P_Relf_WriteOutput: size is %x at address %x", size, addr));
435
436   BMEM_Heap_ConvertOffsetToAddress(hXvd->hSystemHeap, 
437                                    addr, 
438                                    (void **)&temp);
439#if BXVD_RELF_WRITE_CACHED_MEMORY
440   BMEM_Heap_ConvertAddressToCached(hXvd->hSystemHeap, 
441                                    temp, 
442                                    (void **)&ctemp);   
443   virt_addr = (uint32_t)ctemp;
444#else
445   virt_addr = (uint32_t)temp;
446#endif
447
448   while ( size > 3 )
449   {
450      word = ((block[3] & 0xFF) << 24) |
451         ((block[2] & 0xFF) << 16) |
452         ((block[1] & 0xFF) <<  8) |
453         ((block[0] & 0xFF) <<  0);
454                               
455      *(uint32_t *)virt_addr = word;
456
457      addr  += 4;
458      block += 4;
459      size  -= 4;
460      virt_addr += 4;
461   }
462
463   if ( size > 0 )
464   {
465      word = 0;
466      virt_addr += 4;
467      switch ( size )
468      {
469         case 3: word |= (block[2] & 0xFF) << 16;
470         case 2: word |= (block[1] & 0xFF) <<  8;
471         case 1: word |= (block[0] & 0xFF) <<  0;
472            break;
473      }
474      *(uint32_t *)virt_addr = word;
475   }
476
477#if BXVD_RELF_WRITE_CACHED_MEMORY
478   BMEM_Heap_FlushCache(hXvd->hSystemHeap, ctemp, size);
479#endif
480}
481
482/*----------------------------------------------------------------------*
483 *              Entry Point                                             *
484 *----------------------------------------------------------------------*/
485
486/* Read and relocate and ELF file.  The ELF file is assumed to
487 * already reside in memory at image[]; the total number of bytes
488 * in the ELF image is given by image_size.
489 *
490 * Output is produced via the BXVD_P_Relf_WriteBlock() function.
491 *
492 * The two parameters (code_base and load_base) define the
493 * relocation as described in the comments at the top of the file.
494 */
495BERR_Code BXVD_P_Relf_RelocateELF(BXVD_Handle hXvd,
496                                  uint8_t  *image,
497                                  uint32_t image_size,
498                                  uint32_t code_base,
499                                  uint32_t load_base,
500                                  uint32_t *end_of_code)
501{
502   bool     found_data_section;
503   int32_t  i;
504   int32_t  r;
505#if !BXVD_USE_UNCACHED_MEMORY && !BXVD_RELF_USE_KERNEL_MEMORY
506   void *temp;
507   ElfInfo *tinfo;
508#endif
509   ElfInfo  *info;
510   uint32_t base, allocCount, freeCount;
511   BERR_Code status = BERR_SUCCESS;
512               
513   BDBG_ENTER(BXVD_P_Relf_RelocateELF);
514               
515   allocCount = freeCount = 0;
516
517#if BXVD_USE_UNCACHED_MEMORY && !BXVD_RELF_USE_KERNEL_MEMORY
518   BDBG_MSG(("using uncached memory"));
519#else
520   BDBG_MSG(("using cached memory"));
521#endif
522               
523   /* Allocate and initialize our local context. */
524#if BXVD_RELF_USE_KERNEL_MEMORY
525   info = (ElfInfo *)BKNI_Malloc(sizeof(ElfInfo));
526   if (!info)
527   {
528      BDBG_ERR(("unable to allocate context structure"));
529      return BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
530   }
531   ++allocCount;
532   BKNI_Memset(info, 0, sizeof(ElfInfo));
533#else
534   /* Allocate and initialize our local context. */
535   tinfo = (ElfInfo *)BMEM_Heap_AllocAligned(hXvd->hSystemHeap, 
536                                             sizeof(ElfInfo), 
537                                             4, 
538                                             0);
539   if (!tinfo)
540   {
541      BDBG_ERR(("unable to allocate context structure"));
542      return BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
543   }
544   BKNI_Memset(tinfo, 0, sizeof(ElfInfo));
545   ++allocCount;
546   /* Use cached access for relocation memory */
547#if BXVD_USE_UNCACHED_MEMORY
548   info = tinfo;
549#else
550   BMEM_Heap_ConvertAddressToCached(hXvd->hSystemHeap, tinfo, (void **)&temp);
551   info = (ElfInfo *)temp;
552#endif
553#endif
554
555   found_data_section = false;
556               
557   BDBG_MSG(("image = %x image size = %d(%x), code_base = %x, load_base = %x",
558             image, image_size, image_size, code_base, load_base));
559               
560   info->code_base   = code_base;
561   info->load_base   = load_base;
562   info->image       = image;
563   info->image_size  = image_size;
564               
565   /* Read the control information from the ELF image. */
566   BDBG_MSG(("Reading ELF image headers"));
567   if ( BXVD_P_Relf_ReadHeaders(hXvd, info, &allocCount, &freeCount) != 0 )
568   {
569      BDBG_ERR(("failed reading header information\n"));
570      BKNI_Free(info);
571      return BERR_TRACE(BXVD_ERR_RELF_BAD_HEADER);
572   }
573               
574   /* Do part 1 of the relocation: move the sections and symbols. */
575   BDBG_MSG(("Relocating sections"));
576   BXVD_P_Relf_RelocateSections(info);
577   BDBG_MSG(("Relocating symbols"));
578   BXVD_P_Relf_RelocateSymbols (info);
579               
580   /* Do part 2 of the relocation: relocate and emit each loadable
581    *   PROGBITS section.
582    */
583   for (i = 1; i < info->header.e_shnum; i++)
584   {
585#if BXVD_RELOC_DEBUG_DETAIL_MSGS
586      BDBG_MSG(("Relocating PROGBITS section %d", i));
587#endif
588      if ( info->section_header[i].sh_size == 0 )
589      {
590#if BXVD_RELOC_DEBUG_DETAIL_MSGS
591         BDBG_MSG(("section size = 0... skipping"));
592#endif
593         continue;
594      }
595      if ((info->section_header[i].sh_flags & BXVD_SHF_ALLOC) == 0)
596      {
597#if BXVD_RELOC_DEBUG_DETAIL_MSGS
598         BDBG_MSG(("sh_flags & SHF_ALLOC... skipping"));
599#endif
600         continue;
601      }
602      if ( info->section_header[i].sh_type != BXVD_SHT_PROGBITS )
603      {
604#if BXVD_RELOC_DEBUG_DETAIL_MSGS
605         BDBG_MSG(("not a PROGBITS section... skipping"));
606#endif
607         continue;
608      }
609      if ( info->section_header[i].sh_addr >= LSRAM )
610      {
611#if BXVD_RELOC_DEBUG_DETAIL_MSGS
612         BDBG_MSG(("section addr >= 0x30000000... done"));
613#endif
614         break;
615      }
616                               
617      /* Read sections */
618      if ( ! BXVD_P_Relf_ReadSection(hXvd, info, i, &allocCount, &freeCount) )
619      { 
620         BDBG_MSG(("unable to read program data in RelocateELF()"));
621         status = BXVD_ERR_RELF_BAD_SECTION;
622         break;
623      }
624                               
625      /* See if we can find a relocation section for this program section.  If
626       *        there isn't one then we don't need to modify this section.
627       */
628      r = BXVD_P_Relf_FindRelocSection(info, i);
629      if (r)
630      {         
631         if (info->section_header[r].sh_type == BXVD_SHT_REL)
632         {     
633            BDBG_ERR(("relocation type REL unsupported for ARC"));
634            status = BXVD_ERR_RELF_BAD_RELOC_TYPE;
635            break;
636         }
637                                               
638         if ( ! BXVD_P_Relf_ReadSection(hXvd, info, r, &allocCount, &freeCount) )
639         {
640            BDBG_ERR(("unable to read relocation data in RelocateELF()"));
641            status = BXVD_ERR_RELF_BAD_SECTION; 
642            break;
643         }
644                                               
645         BXVD_P_Relf_DoRelocationA(info, i, r);
646         BXVD_P_Relf_ReleaseSection(hXvd, info, r);
647      } 
648                       
649                               
650      /* Determine the base address of this section in the output.
651       * This is different for code vs. data because code is always
652       * relocated to zero, but loaded somewhere else (load_base).
653       * Data is relocated to its absolute address.
654       */
655      if ( info->section_header[i].sh_flags & BXVD_SHF_EXECINSTR )
656      {
657         base = info->new_section_base[i] + info->load_base;
658      }
659      else
660      {
661         base = info->new_section_base[i];
662         if (found_data_section == false)
663         {
664            *end_of_code = base;
665            found_data_section = true;
666         }
667      }
668
669      /* Move relocated code to FW memory one section at a time */
670      BXVD_P_Relf_WriteOutput(hXvd, 
671                              base, 
672                              info->section_data[i], 
673                              info->section_header[i].sh_size);
674      BXVD_P_Relf_ReleaseSection(hXvd, info, i);
675   }
676               
677               
678   /* Release anything that we allocated along the way. */
679   for (i = 0; i < info->header.e_shnum; i++)
680   {
681      if ( info->section_data[i] )
682         BXVD_P_Relf_ReleaseSection(hXvd, info, i);
683   }
684               
685   /* If we didn't detect EOC, signal an error since the image is
686    * probably corrupt
687    */
688   if (*end_of_code == 0)
689   {
690      BDBG_ERR(("EOC == 0!"));
691      status = BXVD_ERR_RELF_NO_EOC_FOUND;
692   }
693               
694   /* Free the heap we used for the info structure */
695#if !BXVD_USE_UNCACHED_MEMORY && !BXVD_RELF_USE_KERNEL_MEMORY
696   BMEM_Heap_FlushCache(hXvd->hSystemHeap, info, sizeof(ElfInfo));
697#endif
698
699#if BXVD_RELF_USE_KERNEL_MEMORY
700   BKNI_Free(info);
701   ++freeCount;
702#else
703   BMEM_Heap_Free(hXvd->hSystemHeap, tinfo);
704   ++freeCount;
705#endif 
706
707   /* Show the number of allocations and frees */
708   BDBG_MSG(("Local allocation count: %d local free count: %d", allocCount, freeCount));
709               
710   /* Get out cleanly or signal an error if we picked one up along the way */
711   BDBG_LEAVE(BXVD_P_Relf_RelocateELF);
712
713   if (status == 0)
714      return status;
715   else
716      return BERR_TRACE(status);
717}
718
719/*
720 * Read the ELF image into the supplied local buffer
721 */
722static BERR_Code BXVD_P_Relf_ReadInput (ElfInfo *info, 
723                                        uint8_t *buffer, 
724                                        uint32_t offset, 
725                                        uint32_t length)
726{
727   if ( offset >= info->image_size )
728   {
729      BDBG_ERR(("BXVD_P_Relf_ReadInput error: offset (%x) >= info->image_size (%x)",
730                offset, info->image_size));
731      return BERR_TRACE(BXVD_ERR_RELF_BAD_INPUT);
732   }
733 
734   if ( (offset + length) > info->image_size )
735   {
736      BDBG_ERR(("BXVD_P_Relf_ReadInput error:(offset + length)(%x) > info->image_size (%x)",
737                (offset + length), info->image_size));
738      return BERR_TRACE(BXVD_ERR_RELF_BAD_INPUT);
739   }
740 
741   BKNI_Memcpy(buffer, info->image + offset, length);
742               
743   return BERR_TRACE(BERR_SUCCESS);
744}
745
746/*----------------------------------------------------------------------*
747 *              ELF input and parsing                                   *
748 *----------------------------------------------------------------------*/
749
750/* Read the header information from the ELF image.  This function
751 * reads the following sections:
752 *
753 * - the ELF header
754 * - the section headers
755 * - the dynamic symbol table
756 */
757static BERR_Code BXVD_P_Relf_ReadHeaders( BXVD_Handle hXvd, ElfInfo * info, 
758                                          uint32_t *allocCount, uint32_t *freeCount)
759{
760   int32_t    i;
761   uint32_t   offset;
762   uint32_t   n;
763   Bxvd_Elf32_Shdr *hdr;
764               
765   /* Read the ELF header. */
766   if (BXVD_P_Relf_ReadInput(info, 
767                             (uint8_t *)&(info->header), 
768                             0, 
769                             sizeof(Bxvd_Elf32_Ehdr)) != 0)
770   {
771      BDBG_ERR(("unable to read ELF header"));
772      return BERR_TRACE(BXVD_ERR_RELF_BAD_HEADER);
773   } 
774               
775#if (BSTD_CPU_ENDIAN == BSTD_ENDIAN_LITTLE)
776   info->swap_required = (info->header.e_ident[BXVD_EI_DATA] == BXVD_ELFDATA2LSB) ? 0 : 1;
777#else
778   info->swap_required = (info->header.e_ident[BXVD_EI_DATA] == BXVD_ELFDATA2LSB) ? 1 : 0;
779#endif
780
781   BDBG_MSG(("Header %s endianess of system - byteswapping %s occur (data=%d)",
782             info->swap_required?"does not match":"matches", 
783             info->swap_required?"will":"will not", 
784             info->header.e_ident[BXVD_EI_DATA]));
785
786   BXVD_P_Relf_Get16(info->swap_required, info->header.e_type);
787   BXVD_P_Relf_Get16(info->swap_required, info->header.e_machine);
788   BXVD_P_Relf_Get32(info->swap_required, info->header.e_version);
789   BXVD_P_Relf_Get32(info->swap_required, info->header.e_entry);
790   BXVD_P_Relf_Get32(info->swap_required, info->header.e_phoff);
791   BXVD_P_Relf_Get32(info->swap_required, info->header.e_shoff);
792   BXVD_P_Relf_Get32(info->swap_required, info->header.e_flags);
793   BXVD_P_Relf_Get16(info->swap_required, info->header.e_ehsize);
794   BXVD_P_Relf_Get16(info->swap_required, info->header.e_phentsize);
795   BXVD_P_Relf_Get16(info->swap_required, info->header.e_phnum);
796   BXVD_P_Relf_Get16(info->swap_required, info->header.e_shentsize);
797   BXVD_P_Relf_Get16(info->swap_required, info->header.e_shnum);
798   BXVD_P_Relf_Get16(info->swap_required, info->header.e_shstrndx);
799 
800
801   /* Read the section headers. */
802   if ( info->header.e_shoff )
803   {       
804      offset = info->header.e_shoff;
805      hdr    = info->section_header;
806   
807      for (i = 0; i < info->header.e_shnum; i++)
808      {
809         if ( BXVD_P_Relf_ReadInput(info, 
810                                    (uint8_t *)hdr, 
811                                    offset, 
812                                    sizeof(Bxvd_Elf32_Shdr)) != 0 )
813         {
814            BDBG_ERR(("unable to read section header"));
815            return BERR_TRACE(BXVD_ERR_RELF_BAD_INPUT);
816         }
817
818         offset += info->header.e_shentsize;
819     
820         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_name);
821         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_type);
822         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_flags);
823         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_addr);
824         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_offset);
825         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_size);
826         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_link);
827         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_info);
828         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_addralign);
829         BXVD_P_Relf_Get32(info->swap_required, hdr->sh_entsize);
830     
831         hdr++;
832      }
833   }
834
835   /*
836    * Any REL or RELA sections will point to the dynamic symbol table, which
837    * must be a single section (so they'd better all point to the same place).
838    * Find it and read in that symbol table section.
839    */
840   n = 0;
841   for (i = 0; i < info->header.e_shnum; i++)
842   {
843      if ( info->section_header[i].sh_type == BXVD_SHT_REL || 
844           info->section_header[i].sh_type == BXVD_SHT_RELA )
845      {
846         if ( n == 0 )
847            n = info->section_header[i].sh_link;
848         else if ( n != info->section_header[i].sh_link )
849         {
850            BDBG_ERR(("multiple dynamic symbol table sections referenced"));
851            return BERR_TRACE(BXVD_ERR_MULT_SYM_TABLE_REFS);
852         }
853      } 
854   }
855   if ( ! n )
856   {
857      for (i = 0; i < info->header.e_shnum; i++)
858      {
859         if ( info->section_header[i].sh_type == BXVD_SHT_SYMTAB )
860         {
861            n = i;
862            break;
863         }
864      }
865   }
866               
867   if ( n )
868   {
869      info->symtab   = (Bxvd_Elf32_Sym *) BXVD_P_Relf_ReadSection(hXvd, info, n, allocCount, freeCount);
870      info->symcount = info->section_header[n].sh_size / sizeof(Bxvd_Elf32_Sym);
871      if ( ! info->symtab )
872      {
873         BDBG_ERR(("unable to read symbol table"));
874         return BERR_TRACE(BXVD_ERR_CANT_READ_SYMTAB);
875      }
876   
877      /* Byte-swap the symbol table entries. */
878      for (i = 0; i < info->symcount; i++)
879      {     
880         BXVD_P_Relf_Get32(info->swap_required, info->symtab[i].st_name);
881         BXVD_P_Relf_Get32(info->swap_required, info->symtab[i].st_value);
882         BXVD_P_Relf_Get32(info->swap_required, info->symtab[i].st_size);
883         BXVD_P_Relf_Get16(info->swap_required, info->symtab[i].st_shndx);
884      }
885   }
886
887   return BERR_TRACE(BERR_SUCCESS);
888}
889
890/*
891 * Read the section information from the ELF image
892 */
893static uint8_t *BXVD_P_Relf_ReadSection( BXVD_Handle hXvd, ElfInfo * info, int32_t index, 
894                                         uint32_t *allocCount, uint32_t *freeCount)
895{
896#if !BXVD_USE_UNCACHED_MEMORY && !BXVD_RELF_USE_KERNEL_MEMORY
897   void *temp;
898#endif
899   uint8_t   *ptr, *tptr;
900   unsigned offset;
901   unsigned size;
902 
903   if ( info->section_data[index] )
904      return info->section_data[index];
905
906   size   = info->section_header[index].sh_size;
907   offset = info->section_header[index].sh_offset;
908 
909   if ( size == 0 || offset == 0 )
910      return NULL;
911 
912#if BXVD_RELF_USE_KERNEL_MEMORY
913   tptr = (uint8_t *)BKNI_Malloc(size);
914   ++(*allocCount);
915#else
916   tptr = (uint8_t *)BMEM_Heap_AllocAligned(hXvd->hSystemHeap, size, 4, 0);
917   ++(*allocCount);
918#endif
919   if ( tptr )
920   {
921#if BXVD_USE_UNCACHED_MEMORY || BXVD_RELF_USE_KERNEL_MEMORY
922      ptr = tptr;
923#else
924      BMEM_Heap_ConvertAddressToCached(hXvd->hSystemHeap, 
925                                       tptr, 
926                                       (void **)&temp);
927      ptr = (uint8_t *)temp;
928#endif
929      if ( BXVD_P_Relf_ReadInput(info, ptr, offset, size) != 0 )
930      {
931#if !BXVD_USE_UNCACHED_MEMORY
932         BMEM_Heap_FlushCache(hXvd->hSystemHeap, ptr, size);
933#endif
934#if BXVD_RELF_USE_KERNEL_MEMORY
935         BKNI_Free(ptr);
936         ++(*freeCount);
937#else
938         BMEM_Heap_Free(hXvd->hSystemHeap, ptr);
939         ++(*freeCount);
940#endif
941         return NULL;
942      }
943     
944      info->section_data[index] = ptr;
945   }
946   else
947   {
948      BDBG_ERR(("Could not allocate section data buffer"));
949      ptr = NULL;
950   }
951
952   return ptr;
953}
954
955/*----------------------------------------------------------------------*
956 *              Relocation                                              *
957 *----------------------------------------------------------------------*/
958
959/* Compute new base addresses for each section header. These get written into
960 * the array new_section_base[] (rather than overwriting the sh_addr members)
961 * because we need the original section base addresses later during
962 * relocation.
963 */
964static void BXVD_P_Relf_RelocateSections( ElfInfo * info )
965{
966   int32_t i;
967   uint32_t base;
968
969   for (i = 1; i < info->header.e_shnum; i++)
970   {
971      info->new_section_base[i] = 0;
972   
973      base = info->section_header[i].sh_addr;
974      if ( base == 0 && info->section_header[i].sh_type != BXVD_SHT_PROGBITS )
975         continue;
976               
977      /* Skip anything in LSRAM -- that stays where it is. */
978      if ( base >= LSRAM )
979         continue;
980
981      /* Skip anything below the stated code base -- we don't know
982       * what it is.
983       */
984      if ( base < info->code_base )
985         continue;
986   
987      if ( info->section_header[i].sh_flags & BXVD_SHF_EXECINSTR )
988      {
989         /* This is a code section -- relocate it to zero. */
990         base -= info->code_base;
991#if BXVD_RELOC_DEBUG_DETAIL_MSGS
992         BDBG_MSG(("Code section relocation. base = %x", base));
993#endif
994      }
995      else
996      {
997         /* This is a data section -- relocate it to the stated
998          * load position (same offset as in the current image).
999          */
1000         base = (base - info->code_base) + info->load_base;
1001#if BXVD_RELOC_DEBUG_DETAIL_MSGS
1002         BDBG_MSG(("Data section relocation. base = %x", base));
1003#endif
1004      }
1005   
1006      info->new_section_base[i] = base;
1007   }
1008}
1009
1010/* Go through the symbol table and relocate all symbols.  We just overwrite
1011 * the st_addr field, since we won't be needing the original address after
1012 * this.
1013 */
1014static void BXVD_P_Relf_RelocateSymbols( ElfInfo * info )
1015{
1016   int32_t    i;
1017   uint32_t   offset;     /* Offset of symbol within section */
1018   Bxvd_Elf32_Sym  *symbol;    /* Symbol being relocated */
1019   Bxvd_Elf32_Shdr *section;   /* Section containing symbol */
1020 
1021   symbol = info->symtab;
1022   for (i = 1; i < info->symcount; i++)
1023   {
1024      symbol++;
1025
1026      if ( symbol->st_shndx == 0 || symbol->st_shndx >= BXVD_MAX_SHDR )
1027         continue;
1028   
1029      if ( symbol->st_value >= LSRAM )
1030         continue;
1031   
1032      section          = info->section_header + symbol->st_shndx;
1033      offset           = symbol->st_value - section->sh_addr;
1034      symbol->st_value = info->new_section_base[ symbol->st_shndx ] + offset;
1035   }
1036}
1037
1038/* Determine which REL or RELA section holds relocation enties for the
1039 * program section indexed by 'prog_index'.
1040 *
1041 * Returns the index of the REL(A) section, or 0 if there is none.
1042 */
1043static int32_t BXVD_P_Relf_FindRelocSection(ElfInfo * info, 
1044                                            uint32_t prog_index )
1045{
1046   int32_t     i;
1047 
1048   for (i = 1; i < info->header.e_shnum; i++)
1049   {
1050      if ( info->section_header[i].sh_info != prog_index )
1051         continue;
1052   
1053      if ( info->section_header[i].sh_type == BXVD_SHT_RELA ||
1054           info->section_header[i].sh_type == BXVD_SHT_REL )
1055         return i;
1056   }
1057 
1058   return 0;
1059}
1060
1061/* Process a single RELA section.  This function processes
1062 * (applies) all records in the specified RELA section.
1063 *
1064 * Assumes: the sections referenced by prog_index and rel_index have
1065 * been read into memory (and are in section_data[]).
1066 *
1067 */
1068static void BXVD_P_Relf_DoRelocationA(ElfInfo *info, 
1069                                      int32_t prog_index, 
1070                                      int32_t rel_index)
1071{
1072   uint8_t    *data;
1073   int32_t    count;        /* Entries in RELA section         */
1074   int32_t    type;         /* RELA entry type                       */
1075   int32_t    sym;          /* RELA entry symbol index         */
1076   int32_t    i;
1077   uint32_t   offset;
1078   uint32_t   new_pc;
1079   Bxvd_Elf32_Sym  *symbol; /* Symbol referenced by entry      */
1080   Bxvd_Elf32_Shdr *prog;   /* Program section being relocated */
1081   Bxvd_Elf32_Shdr *rel;    /* RELA section being interpreted  */
1082   Bxvd_Elf32_Rela *entry;  /* RELA entry                      */
1083
1084   prog  = info->section_header + prog_index;
1085   rel   = info->section_header + rel_index;
1086   count = rel->sh_size / sizeof(Bxvd_Elf32_Rela);
1087         
1088   entry = (Bxvd_Elf32_Rela *)(info->section_data[rel_index]);
1089   for (i = 0; i < count; i++)
1090   {
1091      BXVD_P_Relf_Get32(info->swap_required, entry->r_offset);
1092      BXVD_P_Relf_Get32(info->swap_required, entry->r_info);
1093      BXVD_P_Relf_Get32(info->swap_required, entry->r_addend);
1094                               
1095      type = BXVD_ELF32_R_TYPE(entry->r_info);
1096      sym  = BXVD_ELF32_R_SYM (entry->r_info);
1097                               
1098      /* Compute the offset into the 'prog' section at which
1099       * the fixup occurs.  We also need to know the new
1100       *         (relocated) PC of this location, as well as a pointer
1101       *         to the actual data to be changed.
1102       */
1103      offset = entry->r_offset - prog->sh_addr;
1104      data       = info->section_data    [ prog_index ] + offset;
1105      new_pc =  info->new_section_base[ prog_index ] + offset;
1106                                       
1107      /*         Determine which symbol is being referenced. */
1108      symbol = info->symtab + sym;
1109                       
1110      BXVD_P_Relf_Fixup(data,
1111                        new_pc,
1112                        symbol->st_value, 
1113                        type, 
1114                        entry->r_addend);
1115                       
1116      entry++;
1117   }
1118}
1119
1120/* Perform a single relocation fixup.  This is a modified copy of
1121 * the original function from Metaware, and handles the ARC-specific
1122 * types from RELA section entries.
1123 *
1124 * I have no idea whether any of this is correct or not; all questions
1125 * should be refered to Metaware.
1126 */
1127static void BXVD_P_Relf_Fixup(uint8_t *data,
1128                              unsigned pc, 
1129                              unsigned targetAddress, 
1130                              int32_t type, 
1131                              int32_t addend)
1132{
1133   int32_t  t = targetAddress + addend;
1134   int32_t  disp;
1135   int32_t  I0 = 0, I1 = 1, I2 = 2, I3 = 3;
1136   int32_t  W0 = 0, W1 = 1, W2 = 2;
1137   int32_t  S0 = 0, S1 = 1;
1138   uint32_t w = 0;
1139
1140   switch ( type )
1141   {
1142      case R_ARC_8:
1143         *data = (uint8_t)t;
1144         break;
1145      case R_ARC_16:
1146         data[S0] = (uint8_t)(t & 0xFF);
1147         data[S1] = (uint8_t)(t >> 8);
1148         break;
1149      case R_ARC_24:
1150         data[W0] = (uint8_t)(t & 0xFF);
1151         data[W1] = (uint8_t)(t >> 8);
1152         data[W2] = (uint8_t)(t >> 16);
1153         break;
1154      case R_ARC_32:
1155         data[I0] = (uint8_t)(t & 0xFF);
1156         data[I1] = (uint8_t)(t >> 8);
1157         data[I2] = (uint8_t)(t >> 16);
1158         data[I3] = (uint8_t)(t >> 24);
1159         break;
1160      case R_ARC_B26:
1161         if (t > 0x03FFFFFF || t < -0x04000000)
1162            BDBG_ERR(("target out of range at pc=%08X", pc));
1163         else if ( t & 3 )
1164            BDBG_ERR(("target needs to be word-aligned at pc=%08X", pc));
1165         w = data[3] << 24;
1166         w |= (t >> 2) & 0x00FFFFFF;
1167         data[I0] = (uint8_t)(w & 0xFF);
1168         data[I1] = (uint8_t)(w >> 8);
1169         data[I2] = (uint8_t)(w >> 16);
1170         data[I3] = (uint8_t)(w >> 24);
1171         break;
1172      case R_ARC_B22_PCREL:
1173         disp = t - pc - 4;
1174         if ( (disp & 3) != 0 )
1175            BDBG_ERR(("fixup at PC 0x%08X requires a word-aligned displacement", 
1176                      pc));
1177         if (disp >> 21 != 0 && disp >> 21 != -1)
1178            BDBG_ERR(("PC-relative fixup at 0x%08X is out of range", pc));
1179         disp <<= 5;
1180         disp &= 0x07FFFF80;       
1181         w = ((data[3] & 0xF8) << 24) + (data[0] & 0x7F);
1182         w |= disp;
1183         data[I0] = (uint8_t)(w & 0xFF);
1184         data[I1] = (uint8_t)(w >> 8);
1185         data[I2] = (uint8_t)(w >> 16);
1186         data[I3] = (uint8_t)(w >> 24);
1187         break;
1188      case R_ARC_H30:
1189         w = t >> 2;
1190         data[I0] = (uint8_t)(w & 0xFF);
1191         data[I1] = (uint8_t)(w >> 8);
1192         data[I2] = (uint8_t)(w >> 16);
1193         data[I3] = (uint8_t)(w >> 24);
1194         break;
1195      case R_ARC_N8:
1196         *data = (uint8_t)(addend - targetAddress);
1197         break;
1198      case R_ARC_N16:
1199         w = addend - targetAddress;
1200         data[S0] = (uint8_t)(w & 0xFF);
1201         data[S1] = (uint8_t)(w >> 8);
1202         break;
1203      case R_ARC_N24:
1204         w = addend - targetAddress;
1205         data[W0] = (uint8_t)(w & 0xFF);
1206         data[W1] = (uint8_t)(w >> 8);
1207         data[W2] = (uint8_t)(w >> 16);
1208         break;
1209      case R_ARC_N32:
1210         w = addend - targetAddress;
1211         data[I0] = (uint8_t)(w & 0xFF);
1212         data[I1] = (uint8_t)(w >> 8);
1213         data[I2] = (uint8_t)(w >> 16);
1214         data[I3] = (uint8_t)(w >> 24);
1215         break;
1216      case R_ARC_SDA:
1217         /* 9-bit SDA. Should require no change */
1218         break;
1219      case R_ARC_SECTOFF:
1220         /* 32-bit SDA. Should require no change */
1221         break;
1222      case R_ARC_NONE:
1223         /* It happens in __xcheck. Don't understand why.*/
1224         break;
1225      default:
1226         BDBG_ERR(("unexpected fixup type %d (0x%08X) at PC 0x%08X", type,type,pc));
1227         break; 
1228   }
1229}
1230
Note: See TracBrowser for help on using the repository browser.