Home | History | Annotate | Line # | Download | only in bfd
      1 /* BFD back-end for PPCbug boot records.
      2    Copyright (C) 1996-2025 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 bool
    102 ppcboot_mkobject (bfd *abfd)
    103 {
    104   if (!ppcboot_get_tdata (abfd))
    105     {
    106       size_t 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 bool
    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 bfd_cleanup
    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_read (&hdr, sizeof (hdr), abfd) != sizeof (hdr))
    168     {
    169       if (bfd_get_error () != bfd_error_system_call)
    170 	bfd_set_error (bfd_error_wrong_format);
    171 
    172       return NULL;
    173     }
    174 
    175   /* Now do some basic checks.  */
    176   for (i = 0; i < sizeof (hdr.pc_compatibility); i++)
    177     if (hdr.pc_compatibility[i])
    178       {
    179 	bfd_set_error (bfd_error_wrong_format);
    180 	return NULL;
    181       }
    182 
    183   if (hdr.signature[0] != SIGNATURE0 || hdr.signature[1] != SIGNATURE1)
    184     {
    185       bfd_set_error (bfd_error_wrong_format);
    186       return NULL;
    187     }
    188 
    189   if (hdr.partition[0].partition_end.ind != PPC_IND)
    190     {
    191       bfd_set_error (bfd_error_wrong_format);
    192       return NULL;
    193     }
    194 
    195   abfd->symcount = PPCBOOT_SYMS;
    196 
    197   /* One data section.  */
    198   flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_CODE | SEC_HAS_CONTENTS;
    199   sec = bfd_make_section_with_flags (abfd, ".data", flags);
    200   if (sec == NULL)
    201     return NULL;
    202   sec->vma = 0;
    203   sec->size = statbuf.st_size - sizeof (ppcboot_hdr_t);
    204   sec->filepos = sizeof (ppcboot_hdr_t);
    205 
    206   ppcboot_mkobject (abfd);
    207   tdata = ppcboot_get_tdata (abfd);
    208   tdata->sec = sec;
    209   memcpy (&tdata->header, &hdr, sizeof (ppcboot_hdr_t));
    210 
    211   ppcboot_set_arch_mach (abfd, bfd_arch_powerpc, 0L);
    212   return _bfd_no_cleanup;
    213 }
    214 
    215 #define ppcboot_close_and_cleanup _bfd_generic_close_and_cleanup
    216 #define ppcboot_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
    217 #define ppcboot_new_section_hook _bfd_generic_new_section_hook
    218 
    219 
    220 /* Get contents of the only section.  */
    222 
    223 static bool
    224 ppcboot_get_section_contents (bfd *abfd,
    225 			      asection *section ATTRIBUTE_UNUSED,
    226 			      void * location,
    227 			      file_ptr offset,
    228 			      bfd_size_type count)
    229 {
    230   if (bfd_seek (abfd, offset + sizeof (ppcboot_hdr_t), SEEK_SET) != 0
    231       || bfd_read (location, count, abfd) != count)
    232     return false;
    233   return true;
    234 }
    235 
    236 
    237 /* Return the amount of memory needed to read the symbol table.  */
    239 
    240 static long
    241 ppcboot_get_symtab_upper_bound (bfd *abfd ATTRIBUTE_UNUSED)
    242 {
    243   return (PPCBOOT_SYMS + 1) * sizeof (asymbol *);
    244 }
    245 
    246 
    247 /* Create a symbol name based on the bfd's filename.  */
    249 
    250 static char *
    251 mangle_name (bfd *abfd, char *suffix)
    252 {
    253   bfd_size_type size;
    254   char *buf;
    255   char *p;
    256 
    257   size = (strlen (bfd_get_filename (abfd))
    258 	  + strlen (suffix)
    259 	  + sizeof "_ppcboot__");
    260 
    261   buf = (char *) bfd_alloc (abfd, size);
    262   if (buf == NULL)
    263     return "";
    264 
    265   sprintf (buf, "_ppcboot_%s_%s", bfd_get_filename (abfd), suffix);
    266 
    267   /* Change any non-alphanumeric characters to underscores.  */
    268   for (p = buf; *p; p++)
    269     if (! ISALNUM (*p))
    270       *p = '_';
    271 
    272   return buf;
    273 }
    274 
    275 
    276 /* Return the symbol table.  */
    278 
    279 static long
    280 ppcboot_canonicalize_symtab (bfd *abfd, asymbol **alocation)
    281 {
    282   asection *sec = ppcboot_get_tdata (abfd)->sec;
    283   asymbol *syms;
    284   unsigned int i;
    285   size_t amt = PPCBOOT_SYMS * sizeof (asymbol);
    286 
    287   syms = (asymbol *) bfd_alloc (abfd, amt);
    288   if (syms == NULL)
    289     return false;
    290 
    291   /* Start symbol.  */
    292   syms[0].the_bfd = abfd;
    293   syms[0].name = mangle_name (abfd, "start");
    294   syms[0].value = 0;
    295   syms[0].flags = BSF_GLOBAL;
    296   syms[0].section = sec;
    297   syms[0].udata.p = NULL;
    298 
    299   /* End symbol.  */
    300   syms[1].the_bfd = abfd;
    301   syms[1].name = mangle_name (abfd, "end");
    302   syms[1].value = sec->size;
    303   syms[1].flags = BSF_GLOBAL;
    304   syms[1].section = sec;
    305   syms[1].udata.p = NULL;
    306 
    307   /* Size symbol.  */
    308   syms[2].the_bfd = abfd;
    309   syms[2].name = mangle_name (abfd, "size");
    310   syms[2].value = sec->size;
    311   syms[2].flags = BSF_GLOBAL;
    312   syms[2].section = bfd_abs_section_ptr;
    313   syms[2].udata.p = NULL;
    314 
    315   for (i = 0; i < PPCBOOT_SYMS; i++)
    316     *alocation++ = syms++;
    317   *alocation = NULL;
    318 
    319   return PPCBOOT_SYMS;
    320 }
    321 
    322 #define ppcboot_make_empty_symbol _bfd_generic_make_empty_symbol
    323 #define ppcboot_print_symbol _bfd_nosymbols_print_symbol
    324 
    325 /* Get information about a symbol.  */
    326 
    327 static void
    328 ppcboot_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
    329 			 asymbol *symbol,
    330 			 symbol_info *ret)
    331 {
    332   bfd_symbol_info (symbol, ret);
    333 }
    334 
    335 #define ppcboot_get_symbol_version_string \
    336   _bfd_nosymbols_get_symbol_version_string
    337 #define ppcboot_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_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_nearest_line_with_alt _bfd_nosymbols_find_nearest_line_with_alt
    342 #define ppcboot_find_line _bfd_nosymbols_find_line
    343 #define ppcboot_find_inliner_info _bfd_nosymbols_find_inliner_info
    344 #define ppcboot_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
    345 #define ppcboot_read_minisymbols _bfd_generic_read_minisymbols
    346 #define ppcboot_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
    347 
    348 /* Write section contents of a ppcboot file.  */
    350 
    351 static bool
    352 ppcboot_set_section_contents (bfd *abfd,
    353 			      asection *sec,
    354 			      const void * data,
    355 			      file_ptr offset,
    356 			      bfd_size_type size)
    357 {
    358   if (! abfd->output_has_begun)
    359     {
    360       bfd_vma low;
    361       asection *s;
    362 
    363       /* The lowest section VMA sets the virtual address of the start
    364 	 of the file.  We use the set the file position of all the
    365 	 sections.  */
    366       low = abfd->sections->vma;
    367       for (s = abfd->sections->next; s != NULL; s = s->next)
    368 	if (s->vma < low)
    369 	  low = s->vma;
    370 
    371       for (s = abfd->sections; s != NULL; s = s->next)
    372 	s->filepos = s->vma - low;
    373 
    374       abfd->output_has_begun = true;
    375     }
    376 
    377   return _bfd_generic_set_section_contents (abfd, sec, data, offset, size);
    378 }
    379 
    380 
    381 static int
    383 ppcboot_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
    384 			struct bfd_link_info *info ATTRIBUTE_UNUSED)
    385 {
    386   return sizeof (ppcboot_hdr_t);
    387 }
    388 
    389 
    390 /* Print out the program headers.  */
    392 
    393 static bool
    394 ppcboot_bfd_print_private_bfd_data (bfd *abfd, void * farg)
    395 {
    396   FILE *f = (FILE *)farg;
    397   ppcboot_data_t *tdata = ppcboot_get_tdata (abfd);
    398   long entry_offset = bfd_getl_signed_32 (tdata->header.entry_offset);
    399   long length = bfd_getl_signed_32 (tdata->header.length);
    400   int i;
    401 
    402   fprintf (f, _("\nppcboot header:\n"));
    403   fprintf (f, _("Entry offset        = 0x%.8lx (%ld)\n"),
    404 	   (unsigned long) entry_offset, entry_offset);
    405   fprintf (f, _("Length              = 0x%.8lx (%ld)\n"),
    406 	   (unsigned long) length, length);
    407 
    408   if (tdata->header.flags)
    409     fprintf (f, _("Flag field          = 0x%.2x\n"), tdata->header.flags);
    410 
    411   if (tdata->header.os_id)
    412     fprintf (f, "OS_ID               = 0x%.2x\n", tdata->header.os_id);
    413 
    414   if (tdata->header.partition_name[0])
    415     fprintf (f, _("Partition name      = \"%s\"\n"), tdata->header.partition_name);
    416 
    417   for (i = 0; i < 4; i++)
    418     {
    419       long sector_begin  = bfd_getl_signed_32 (tdata->header.partition[i].sector_begin);
    420       long sector_length = bfd_getl_signed_32 (tdata->header.partition[i].sector_length);
    421 
    422       /* Skip all 0 entries */
    423       if (!tdata->header.partition[i].partition_begin.ind
    424 	  && !tdata->header.partition[i].partition_begin.head
    425 	  && !tdata->header.partition[i].partition_begin.sector
    426 	  && !tdata->header.partition[i].partition_begin.cylinder
    427 	  && !tdata->header.partition[i].partition_end.ind
    428 	  && !tdata->header.partition[i].partition_end.head
    429 	  && !tdata->header.partition[i].partition_end.sector
    430 	  && !tdata->header.partition[i].partition_end.cylinder
    431 	  && !sector_begin && !sector_length)
    432 	continue;
    433 
    434       /* xgettext:c-format */
    435       fprintf (f, _("\nPartition[%d] start  = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
    436 	       tdata->header.partition[i].partition_begin.ind,
    437 	       tdata->header.partition[i].partition_begin.head,
    438 	       tdata->header.partition[i].partition_begin.sector,
    439 	       tdata->header.partition[i].partition_begin.cylinder);
    440 
    441       /* xgettext:c-format */
    442       fprintf (f, _("Partition[%d] end    = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
    443 	       tdata->header.partition[i].partition_end.ind,
    444 	       tdata->header.partition[i].partition_end.head,
    445 	       tdata->header.partition[i].partition_end.sector,
    446 	       tdata->header.partition[i].partition_end.cylinder);
    447 
    448       /* xgettext:c-format */
    449       fprintf (f, _("Partition[%d] sector = 0x%.8lx (%ld)\n"),
    450 	       i, (unsigned long) sector_begin, sector_begin);
    451 
    452       /* xgettext:c-format */
    453       fprintf (f, _("Partition[%d] length = 0x%.8lx (%ld)\n"),
    454 	       i, (unsigned long) sector_length, sector_length);
    455     }
    456 
    457   fprintf (f, "\n");
    458   return true;
    459 }
    460 
    461 
    462 #define ppcboot_bfd_get_relocated_section_contents \
    464   bfd_generic_get_relocated_section_contents
    465 #define ppcboot_bfd_relax_section bfd_generic_relax_section
    466 #define ppcboot_bfd_gc_sections bfd_generic_gc_sections
    467 #define ppcboot_bfd_lookup_section_flags bfd_generic_lookup_section_flags
    468 #define ppcboot_bfd_merge_sections bfd_generic_merge_sections
    469 #define ppcboot_bfd_is_group_section bfd_generic_is_group_section
    470 #define ppcboot_bfd_group_name bfd_generic_group_name
    471 #define ppcboot_bfd_discard_group bfd_generic_discard_group
    472 #define ppcboot_section_already_linked \
    473   _bfd_generic_section_already_linked
    474 #define ppcboot_bfd_define_common_symbol bfd_generic_define_common_symbol
    475 #define ppcboot_bfd_link_hide_symbol _bfd_generic_link_hide_symbol
    476 #define ppcboot_bfd_define_start_stop bfd_generic_define_start_stop
    477 #define ppcboot_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
    478 #define ppcboot_bfd_link_add_symbols _bfd_generic_link_add_symbols
    479 #define ppcboot_bfd_link_just_syms _bfd_generic_link_just_syms
    480 #define ppcboot_bfd_copy_link_hash_symbol_type \
    481   _bfd_generic_copy_link_hash_symbol_type
    482 #define ppcboot_bfd_final_link _bfd_generic_final_link
    483 #define ppcboot_bfd_link_split_section _bfd_generic_link_split_section
    484 #define ppcboot_bfd_link_check_relocs _bfd_generic_link_check_relocs
    485 
    486 #define ppcboot_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data
    487 #define ppcboot_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
    488 #define ppcboot_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data
    489 #define ppcboot_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
    490 #define ppcboot_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
    491 #define ppcboot_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
    492 #define ppcboot_bfd_print_private_bfd_dat ppcboot_bfd_print_private_bfd_data
    493 
    494 const bfd_target powerpc_boot_vec =
    495 {
    496   "ppcboot",			/* name */
    497   bfd_target_unknown_flavour,	/* flavour */
    498   BFD_ENDIAN_BIG,		/* byteorder is big endian for code */
    499   BFD_ENDIAN_LITTLE,		/* header_byteorder */
    500   EXEC_P,			/* object_flags */
    501   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
    502    | SEC_ROM | SEC_HAS_CONTENTS), /* section_flags */
    503   0,				/* symbol_leading_char */
    504   ' ',				/* ar_pad_char */
    505   16,				/* ar_max_namelen */
    506   0,				/* match priority.  */
    507   TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
    508   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
    509   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
    510   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* data */
    511   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
    512   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
    513   bfd_getl16, bfd_getl_signed_16, bfd_putl16,	/* hdrs */
    514   {				/* bfd_check_format */
    515     _bfd_dummy_target,
    516     ppcboot_object_p,		/* bfd_check_format */
    517     _bfd_dummy_target,
    518     _bfd_dummy_target,
    519   },
    520   {				/* bfd_set_format */
    521     _bfd_bool_bfd_false_error,
    522     ppcboot_mkobject,
    523     _bfd_bool_bfd_false_error,
    524     _bfd_bool_bfd_false_error,
    525   },
    526   {				/* bfd_write_contents */
    527     _bfd_bool_bfd_false_error,
    528     _bfd_bool_bfd_true,
    529     _bfd_bool_bfd_false_error,
    530     _bfd_bool_bfd_false_error,
    531   },
    532 
    533   BFD_JUMP_TABLE_GENERIC (ppcboot),
    534   BFD_JUMP_TABLE_COPY (ppcboot),
    535   BFD_JUMP_TABLE_CORE (_bfd_nocore),
    536   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
    537   BFD_JUMP_TABLE_SYMBOLS (ppcboot),
    538   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
    539   BFD_JUMP_TABLE_WRITE (ppcboot),
    540   BFD_JUMP_TABLE_LINK (ppcboot),
    541   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
    542 
    543   NULL,
    544 
    545   NULL
    546 };
    547