Back to index

cell-binutils  2.17cvs20070401
ppcboot.c
Go to the documentation of this file.
00001 /* BFD back-end for PPCbug boot records.
00002    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006,
00003    2007 Free Software Foundation, Inc.
00004    Written by Michael Meissner, Cygnus Support, <meissner@cygnus.com>
00005 
00006 This file is part of BFD, the Binary File Descriptor library.
00007 
00008 This program is free software; you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation; either version 2 of the License, or
00011 (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program; if not, write to the Free Software
00020 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 /* This is a BFD backend which may be used to write PowerPCBug boot objects.
00023    It may only be used for output, not input.  The intention is that this may
00024    be used as an output format for objcopy in order to generate raw binary
00025    data.
00026 
00027    This is very simple.  The only complication is that the real data
00028    will start at some address X, and in some cases we will not want to
00029    include X zeroes just to get to that point.  Since the start
00030    address is not meaningful for this object file format, we use it
00031    instead to indicate the number of zeroes to skip at the start of
00032    the file.  objcopy cooperates by specially setting the start
00033    address to zero by default.  */
00034 
00035 #include "safe-ctype.h"
00036 #include "bfd.h"
00037 #include "sysdep.h"
00038 #include "libbfd.h"
00039 
00040 /* PPCbug location structure */
00041 typedef struct ppcboot_location {
00042   bfd_byte    ind;
00043   bfd_byte    head;
00044   bfd_byte    sector;
00045   bfd_byte    cylinder;
00046 } ppcboot_location_t;
00047 
00048 /* PPCbug partition table layout */
00049 typedef struct ppcboot_partition {
00050   ppcboot_location_t partition_begin;     /* partition begin */
00051   ppcboot_location_t partition_end;              /* partition end */
00052   bfd_byte           sector_begin[4];     /* 32-bit start RBA (zero-based), little endian */
00053   bfd_byte           sector_length[4];    /* 32-bit RBA count (one-based), little endian */
00054 } ppcboot_partition_t;
00055 
00056 /* PPCbug boot layout.  */
00057 typedef struct ppcboot_hdr {
00058   bfd_byte           pc_compatibility[446];      /* x86 instruction field */
00059   ppcboot_partition_t       partition[4];        /* partition information */
00060   bfd_byte           signature[2];        /* 0x55 and 0xaa */
00061   bfd_byte           entry_offset[4];     /* entry point offset, little endian */
00062   bfd_byte           length[4];           /* load image length, little endian */
00063   bfd_byte           flags;               /* flag field */
00064   bfd_byte           os_id;               /* OS_ID */
00065   char               partition_name[32];  /* partition name */
00066   bfd_byte           reserved1[470];             /* reserved */
00067 }
00068 #ifdef __GNUC__
00069   __attribute__ ((packed))
00070 #endif
00071 ppcboot_hdr_t;
00072 
00073 /* Signature bytes for last 2 bytes of the 512 byte record */
00074 #define SIGNATURE0 0x55
00075 #define SIGNATURE1 0xaa
00076 
00077 /* PowerPC boot type */
00078 #define PPC_IND 0x41
00079 
00080 /* Information needed for ppcboot header */
00081 typedef struct ppcboot_data {
00082   ppcboot_hdr_t      header;                            /* raw header */
00083   asection *sec;                          /* single section */
00084 } ppcboot_data_t;
00085 
00086 /* Any bfd we create by reading a ppcboot file has three symbols:
00087    a start symbol, an end symbol, and an absolute length symbol.  */
00088 #define PPCBOOT_SYMS 3
00089 
00090 static bfd_boolean ppcboot_mkobject PARAMS ((bfd *));
00091 static const bfd_target *ppcboot_object_p PARAMS ((bfd *));
00092 static bfd_boolean ppcboot_set_arch_mach
00093   PARAMS ((bfd *, enum bfd_architecture, unsigned long));
00094 static bfd_boolean ppcboot_get_section_contents
00095   PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
00096 static long ppcboot_get_symtab_upper_bound PARAMS ((bfd *));
00097 static char *mangle_name PARAMS ((bfd *, char *));
00098 static long ppcboot_canonicalize_symtab PARAMS ((bfd *, asymbol **));
00099 static void ppcboot_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *));
00100 static bfd_boolean ppcboot_set_section_contents
00101   PARAMS ((bfd *, asection *, const PTR, file_ptr, bfd_size_type));
00102 static bfd_boolean ppcboot_bfd_print_private_bfd_data PARAMS ((bfd *, PTR));
00103 
00104 #define ppcboot_set_tdata(abfd, ptr) ((abfd)->tdata.any = (PTR) (ptr))
00105 #define ppcboot_get_tdata(abfd) ((ppcboot_data_t *) ((abfd)->tdata.any))
00106 
00107 /* Create a ppcboot object.  Invoked via bfd_set_format.  */
00108 
00109 static bfd_boolean
00110 ppcboot_mkobject (abfd)
00111      bfd *abfd;
00112 {
00113   if (!ppcboot_get_tdata (abfd))
00114     {
00115       bfd_size_type amt = sizeof (ppcboot_data_t);
00116       ppcboot_set_tdata (abfd, bfd_zalloc (abfd, amt));
00117     }
00118 
00119   return TRUE;
00120 }
00121 
00122 
00123 /* Set the architecture to PowerPC */
00124 static bfd_boolean
00125 ppcboot_set_arch_mach (abfd, arch, machine)
00126      bfd *abfd;
00127      enum bfd_architecture arch;
00128      unsigned long machine;
00129 {
00130   if (arch == bfd_arch_unknown)
00131     arch = bfd_arch_powerpc;
00132 
00133   else if (arch != bfd_arch_powerpc)
00134     return FALSE;
00135 
00136   return bfd_default_set_arch_mach (abfd, arch, machine);
00137 }
00138 
00139 
00140 /* Any file may be considered to be a ppcboot file, provided the target
00141    was not defaulted.  That is, it must be explicitly specified as
00142    being ppcboot.  */
00143 
00144 static const bfd_target *
00145 ppcboot_object_p (abfd)
00146      bfd *abfd;
00147 {
00148   struct stat statbuf;
00149   asection *sec;
00150   ppcboot_hdr_t hdr;
00151   size_t i;
00152   ppcboot_data_t *tdata;
00153   flagword flags;
00154 
00155   BFD_ASSERT (sizeof (ppcboot_hdr_t) == 1024);
00156 
00157   if (abfd->target_defaulted)
00158     {
00159       bfd_set_error (bfd_error_wrong_format);
00160       return NULL;
00161     }
00162 
00163   /* Find the file size.  */
00164   if (bfd_stat (abfd, &statbuf) < 0)
00165     {
00166       bfd_set_error (bfd_error_system_call);
00167       return NULL;
00168     }
00169 
00170   if ((size_t) statbuf.st_size < sizeof (ppcboot_hdr_t))
00171     {
00172       bfd_set_error (bfd_error_wrong_format);
00173       return NULL;
00174     }
00175 
00176   if (bfd_bread ((PTR) &hdr, (bfd_size_type) sizeof (hdr), abfd)
00177       != sizeof (hdr))
00178     {
00179       if (bfd_get_error () != bfd_error_system_call)
00180        bfd_set_error (bfd_error_wrong_format);
00181 
00182       return NULL;
00183     }
00184 
00185   /* Now do some basic checks.  */
00186   for (i = 0; i < sizeof (hdr.pc_compatibility); i++)
00187     if (hdr.pc_compatibility[i])
00188       {
00189        bfd_set_error (bfd_error_wrong_format);
00190        return NULL;
00191       }
00192 
00193   if (hdr.signature[0] != SIGNATURE0 || hdr.signature[1] != SIGNATURE1)
00194     {
00195       bfd_set_error (bfd_error_wrong_format);
00196       return NULL;
00197     }
00198 
00199   if (hdr.partition[0].partition_end.ind != PPC_IND)
00200     {
00201       bfd_set_error (bfd_error_wrong_format);
00202       return NULL;
00203     }
00204 
00205   abfd->symcount = PPCBOOT_SYMS;
00206 
00207   /* One data section.  */
00208   flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_CODE | SEC_HAS_CONTENTS;
00209   sec = bfd_make_section_with_flags (abfd, ".data", flags);
00210   if (sec == NULL)
00211     return NULL;
00212   sec->vma = 0;
00213   sec->size = statbuf.st_size - sizeof (ppcboot_hdr_t);
00214   sec->filepos = sizeof (ppcboot_hdr_t);
00215 
00216   ppcboot_mkobject (abfd);
00217   tdata = ppcboot_get_tdata (abfd);
00218   tdata->sec = sec;
00219   memcpy ((PTR) &tdata->header, (PTR) &hdr, sizeof (ppcboot_hdr_t));
00220 
00221   ppcboot_set_arch_mach (abfd, bfd_arch_powerpc, 0L);
00222   return abfd->xvec;
00223 }
00224 
00225 #define ppcboot_close_and_cleanup _bfd_generic_close_and_cleanup
00226 #define ppcboot_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
00227 #define ppcboot_new_section_hook _bfd_generic_new_section_hook
00228 
00229 
00230 /* Get contents of the only section.  */
00231 
00232 static bfd_boolean
00233 ppcboot_get_section_contents (abfd, section, location, offset, count)
00234      bfd *abfd;
00235      asection *section ATTRIBUTE_UNUSED;
00236      PTR location;
00237      file_ptr offset;
00238      bfd_size_type count;
00239 {
00240   if (bfd_seek (abfd, offset + (file_ptr) sizeof (ppcboot_hdr_t), SEEK_SET) != 0
00241       || bfd_bread (location, count, abfd) != count)
00242     return FALSE;
00243   return TRUE;
00244 }
00245 
00246 
00247 /* Return the amount of memory needed to read the symbol table.  */
00248 
00249 static long
00250 ppcboot_get_symtab_upper_bound (abfd)
00251      bfd *abfd ATTRIBUTE_UNUSED;
00252 {
00253   return (PPCBOOT_SYMS + 1) * sizeof (asymbol *);
00254 }
00255 
00256 
00257 /* Create a symbol name based on the bfd's filename.  */
00258 
00259 static char *
00260 mangle_name (abfd, suffix)
00261      bfd *abfd;
00262      char *suffix;
00263 {
00264   bfd_size_type size;
00265   char *buf;
00266   char *p;
00267 
00268   size = (strlen (bfd_get_filename (abfd))
00269          + strlen (suffix)
00270          + sizeof "_ppcboot__");
00271 
00272   buf = (char *) bfd_alloc (abfd, size);
00273   if (buf == NULL)
00274     return "";
00275 
00276   sprintf (buf, "_ppcboot_%s_%s", bfd_get_filename (abfd), suffix);
00277 
00278   /* Change any non-alphanumeric characters to underscores.  */
00279   for (p = buf; *p; p++)
00280     if (! ISALNUM (*p))
00281       *p = '_';
00282 
00283   return buf;
00284 }
00285 
00286 
00287 /* Return the symbol table.  */
00288 
00289 static long
00290 ppcboot_canonicalize_symtab (abfd, alocation)
00291      bfd *abfd;
00292      asymbol **alocation;
00293 {
00294   asection *sec = ppcboot_get_tdata (abfd)->sec;
00295   asymbol *syms;
00296   unsigned int i;
00297   bfd_size_type amt = PPCBOOT_SYMS * sizeof (asymbol);
00298 
00299   syms = (asymbol *) bfd_alloc (abfd, amt);
00300   if (syms == NULL)
00301     return FALSE;
00302 
00303   /* Start symbol.  */
00304   syms[0].the_bfd = abfd;
00305   syms[0].name = mangle_name (abfd, "start");
00306   syms[0].value = 0;
00307   syms[0].flags = BSF_GLOBAL;
00308   syms[0].section = sec;
00309   syms[0].udata.p = NULL;
00310 
00311   /* End symbol.  */
00312   syms[1].the_bfd = abfd;
00313   syms[1].name = mangle_name (abfd, "end");
00314   syms[1].value = sec->size;
00315   syms[1].flags = BSF_GLOBAL;
00316   syms[1].section = sec;
00317   syms[1].udata.p = NULL;
00318 
00319   /* Size symbol.  */
00320   syms[2].the_bfd = abfd;
00321   syms[2].name = mangle_name (abfd, "size");
00322   syms[2].value = sec->size;
00323   syms[2].flags = BSF_GLOBAL;
00324   syms[2].section = bfd_abs_section_ptr;
00325   syms[2].udata.p = NULL;
00326 
00327   for (i = 0; i < PPCBOOT_SYMS; i++)
00328     *alocation++ = syms++;
00329   *alocation = NULL;
00330 
00331   return PPCBOOT_SYMS;
00332 }
00333 
00334 #define ppcboot_make_empty_symbol _bfd_generic_make_empty_symbol
00335 #define ppcboot_print_symbol _bfd_nosymbols_print_symbol
00336 
00337 /* Get information about a symbol.  */
00338 
00339 static void
00340 ppcboot_get_symbol_info (ignore_abfd, symbol, ret)
00341      bfd *ignore_abfd ATTRIBUTE_UNUSED;
00342      asymbol *symbol;
00343      symbol_info *ret;
00344 {
00345   bfd_symbol_info (symbol, ret);
00346 }
00347 
00348 #define ppcboot_bfd_is_target_special_symbol \
00349   ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
00350 #define ppcboot_bfd_is_local_label_name bfd_generic_is_local_label_name
00351 #define ppcboot_get_lineno _bfd_nosymbols_get_lineno
00352 #define ppcboot_find_nearest_line _bfd_nosymbols_find_nearest_line
00353 #define ppcboot_find_inliner_info _bfd_nosymbols_find_inliner_info
00354 #define ppcboot_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
00355 #define ppcboot_read_minisymbols _bfd_generic_read_minisymbols
00356 #define ppcboot_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
00357 
00358 /* Write section contents of a ppcboot file.  */
00359 
00360 static bfd_boolean
00361 ppcboot_set_section_contents (abfd, sec, data, offset, size)
00362      bfd *abfd;
00363      asection *sec;
00364      const PTR data;
00365      file_ptr offset;
00366      bfd_size_type size;
00367 {
00368   if (! abfd->output_has_begun)
00369     {
00370       bfd_vma low;
00371       asection *s;
00372 
00373       /* The lowest section VMA sets the virtual address of the start
00374          of the file.  We use the set the file position of all the
00375          sections.  */
00376       low = abfd->sections->vma;
00377       for (s = abfd->sections->next; s != NULL; s = s->next)
00378        if (s->vma < low)
00379          low = s->vma;
00380 
00381       for (s = abfd->sections; s != NULL; s = s->next)
00382        s->filepos = s->vma - low;
00383 
00384       abfd->output_has_begun = TRUE;
00385     }
00386 
00387   return _bfd_generic_set_section_contents (abfd, sec, data, offset, size);
00388 }
00389 
00390 
00391 static int
00392 ppcboot_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
00393                      struct bfd_link_info *info ATTRIBUTE_UNUSED)
00394 {
00395   return sizeof (ppcboot_hdr_t);
00396 }
00397 
00398 
00399 /* Print out the program headers.  */
00400 
00401 static bfd_boolean
00402 ppcboot_bfd_print_private_bfd_data (abfd, farg)
00403      bfd *abfd;
00404      PTR farg;
00405 {
00406   FILE *f = (FILE *)farg;
00407   ppcboot_data_t *tdata = ppcboot_get_tdata (abfd);
00408   long entry_offset = bfd_getl_signed_32 ((PTR) tdata->header.entry_offset);
00409   long length = bfd_getl_signed_32 ((PTR) tdata->header.length);
00410   int i;
00411 
00412   fprintf (f, _("\nppcboot header:\n"));
00413   fprintf (f, _("Entry offset        = 0x%.8lx (%ld)\n"), entry_offset, entry_offset);
00414   fprintf (f, _("Length              = 0x%.8lx (%ld)\n"), length, length);
00415 
00416   if (tdata->header.flags)
00417     fprintf (f, _("Flag field          = 0x%.2x\n"), tdata->header.flags);
00418 
00419   if (tdata->header.os_id)
00420     fprintf (f, "OS_ID               = 0x%.2x\n", tdata->header.os_id);
00421 
00422   if (tdata->header.partition_name)
00423     fprintf (f, _("Partition name      = \"%s\"\n"), tdata->header.partition_name);
00424 
00425   for (i = 0; i < 4; i++)
00426     {
00427       long sector_begin  = bfd_getl_signed_32 ((PTR) tdata->header.partition[i].sector_begin);
00428       long sector_length = bfd_getl_signed_32 ((PTR) tdata->header.partition[i].sector_length);
00429 
00430       /* Skip all 0 entries */
00431       if (!tdata->header.partition[i].partition_begin.ind
00432          && !tdata->header.partition[i].partition_begin.head
00433          && !tdata->header.partition[i].partition_begin.sector
00434          && !tdata->header.partition[i].partition_begin.cylinder
00435          && !tdata->header.partition[i].partition_end.ind
00436          && !tdata->header.partition[i].partition_end.head
00437          && !tdata->header.partition[i].partition_end.sector
00438          && !tdata->header.partition[i].partition_end.cylinder
00439          && !sector_begin && !sector_length)
00440        continue;
00441 
00442       fprintf (f, _("\nPartition[%d] start  = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
00443               tdata->header.partition[i].partition_begin.ind,
00444               tdata->header.partition[i].partition_begin.head,
00445               tdata->header.partition[i].partition_begin.sector,
00446               tdata->header.partition[i].partition_begin.cylinder);
00447 
00448       fprintf (f, _("Partition[%d] end    = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
00449               tdata->header.partition[i].partition_end.ind,
00450               tdata->header.partition[i].partition_end.head,
00451               tdata->header.partition[i].partition_end.sector,
00452               tdata->header.partition[i].partition_end.cylinder);
00453 
00454       fprintf (f, _("Partition[%d] sector = 0x%.8lx (%ld)\n"), i, sector_begin, sector_begin);
00455       fprintf (f, _("Partition[%d] length = 0x%.8lx (%ld)\n"), i, sector_length, sector_length);
00456     }
00457 
00458   fprintf (f, "\n");
00459   return TRUE;
00460 }
00461 
00462 
00463 #define ppcboot_bfd_get_relocated_section_contents \
00464   bfd_generic_get_relocated_section_contents
00465 #define ppcboot_bfd_relax_section bfd_generic_relax_section
00466 #define ppcboot_bfd_gc_sections bfd_generic_gc_sections
00467 #define ppcboot_bfd_merge_sections bfd_generic_merge_sections
00468 #define ppcboot_bfd_is_group_section bfd_generic_is_group_section
00469 #define ppcboot_bfd_discard_group bfd_generic_discard_group
00470 #define ppcboot_section_already_linked \
00471   _bfd_generic_section_already_linked
00472 #define ppcboot_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
00473 #define ppcboot_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
00474 #define ppcboot_bfd_link_add_symbols _bfd_generic_link_add_symbols
00475 #define ppcboot_bfd_link_just_syms _bfd_generic_link_just_syms
00476 #define ppcboot_bfd_final_link _bfd_generic_final_link
00477 #define ppcboot_bfd_link_split_section _bfd_generic_link_split_section
00478 #define ppcboot_get_section_contents_in_window \
00479   _bfd_generic_get_section_contents_in_window
00480 
00481 #define ppcboot_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data
00482 #define ppcboot_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
00483 #define ppcboot_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data
00484 #define ppcboot_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
00485 #define ppcboot_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
00486 #define ppcboot_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
00487 #define ppcboot_bfd_print_private_bfd_dat ppcboot_bfd_print_private_bfd_data
00488 
00489 const bfd_target ppcboot_vec =
00490 {
00491   "ppcboot",                /* name */
00492   bfd_target_unknown_flavour,      /* flavour */
00493   BFD_ENDIAN_BIG,           /* byteorder is big endian for code */
00494   BFD_ENDIAN_LITTLE,        /* header_byteorder */
00495   EXEC_P,                   /* object_flags */
00496   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
00497    | SEC_ROM | SEC_HAS_CONTENTS), /* section_flags */
00498   0,                        /* symbol_leading_char */
00499   ' ',                      /* ar_pad_char */
00500   16,                       /* ar_max_namelen */
00501   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
00502   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
00503   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* data */
00504   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
00505   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
00506   bfd_getl16, bfd_getl_signed_16, bfd_putl16,    /* hdrs */
00507   {                         /* bfd_check_format */
00508     _bfd_dummy_target,
00509     ppcboot_object_p,              /* bfd_check_format */
00510     _bfd_dummy_target,
00511     _bfd_dummy_target,
00512   },
00513   {                         /* bfd_set_format */
00514     bfd_false,
00515     ppcboot_mkobject,
00516     bfd_false,
00517     bfd_false,
00518   },
00519   {                         /* bfd_write_contents */
00520     bfd_false,
00521     bfd_true,
00522     bfd_false,
00523     bfd_false,
00524   },
00525 
00526   BFD_JUMP_TABLE_GENERIC (ppcboot),
00527   BFD_JUMP_TABLE_COPY (ppcboot),
00528   BFD_JUMP_TABLE_CORE (_bfd_nocore),
00529   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
00530   BFD_JUMP_TABLE_SYMBOLS (ppcboot),
00531   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
00532   BFD_JUMP_TABLE_WRITE (ppcboot),
00533   BFD_JUMP_TABLE_LINK (ppcboot),
00534   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
00535 
00536   NULL,
00537 
00538   NULL
00539 };