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