Home | History | Annotate | Download | only in bfd
      1 /* BFD back-end for PPCbug boot records.
      2    Copyright (C) 1996-2014 Free Software Foundation, Inc.
      3    Written by Michael Meissner, Cygnus Support, <meissner (at) cygnus.com>
      4 
      5    This file is part of BFD, the Binary File Descriptor library.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program; if not, write to the Free Software
     19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20    MA 02110-1301, USA.  */
     21 
     22 
     23 /* This is a BFD backend which may be used to write PowerPCBug boot objects.
     24    It may only be used for output, not input.  The intention is that this may
     25    be used as an output format for objcopy in order to generate raw binary
     26    data.
     27 
     28    This is very simple.  The only complication is that the real data
     29    will start at some address X, and in some cases we will not want to
     30    include X zeroes just to get to that point.  Since the start
     31    address is not meaningful for this object file format, we use it
     32    instead to indicate the number of zeroes to skip at the start of
     33    the file.  objcopy cooperates by specially setting the start
     34    address to zero by default.  */
     35 
     36 #include "sysdep.h"
     37 #include "safe-ctype.h"
     38 #include "bfd.h"
     39 #include "libbfd.h"
     40 
     41 /* PPCbug location structure */
     42 typedef struct ppcboot_location
     43 {
     44   bfd_byte	ind;
     45   bfd_byte	head;
     46   bfd_byte	sector;
     47   bfd_byte	cylinder;
     48 } ppcboot_location_t;
     49 
     50 /* PPCbug partition table layout */
     51 typedef struct ppcboot_partition
     52 {
     53   ppcboot_location_t	partition_begin;	/* partition begin */
     54   ppcboot_location_t	partition_end;		/* partition end */
     55   bfd_byte		sector_begin[4];	/* 32-bit start RBA (zero-based), little endian */
     56   bfd_byte		sector_length[4];	/* 32-bit RBA count (one-based), little endian */
     57 } ppcboot_partition_t;
     58 
     59 /* PPCbug boot layout.  */
     60 typedef struct ppcboot_hdr
     61 {
     62   bfd_byte		pc_compatibility[446];	/* x86 instruction field */
     63   ppcboot_partition_t	partition[4];		/* partition information */
     64   bfd_byte		signature[2];		/* 0x55 and 0xaa */
     65   bfd_byte		entry_offset[4];	/* entry point offset, little endian */
     66   bfd_byte		length[4];		/* load image length, little endian */
     67   bfd_byte		flags;			/* flag field */
     68   bfd_byte		os_id;			/* OS_ID */
     69   char			partition_name[32];	/* partition name */
     70   bfd_byte		reserved1[470];		/* reserved */
     71 }
     72 #ifdef __GNUC__
     73   __attribute__ ((packed))
     74 #endif
     75 ppcboot_hdr_t;
     76 
     77 /* Signature bytes for last 2 bytes of the 512 byte record */
     78 #define SIGNATURE0 0x55
     79 #define SIGNATURE1 0xaa
     80 
     81 /* PowerPC boot type */
     82 #define PPC_IND 0x41
     83 
     84 /* Information needed for ppcboot header */
     85 typedef struct ppcboot_data
     86 {
     87   ppcboot_hdr_t	header;				/* raw header */
     88   asection *sec;				/* single section */
     89 } ppcboot_data_t;
     90 
     91 /* Any bfd we create by reading a ppcboot file has three symbols:
     92    a start symbol, an end symbol, and an absolute length symbol.  */
     93 #define PPCBOOT_SYMS 3
     94 
     95 #define ppcboot_set_tdata(abfd, ptr) ((abfd)->tdata.any = (ptr))
     96 #define ppcboot_get_tdata(abfd) ((ppcboot_data_t *) ((abfd)->tdata.any))
     97 
     98 /* Create a ppcboot object.  Invoked via bfd_set_format.  */
    100 
    101 static bfd_boolean
    102 ppcboot_mkobject (bfd *abfd)
    103 {
    104   if (!ppcboot_get_tdata (abfd))
    105     {
    106       bfd_size_type amt = sizeof (ppcboot_data_t);
    107       ppcboot_set_tdata (abfd, bfd_zalloc (abfd, amt));
    108     }
    109 
    110   return TRUE;
    111 }
    112 
    113 
    114 /* Set the architecture to PowerPC */
    116 static bfd_boolean
    117 ppcboot_set_arch_mach (bfd *abfd,
    118 		       enum bfd_architecture arch,
    119 		       unsigned long machine)
    120 {
    121   if (arch == bfd_arch_unknown)
    122     arch = bfd_arch_powerpc;
    123 
    124   else if (arch != bfd_arch_powerpc)
    125     return FALSE;
    126 
    127   return bfd_default_set_arch_mach (abfd, arch, machine);
    128 }
    129 
    130 
    131 /* Any file may be considered to be a ppcboot file, provided the target
    133    was not defaulted.  That is, it must be explicitly specified as
    134    being ppcboot.  */
    135 
    136 static const bfd_target *
    137 ppcboot_object_p (bfd *abfd)
    138 {
    139   struct stat statbuf;
    140   asection *sec;
    141   ppcboot_hdr_t hdr;
    142   size_t i;
    143   ppcboot_data_t *tdata;
    144   flagword flags;
    145 
    146   BFD_ASSERT (sizeof (ppcboot_hdr_t) == 1024);
    147 
    148   if (abfd->target_defaulted)
    149     {
    150       bfd_set_error (bfd_error_wrong_format);
    151       return NULL;
    152     }
    153 
    154   /* Find the file size.  */
    155   if (bfd_stat (abfd, &statbuf) < 0)
    156     {
    157       bfd_set_error (bfd_error_system_call);
    158       return NULL;
    159     }
    160 
    161   if ((size_t) statbuf.st_size < sizeof (ppcboot_hdr_t))
    162     {
    163       bfd_set_error (bfd_error_wrong_format);
    164       return NULL;
    165     }
    166 
    167   if (bfd_bread (&hdr, (bfd_size_type) sizeof (hdr), abfd)
    168       != sizeof (hdr))
    169     {
    170       if (bfd_get_error () != bfd_error_system_call)
    171 	bfd_set_error (bfd_error_wrong_format);
    172 
    173       return NULL;
    174     }
    175 
    176   /* Now do some basic checks.  */
    177   for (i = 0; i < sizeof (hdr.pc_compatibility); i++)
    178     if (hdr.pc_compatibility[i])
    179       {
    180 	bfd_set_error (bfd_error_wrong_format);
    181 	return NULL;
    182       }
    183 
    184   if (hdr.signature[0] != SIGNATURE0 || hdr.signature[1] != SIGNATURE1)
    185     {
    186       bfd_set_error (bfd_error_wrong_format);
    187       return NULL;
    188     }
    189 
    190   if (hdr.partition[0].partition_end.ind != PPC_IND)
    191     {
    192       bfd_set_error (bfd_error_wrong_format);
    193       return NULL;
    194     }
    195 
    196   abfd->symcount = PPCBOOT_SYMS;
    197 
    198   /* One data section.  */
    199   flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_CODE | SEC_HAS_CONTENTS;
    200   sec = bfd_make_section_with_flags (abfd, ".data", flags);
    201   if (sec == NULL)
    202     return NULL;
    203   sec->vma = 0;
    204   sec->size = statbuf.st_size - sizeof (ppcboot_hdr_t);
    205   sec->filepos = sizeof (ppcboot_hdr_t);
    206 
    207   ppcboot_mkobject (abfd);
    208   tdata = ppcboot_get_tdata (abfd);
    209   tdata->sec = sec;
    210   memcpy (&tdata->header, &hdr, sizeof (ppcboot_hdr_t));
    211 
    212   ppcboot_set_arch_mach (abfd, bfd_arch_powerpc, 0L);
    213   return abfd->xvec;
    214 }
    215 
    216 #define ppcboot_close_and_cleanup _bfd_generic_close_and_cleanup
    217 #define ppcboot_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
    218 #define ppcboot_new_section_hook _bfd_generic_new_section_hook
    219 
    220 
    221 /* Get contents of the only section.  */
    223 
    224 static bfd_boolean
    225 ppcboot_get_section_contents (bfd *abfd,
    226 			      asection *section ATTRIBUTE_UNUSED,
    227 			      void * location,
    228 			      file_ptr offset,
    229 			      bfd_size_type count)
    230 {
    231   if (bfd_seek (abfd, offset + (file_ptr) sizeof (ppcboot_hdr_t), SEEK_SET) != 0
    232       || bfd_bread (location, count, abfd) != count)
    233     return FALSE;
    234   return TRUE;
    235 }
    236 
    237 
    238 /* Return the amount of memory needed to read the symbol table.  */
    240 
    241 static long
    242 ppcboot_get_symtab_upper_bound (bfd *abfd ATTRIBUTE_UNUSED)
    243 {
    244   return (PPCBOOT_SYMS + 1) * sizeof (asymbol *);
    245 }
    246 
    247 
    248 /* Create a symbol name based on the bfd's filename.  */
    250 
    251 static char *
    252 mangle_name (bfd *abfd, char *suffix)
    253 {
    254   bfd_size_type size;
    255   char *buf;
    256   char *p;
    257 
    258   size = (strlen (bfd_get_filename (abfd))
    259 	  + strlen (suffix)
    260 	  + sizeof "_ppcboot__");
    261 
    262   buf = (char *) bfd_alloc (abfd, size);
    263   if (buf == NULL)
    264     return "";
    265 
    266   sprintf (buf, "_ppcboot_%s_%s", bfd_get_filename (abfd), suffix);
    267 
    268   /* Change any non-alphanumeric characters to underscores.  */
    269   for (p = buf; *p; p++)
    270     if (! ISALNUM (*p))
    271       *p = '_';
    272 
    273   return buf;
    274 }
    275 
    276 
    277 /* Return the symbol table.  */
    279 
    280 static long
    281 ppcboot_canonicalize_symtab (bfd *abfd, asymbol **alocation)
    282 {
    283   asection *sec = ppcboot_get_tdata (abfd)->sec;
    284   asymbol *syms;
    285   unsigned int i;
    286   bfd_size_type amt = PPCBOOT_SYMS * sizeof (asymbol);
    287 
    288   syms = (asymbol *) bfd_alloc (abfd, amt);
    289   if (syms == NULL)
    290     return FALSE;
    291 
    292   /* Start symbol.  */
    293   syms[0].the_bfd = abfd;
    294   syms[0].name = mangle_name (abfd, "start");
    295   syms[0].value = 0;
    296   syms[0].flags = BSF_GLOBAL;
    297   syms[0].section = sec;
    298   syms[0].udata.p = NULL;
    299 
    300   /* End symbol.  */
    301   syms[1].the_bfd = abfd;
    302   syms[1].name = mangle_name (abfd, "end");
    303   syms[1].value = sec->size;
    304   syms[1].flags = BSF_GLOBAL;
    305   syms[1].section = sec;
    306   syms[1].udata.p = NULL;
    307 
    308   /* Size symbol.  */
    309   syms[2].the_bfd = abfd;
    310   syms[2].name = mangle_name (abfd, "size");
    311   syms[2].value = sec->size;
    312   syms[2].flags = BSF_GLOBAL;
    313   syms[2].section = bfd_abs_section_ptr;
    314   syms[2].udata.p = NULL;
    315 
    316   for (i = 0; i < PPCBOOT_SYMS; i++)
    317     *alocation++ = syms++;
    318   *alocation = NULL;
    319 
    320   return PPCBOOT_SYMS;
    321 }
    322 
    323 #define ppcboot_make_empty_symbol _bfd_generic_make_empty_symbol
    324 #define ppcboot_print_symbol _bfd_nosymbols_print_symbol
    325 
    326 /* Get information about a symbol.  */
    327 
    328 static void
    329 ppcboot_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
    330 			 asymbol *symbol,
    331 			 symbol_info *ret)
    332 {
    333   bfd_symbol_info (symbol, ret);
    334 }
    335 
    336 #define ppcboot_bfd_is_target_special_symbol \
    337   ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
    338 #define ppcboot_bfd_is_local_label_name bfd_generic_is_local_label_name
    339 #define ppcboot_get_lineno _bfd_nosymbols_get_lineno
    340 #define ppcboot_find_nearest_line _bfd_nosymbols_find_nearest_line
    341 #define ppcboot_find_line _bfd_nosymbols_find_line
    342 #define ppcboot_find_inliner_info _bfd_nosymbols_find_inliner_info
    343 #define ppcboot_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
    344 #define ppcboot_read_minisymbols _bfd_generic_read_minisymbols
    345 #define ppcboot_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
    346 
    347 /* Write section contents of a ppcboot file.  */
    349 
    350 static bfd_boolean
    351 ppcboot_set_section_contents (bfd *abfd,
    352 			      asection *sec,
    353 			      const void * data,
    354 			      file_ptr offset,
    355 			      bfd_size_type size)
    356 {
    357   if (! abfd->output_has_begun)
    358     {
    359       bfd_vma low;
    360       asection *s;
    361 
    362       /* The lowest section VMA sets the virtual address of the start
    363          of the file.  We use the set the file position of all the
    364          sections.  */
    365       low = abfd->sections->vma;
    366       for (s = abfd->sections->next; s != NULL; s = s->next)
    367 	if (s->vma < low)
    368 	  low = s->vma;
    369 
    370       for (s = abfd->sections; s != NULL; s = s->next)
    371 	s->filepos = s->vma - low;
    372 
    373       abfd->output_has_begun = TRUE;
    374     }
    375 
    376   return _bfd_generic_set_section_contents (abfd, sec, data, offset, size);
    377 }
    378 
    379 
    380 static int
    382 ppcboot_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
    383 			struct bfd_link_info *info ATTRIBUTE_UNUSED)
    384 {
    385   return sizeof (ppcboot_hdr_t);
    386 }
    387 
    388 
    389 /* Print out the program headers.  */
    391 
    392 static bfd_boolean
    393 ppcboot_bfd_print_private_bfd_data (bfd *abfd, void * farg)
    394 {
    395   FILE *f = (FILE *)farg;
    396   ppcboot_data_t *tdata = ppcboot_get_tdata (abfd);
    397   long entry_offset = bfd_getl_signed_32 (tdata->header.entry_offset);
    398   long length = bfd_getl_signed_32 (tdata->header.length);
    399   int i;
    400 
    401   fprintf (f, _("\nppcboot header:\n"));
    402   fprintf (f, _("Entry offset        = 0x%.8lx (%ld)\n"),
    403 	   (unsigned long) entry_offset, entry_offset);
    404   fprintf (f, _("Length              = 0x%.8lx (%ld)\n"),
    405 	   (unsigned long) length, length);
    406 
    407   if (tdata->header.flags)
    408     fprintf (f, _("Flag field          = 0x%.2x\n"), tdata->header.flags);
    409 
    410   if (tdata->header.os_id)
    411     fprintf (f, "OS_ID               = 0x%.2x\n", tdata->header.os_id);
    412 
    413   if (tdata->header.partition_name)
    414     fprintf (f, _("Partition name      = \"%s\"\n"), tdata->header.partition_name);
    415 
    416   for (i = 0; i < 4; i++)
    417     {
    418       long sector_begin  = bfd_getl_signed_32 (tdata->header.partition[i].sector_begin);
    419       long sector_length = bfd_getl_signed_32 (tdata->header.partition[i].sector_length);
    420 
    421       /* Skip all 0 entries */
    422       if (!tdata->header.partition[i].partition_begin.ind
    423 	  && !tdata->header.partition[i].partition_begin.head
    424 	  && !tdata->header.partition[i].partition_begin.sector
    425 	  && !tdata->header.partition[i].partition_begin.cylinder
    426 	  && !tdata->header.partition[i].partition_end.ind
    427 	  && !tdata->header.partition[i].partition_end.head
    428 	  && !tdata->header.partition[i].partition_end.sector
    429 	  && !tdata->header.partition[i].partition_end.cylinder
    430 	  && !sector_begin && !sector_length)
    431 	continue;
    432 
    433       fprintf (f, _("\nPartition[%d] start  = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
    434 	       tdata->header.partition[i].partition_begin.ind,
    435 	       tdata->header.partition[i].partition_begin.head,
    436 	       tdata->header.partition[i].partition_begin.sector,
    437 	       tdata->header.partition[i].partition_begin.cylinder);
    438 
    439       fprintf (f, _("Partition[%d] end    = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
    440 	       tdata->header.partition[i].partition_end.ind,
    441 	       tdata->header.partition[i].partition_end.head,
    442 	       tdata->header.partition[i].partition_end.sector,
    443 	       tdata->header.partition[i].partition_end.cylinder);
    444 
    445       fprintf (f, _("Partition[%d] sector = 0x%.8lx (%ld)\n"),
    446 	       i, (unsigned long) sector_begin, sector_begin);
    447       fprintf (f, _("Partition[%d] length = 0x%.8lx (%ld)\n"),
    448 	       i, (unsigned long) sector_length, sector_length);
    449     }
    450 
    451   fprintf (f, "\n");
    452   return TRUE;
    453 }
    454 
    455 
    456 #define ppcboot_bfd_get_relocated_section_contents \
    458   bfd_generic_get_relocated_section_contents
    459 #define ppcboot_bfd_relax_section bfd_generic_relax_section
    460 #define ppcboot_bfd_gc_sections bfd_generic_gc_sections
    461 #define ppcboot_bfd_lookup_section_flags bfd_generic_lookup_section_flags
    462 #define ppcboot_bfd_merge_sections bfd_generic_merge_sections
    463 #define ppcboot_bfd_is_group_section bfd_generic_is_group_section
    464 #define ppcboot_bfd_discard_group bfd_generic_discard_group
    465 #define ppcboot_section_already_linked \
    466   _bfd_generic_section_already_linked
    467 #define ppcboot_bfd_define_common_symbol bfd_generic_define_common_symbol
    468 #define ppcboot_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
    469 #define ppcboot_bfd_link_add_symbols _bfd_generic_link_add_symbols
    470 #define ppcboot_bfd_link_just_syms _bfd_generic_link_just_syms
    471 #define ppcboot_bfd_copy_link_hash_symbol_type \
    472   _bfd_generic_copy_link_hash_symbol_type
    473 #define ppcboot_bfd_final_link _bfd_generic_final_link
    474 #define ppcboot_bfd_link_split_section _bfd_generic_link_split_section
    475 #define ppcboot_get_section_contents_in_window \
    476   _bfd_generic_get_section_contents_in_window
    477 
    478 #define ppcboot_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data
    479 #define ppcboot_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
    480 #define ppcboot_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data
    481 #define ppcboot_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
    482 #define ppcboot_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
    483 #define ppcboot_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
    484 #define ppcboot_bfd_print_private_bfd_dat ppcboot_bfd_print_private_bfd_data
    485 
    486 const bfd_target powerpc_boot_vec =
    487 {
    488   "ppcboot",			/* name */
    489   bfd_target_unknown_flavour,	/* flavour */
    490   BFD_ENDIAN_BIG,		/* byteorder is big endian for code */
    491   BFD_ENDIAN_LITTLE,		/* header_byteorder */
    492   EXEC_P,			/* object_flags */
    493   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
    494    | SEC_ROM | SEC_HAS_CONTENTS), /* section_flags */
    495   0,				/* symbol_leading_char */
    496   ' ',				/* ar_pad_char */
    497   16,				/* ar_max_namelen */
    498   0,				/* match priority.  */
    499   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
    500   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
    501   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* data */
    502   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
    503   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
    504   bfd_getl16, bfd_getl_signed_16, bfd_putl16,	/* hdrs */
    505   {				/* bfd_check_format */
    506     _bfd_dummy_target,
    507     ppcboot_object_p,		/* bfd_check_format */
    508     _bfd_dummy_target,
    509     _bfd_dummy_target,
    510   },
    511   {				/* bfd_set_format */
    512     bfd_false,
    513     ppcboot_mkobject,
    514     bfd_false,
    515     bfd_false,
    516   },
    517   {				/* bfd_write_contents */
    518     bfd_false,
    519     bfd_true,
    520     bfd_false,
    521     bfd_false,
    522   },
    523 
    524   BFD_JUMP_TABLE_GENERIC (ppcboot),
    525   BFD_JUMP_TABLE_COPY (ppcboot),
    526   BFD_JUMP_TABLE_CORE (_bfd_nocore),
    527   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
    528   BFD_JUMP_TABLE_SYMBOLS (ppcboot),
    529   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
    530   BFD_JUMP_TABLE_WRITE (ppcboot),
    531   BFD_JUMP_TABLE_LINK (ppcboot),
    532   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
    533 
    534   NULL,
    535 
    536   NULL
    537 };
    538