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