source: trunk/src/binutils/bfd/ppcboot.c@ 10

Last change on this file since 10 was 10, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 16.1 KB
Line 
1/* BFD back-end for PPCbug boot records.
2 Copyright 1996, 1997, 1998, 1999, 2000, 2001
3 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 <ctype.h>
36
37#include "bfd.h"
38#include "sysdep.h"
39#include "libbfd.h"
40
41/* PPCbug location structure */
42typedef struct ppcboot_location {
43 bfd_byte ind;
44 bfd_byte head;
45 bfd_byte sector;
46 bfd_byte cylinder;
47} ppcboot_location_t;
48
49/* PPCbug partition table layout */
50typedef struct ppcboot_partition {
51 ppcboot_location_t partition_begin; /* partition begin */
52 ppcboot_location_t partition_end; /* partition end */
53 bfd_byte sector_begin[4]; /* 32-bit start RBA (zero-based), little endian */
54 bfd_byte sector_length[4]; /* 32-bit RBA count (one-based), little endian */
55} ppcboot_partition_t;
56
57/* PPCbug boot layout. */
58typedef struct ppcboot_hdr {
59 bfd_byte pc_compatibility[446]; /* x86 instruction field */
60 ppcboot_partition_t partition[4]; /* partition information */
61 bfd_byte signature[2]; /* 0x55 and 0xaa */
62 bfd_byte entry_offset[4]; /* entry point offset, little endian */
63 bfd_byte length[4]; /* load image length, little endian */
64 bfd_byte flags; /* flag field */
65 bfd_byte os_id; /* OS_ID */
66 char partition_name[32]; /* partition name */
67 bfd_byte reserved1[470]; /* reserved */
68}
69#ifdef __GNUC__
70 __attribute__ ((packed))
71#endif
72ppcboot_hdr_t;
73
74/* Signature bytes for last 2 bytes of the 512 byte record */
75#define SIGNATURE0 0x55
76#define SIGNATURE1 0xaa
77
78/* PowerPC boot type */
79#define PPC_IND 0x41
80
81/* Information needed for ppcboot header */
82typedef struct ppcboot_data {
83 ppcboot_hdr_t header; /* raw header */
84 asection *sec; /* single section */
85} ppcboot_data_t;
86
87/* Any bfd we create by reading a ppcboot file has three symbols:
88 a start symbol, an end symbol, and an absolute length symbol. */
89#define PPCBOOT_SYMS 3
90
91static boolean ppcboot_mkobject PARAMS ((bfd *));
92static const bfd_target *ppcboot_object_p PARAMS ((bfd *));
93static boolean ppcboot_set_arch_mach
94 PARAMS ((bfd *, enum bfd_architecture, unsigned long));
95static boolean ppcboot_get_section_contents
96 PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
97static long ppcboot_get_symtab_upper_bound PARAMS ((bfd *));
98static char *mangle_name PARAMS ((bfd *, char *));
99static long ppcboot_get_symtab PARAMS ((bfd *, asymbol **));
100static asymbol *ppcboot_make_empty_symbol PARAMS ((bfd *));
101static void ppcboot_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *));
102static boolean ppcboot_set_section_contents
103 PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
104static int ppcboot_sizeof_headers PARAMS ((bfd *, boolean));
105static boolean ppcboot_bfd_print_private_bfd_data PARAMS ((bfd *, PTR));
106
107#define ppcboot_set_tdata(abfd, ptr) ((abfd)->tdata.any = (PTR) (ptr))
108#define ppcboot_get_tdata(abfd) ((ppcboot_data_t *) ((abfd)->tdata.any))
109
110
111/* Create a ppcboot object. Invoked via bfd_set_format. */
112
113static boolean
114ppcboot_mkobject (abfd)
115 bfd *abfd;
116{
117 if (!ppcboot_get_tdata (abfd))
118 ppcboot_set_tdata (abfd, bfd_zalloc (abfd, sizeof (ppcboot_data_t)));
119
120 return true;
121}
122
123
124
125/* Set the architecture to PowerPC */
126static boolean
127ppcboot_set_arch_mach (abfd, arch, machine)
128 bfd *abfd;
129 enum bfd_architecture arch;
130 unsigned long machine;
131{
132 if (arch == bfd_arch_unknown)
133 arch = bfd_arch_powerpc;
134
135 else if (arch != bfd_arch_powerpc)
136 return false;
137
138 return bfd_default_set_arch_mach (abfd, arch, machine);
139}
140
141
142
143/* Any file may be considered to be a ppcboot file, provided the target
144 was not defaulted. That is, it must be explicitly specified as
145 being ppcboot. */
146
147static const bfd_target *
148ppcboot_object_p (abfd)
149 bfd *abfd;
150{
151 struct stat statbuf;
152 asection *sec;
153 ppcboot_hdr_t hdr;
154 size_t i;
155 ppcboot_data_t *tdata;
156
157 BFD_ASSERT (sizeof (ppcboot_hdr_t) == 1024);
158
159 if (abfd->target_defaulted)
160 {
161 bfd_set_error (bfd_error_wrong_format);
162 return NULL;
163 }
164
165 /* Find the file size. */
166 if (bfd_stat (abfd, &statbuf) < 0)
167 {
168 bfd_set_error (bfd_error_system_call);
169 return NULL;
170 }
171
172 if ((size_t) statbuf.st_size < sizeof (ppcboot_hdr_t))
173 {
174 bfd_set_error (bfd_error_wrong_format);
175 return NULL;
176 }
177
178 if (bfd_read ((PTR) &hdr, sizeof (hdr), 1, abfd) != sizeof (hdr))
179 {
180 if (bfd_get_error () != bfd_error_system_call)
181 bfd_set_error (bfd_error_wrong_format);
182
183 return NULL;
184 }
185
186 /* Now do some basic checks. */
187 for (i = 0; i < sizeof (hdr.pc_compatibility); i++)
188 if (hdr.pc_compatibility[i])
189 {
190 bfd_set_error (bfd_error_wrong_format);
191 return NULL;
192 }
193
194 if (hdr.signature[0] != SIGNATURE0 || hdr.signature[1] != SIGNATURE1)
195 {
196 bfd_set_error (bfd_error_wrong_format);
197 return NULL;
198 }
199
200 if (hdr.partition[0].partition_end.ind != PPC_IND)
201 {
202 bfd_set_error (bfd_error_wrong_format);
203 return NULL;
204 }
205
206 abfd->symcount = PPCBOOT_SYMS;
207
208 /* One data section. */
209 sec = bfd_make_section (abfd, ".data");
210 if (sec == NULL)
211 return NULL;
212 sec->flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_CODE | SEC_HAS_CONTENTS;
213 sec->vma = 0;
214 sec->_raw_size = statbuf.st_size - sizeof (ppcboot_hdr_t);
215 sec->filepos = sizeof (ppcboot_hdr_t);
216
217 ppcboot_mkobject (abfd);
218 tdata = ppcboot_get_tdata (abfd);
219 tdata->sec = sec;
220 memcpy ((PTR) &tdata->header, (PTR) &hdr, sizeof (ppcboot_hdr_t));
221
222 ppcboot_set_arch_mach (abfd, bfd_arch_powerpc, 0);
223 return abfd->xvec;
224}
225
226#define ppcboot_close_and_cleanup _bfd_generic_close_and_cleanup
227#define ppcboot_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
228#define ppcboot_new_section_hook _bfd_generic_new_section_hook
229
230
231
232/* Get contents of the only section. */
233
234static boolean
235ppcboot_get_section_contents (abfd, section, location, offset, count)
236 bfd *abfd;
237 asection *section ATTRIBUTE_UNUSED;
238 PTR location;
239 file_ptr offset;
240 bfd_size_type count;
241{
242 if (bfd_seek (abfd, offset + sizeof (ppcboot_hdr_t), SEEK_SET) != 0
243 || bfd_read (location, 1, count, abfd) != count)
244 return false;
245 return true;
246}
247
248
249
250/* Return the amount of memory needed to read the symbol table. */
251
252static long
253ppcboot_get_symtab_upper_bound (abfd)
254 bfd *abfd ATTRIBUTE_UNUSED;
255{
256 return (PPCBOOT_SYMS + 1) * sizeof (asymbol *);
257}
258
259
260
261/* Create a symbol name based on the bfd's filename. */
262
263static char *
264mangle_name (abfd, suffix)
265 bfd *abfd;
266 char *suffix;
267{
268 int size;
269 char *buf;
270 char *p;
271
272 size = (strlen (bfd_get_filename (abfd))
273 + strlen (suffix)
274 + sizeof "_ppcboot__");
275
276 buf = (char *) bfd_alloc (abfd, size);
277 if (buf == NULL)
278 return "";
279
280 sprintf (buf, "_ppcboot_%s_%s", bfd_get_filename (abfd), suffix);
281
282 /* Change any non-alphanumeric characters to underscores. */
283 for (p = buf; *p; p++)
284 if (! isalnum ((unsigned char) *p))
285 *p = '_';
286
287 return buf;
288}
289
290
291
292/* Return the symbol table. */
293
294static long
295ppcboot_get_symtab (abfd, alocation)
296 bfd *abfd;
297 asymbol **alocation;
298{
299 asection *sec = ppcboot_get_tdata (abfd)->sec;
300 asymbol *syms;
301 unsigned int i;
302
303 syms = (asymbol *) bfd_alloc (abfd, PPCBOOT_SYMS * sizeof (asymbol));
304 if (syms == NULL)
305 return false;
306
307 /* Start symbol. */
308 syms[0].the_bfd = abfd;
309 syms[0].name = mangle_name (abfd, "start");
310 syms[0].value = 0;
311 syms[0].flags = BSF_GLOBAL;
312 syms[0].section = sec;
313 syms[0].udata.p = NULL;
314
315 /* End symbol. */
316 syms[1].the_bfd = abfd;
317 syms[1].name = mangle_name (abfd, "end");
318 syms[1].value = sec->_raw_size;
319 syms[1].flags = BSF_GLOBAL;
320 syms[1].section = sec;
321 syms[1].udata.p = NULL;
322
323 /* Size symbol. */
324 syms[2].the_bfd = abfd;
325 syms[2].name = mangle_name (abfd, "size");
326 syms[2].value = sec->_raw_size;
327 syms[2].flags = BSF_GLOBAL;
328 syms[2].section = bfd_abs_section_ptr;
329 syms[2].udata.p = NULL;
330
331 for (i = 0; i < PPCBOOT_SYMS; i++)
332 *alocation++ = syms++;
333 *alocation = NULL;
334
335 return PPCBOOT_SYMS;
336}
337
338
339
340/* Make an empty symbol. */
341
342static asymbol *
343ppcboot_make_empty_symbol (abfd)
344 bfd *abfd;
345{
346 return (asymbol *) bfd_alloc (abfd, sizeof (asymbol));
347}
348
349
350
351#define ppcboot_print_symbol _bfd_nosymbols_print_symbol
352
353/* Get information about a symbol. */
354
355static void
356ppcboot_get_symbol_info (ignore_abfd, symbol, ret)
357 bfd *ignore_abfd ATTRIBUTE_UNUSED;
358 asymbol *symbol;
359 symbol_info *ret;
360{
361 bfd_symbol_info (symbol, ret);
362}
363
364#define ppcboot_bfd_is_local_label_name bfd_generic_is_local_label_name
365#define ppcboot_get_lineno _bfd_nosymbols_get_lineno
366#define ppcboot_find_nearest_line _bfd_nosymbols_find_nearest_line
367#define ppcboot_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
368#define ppcboot_read_minisymbols _bfd_generic_read_minisymbols
369#define ppcboot_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
370
371#define ppcboot_get_reloc_upper_bound \
372 ((long (*) PARAMS ((bfd *, asection *))) bfd_0l)
373#define ppcboot_canonicalize_reloc \
374 ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l)
375#define ppcboot_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
376
377
378/* Write section contents of a ppcboot file. */
379
380static boolean
381ppcboot_set_section_contents (abfd, sec, data, offset, size)
382 bfd *abfd;
383 asection *sec;
384 PTR data;
385 file_ptr offset;
386 bfd_size_type size;
387{
388 if (! abfd->output_has_begun)
389 {
390 bfd_vma low;
391 asection *s;
392
393 /* The lowest section VMA sets the virtual address of the start
394 of the file. We use the set the file position of all the
395 sections. */
396 low = abfd->sections->vma;
397 for (s = abfd->sections->next; s != NULL; s = s->next)
398 if (s->vma < low)
399 low = s->vma;
400
401 for (s = abfd->sections; s != NULL; s = s->next)
402 s->filepos = s->vma - low;
403
404 abfd->output_has_begun = true;
405 }
406
407 return _bfd_generic_set_section_contents (abfd, sec, data, offset, size);
408}
409
410
411
412static int
413ppcboot_sizeof_headers (abfd, exec)
414 bfd *abfd ATTRIBUTE_UNUSED;
415 boolean exec ATTRIBUTE_UNUSED;
416{
417 return sizeof (ppcboot_hdr_t);
418}
419
420
421
422/* Print out the program headers. */
423
424static boolean
425ppcboot_bfd_print_private_bfd_data (abfd, farg)
426 bfd *abfd;
427 PTR farg;
428{
429 FILE *f = (FILE *)farg;
430 ppcboot_data_t *tdata = ppcboot_get_tdata (abfd);
431 long entry_offset = bfd_getl_signed_32 ((PTR) tdata->header.entry_offset);
432 long length = bfd_getl_signed_32 ((PTR) tdata->header.length);
433 int i;
434
435 fprintf (f, _("\nppcboot header:\n"));
436 fprintf (f, _("Entry offset = 0x%.8lx (%ld)\n"), entry_offset, entry_offset);
437 fprintf (f, _("Length = 0x%.8lx (%ld)\n"), length, length);
438
439 if (tdata->header.flags)
440 fprintf (f, _("Flag field = 0x%.2x\n"), tdata->header.flags);
441
442 if (tdata->header.os_id)
443 fprintf (f, "OS_ID = 0x%.2x\n", tdata->header.os_id);
444
445 if (tdata->header.partition_name)
446 fprintf (f, _("Partition name = \"%s\"\n"), tdata->header.partition_name);
447
448 for (i = 0; i < 4; i++)
449 {
450 long sector_begin = bfd_getl_signed_32 ((PTR) tdata->header.partition[i].sector_begin);
451 long sector_length = bfd_getl_signed_32 ((PTR) tdata->header.partition[i].sector_length);
452
453 /* Skip all 0 entries */
454 if (!tdata->header.partition[i].partition_begin.ind
455 && !tdata->header.partition[i].partition_begin.head
456 && !tdata->header.partition[i].partition_begin.sector
457 && !tdata->header.partition[i].partition_begin.cylinder
458 && !tdata->header.partition[i].partition_end.ind
459 && !tdata->header.partition[i].partition_end.head
460 && !tdata->header.partition[i].partition_end.sector
461 && !tdata->header.partition[i].partition_end.cylinder
462 && !sector_begin && !sector_length)
463 continue;
464
465 fprintf (f, _("\nPartition[%d] start = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
466 tdata->header.partition[i].partition_begin.ind,
467 tdata->header.partition[i].partition_begin.head,
468 tdata->header.partition[i].partition_begin.sector,
469 tdata->header.partition[i].partition_begin.cylinder);
470
471 fprintf (f, _("Partition[%d] end = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
472 tdata->header.partition[i].partition_end.ind,
473 tdata->header.partition[i].partition_end.head,
474 tdata->header.partition[i].partition_end.sector,
475 tdata->header.partition[i].partition_end.cylinder);
476
477 fprintf (f, _("Partition[%d] sector = 0x%.8lx (%ld)\n"), i, sector_begin, sector_begin);
478 fprintf (f, _("Partition[%d] length = 0x%.8lx (%ld)\n"), i, sector_length, sector_length);
479 }
480
481 fprintf (f, "\n");
482 return true;
483}
484
485
486
487#define ppcboot_bfd_get_relocated_section_contents \
488 bfd_generic_get_relocated_section_contents
489#define ppcboot_bfd_relax_section bfd_generic_relax_section
490#define ppcboot_bfd_gc_sections bfd_generic_gc_sections
491#define ppcboot_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
492#define ppcboot_bfd_link_add_symbols _bfd_generic_link_add_symbols
493#define ppcboot_bfd_final_link _bfd_generic_final_link
494#define ppcboot_bfd_link_split_section _bfd_generic_link_split_section
495#define ppcboot_get_section_contents_in_window \
496 _bfd_generic_get_section_contents_in_window
497
498#define ppcboot_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data
499#define ppcboot_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
500#define ppcboot_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data
501#define ppcboot_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
502#define ppcboot_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
503#define ppcboot_bfd_print_private_bfd_dat ppcboot_bfd_print_private_bfd_data
504
505const bfd_target ppcboot_vec =
506{
507 "ppcboot", /* name */
508 bfd_target_unknown_flavour, /* flavour */
509 BFD_ENDIAN_BIG, /* byteorder is big endian for code */
510 BFD_ENDIAN_LITTLE, /* header_byteorder */
511 EXEC_P, /* object_flags */
512 (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
513 | SEC_ROM | SEC_HAS_CONTENTS), /* section_flags */
514 0, /* symbol_leading_char */
515 ' ', /* ar_pad_char */
516 16, /* ar_max_namelen */
517 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
518 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
519 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
520 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
521 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
522 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
523 { /* bfd_check_format */
524 _bfd_dummy_target,
525 ppcboot_object_p, /* bfd_check_format */
526 _bfd_dummy_target,
527 _bfd_dummy_target,
528 },
529 { /* bfd_set_format */
530 bfd_false,
531 ppcboot_mkobject,
532 bfd_false,
533 bfd_false,
534 },
535 { /* bfd_write_contents */
536 bfd_false,
537 bfd_true,
538 bfd_false,
539 bfd_false,
540 },
541
542 BFD_JUMP_TABLE_GENERIC (ppcboot),
543 BFD_JUMP_TABLE_COPY (ppcboot),
544 BFD_JUMP_TABLE_CORE (_bfd_nocore),
545 BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
546 BFD_JUMP_TABLE_SYMBOLS (ppcboot),
547 BFD_JUMP_TABLE_RELOCS (ppcboot),
548 BFD_JUMP_TABLE_WRITE (ppcboot),
549 BFD_JUMP_TABLE_LINK (ppcboot),
550 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
551
552 NULL,
553
554 NULL
555};
Note: See TracBrowser for help on using the repository browser.