patch-2.3.30 linux/arch/ppc/treeboot/mkevimg
Next file: linux/arch/ppc/treeboot/mkirimg
Previous file: linux/arch/ppc/treeboot/misc.S
Back to the patch index
Back to the overall index
- Lines: 438
- Date:
Sat Nov 27 15:41:59 1999
- Orig file:
v2.3.29/linux/arch/ppc/treeboot/mkevimg
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.29/linux/arch/ppc/treeboot/mkevimg linux/arch/ppc/treeboot/mkevimg
@@ -0,0 +1,437 @@
+#!/usr/local/bin/perl
+
+#
+# Copyright (c) 1998-1999 TiVo, Inc.
+# All rights reserved.
+#
+# Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+# Major syntactic and usability rework.
+#
+# Module name: mkevimg
+#
+# Description:
+# Converts an ELF output file from the linker into the format used by
+# the IBM evaluation board ROM Monitor to load programs from a host
+# onto the evaluation board. The ELF file must be an otherwise execut-
+# able file (with the text and data addresses bound at link time) and
+# have space reserved after the entry point for the load information
+# block:
+#
+# typedef struct boot_block {
+# unsigned long magic; 0x0052504F
+# unsigned long dest; Target address of the image
+# unsigned long num_512blocks; Size, rounded-up, in 512 byte blocks
+# unsigned long debug_flag; Run the debugger or image after load
+# unsigned long entry_point; The image address to jump to after load
+# unsigned long reserved[3];
+# } boot_block_t;
+#
+#
+
+use File::Basename;
+use Getopt::Std;
+
+#
+# usage()
+#
+# Description:
+# This routine prints out the proper command line usage for this program
+#
+# Input(s):
+# status - Flag determining what usage information will be printed and what
+# the exit status of the program will be after the information is
+# printed.
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# This subroutine does not return.
+#
+
+sub usage {
+ my($status);
+ $status = $_[0];
+
+ printf("Usage: %s [-hlvV] <ELF input file> <Evaluation board output file>\n",
+ $program);
+
+ if ($status != 0) {
+ printf("Try `%s -h' for more information.\n", $program);
+ }
+
+ if ($status != 1) {
+ print(" -h Print out this message and exit.\n");
+ print(" -l Linux mode; if present, copy 'image' and 'initrd' sections.\n");
+ print(" -v Verbose. Print out lots of ELF information.\n");
+ print(" -V Print out version information and exit.\n");
+ }
+
+ exit($status);
+}
+
+#
+# version()
+#
+# Description:
+# This routine prints out program version information
+#
+# Input(s):
+# N/A
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# This subroutine does not return.
+#
+
+sub version {
+ print("mkevimg Version 1.1.0\n");
+ print("Copyright (c) 1998-1999 TiVo, Inc.\n");
+ print("Copyright (c) 1999 Grant Erickson <grant\@lcse.umn.edu>\n");
+
+ exit (0);
+}
+
+#
+# file_check()
+#
+# Description:
+# This routine checks an input file to ensure that it exists, is a
+# regular file, and is readable.
+#
+# Input(s):
+# file - Input file to be checked.
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# 0 if the file exists, is a regular file, and is readable, otherwise -1.
+#
+
+sub file_check {
+ my($file);
+ $file = $_[0];
+
+ if (!(-e $file)) {
+ printf("The file \"%s\" does not exist.\n", $file);
+ return (-1);
+ } elsif (!(-f $file)) {
+ printf("The file \"%s\" is not a regular file.\n", $file);
+ return (-1);
+ } elsif (!(-r $file)) {
+ printf("The file \"%s\" is not readable.\n", $file);
+ return (-1);
+ }
+
+ return (0);
+}
+
+#
+# decode_options()
+#
+# Description:
+# This routine steps through the command-line arguments, parsing out
+# recognzied options.
+#
+# Input(s):
+# N/A
+#
+# Output(s):
+# N/A
+#
+# Returns:
+# N/A
+#
+
+sub decode_options {
+
+ if (!getopts("hlvV")) {
+ usage(1);
+ }
+
+ if ($opt_h) {
+ usage(0);
+ }
+
+ if ($opt_l) {
+ $linux = 1;
+ }
+
+ if ($opt_V) {
+ version();
+ exit (0);
+ }
+
+ if ($opt_v) {
+ $verbose = 1;
+ }
+
+ if (!($ifile = shift(@ARGV))) {
+ usage(1);
+ }
+
+ if (!($ofile = shift(@ARGV))) {
+ usage (1);
+ }
+
+ if (file_check($ifile)) {
+ exit(1);
+ }
+
+}
+
+#
+# ELF file and section header field numbers
+#
+
+require 'elf.pl';
+
+#
+# Main program body
+#
+
+{
+ $program = basename($0);
+
+ decode_options();
+
+ open(ELF, "<$ifile") || die "Cannot open input file";
+
+ $ifilesize = (-s $ifile);
+
+ if ($verbose) {
+ print("Output file: $ofile\n");
+ print("Input file: $ifile, $ifilesize bytes.\n");
+ }
+
+ if (read(ELF, $ibuf, $ifilesize) != $ifilesize) {
+ print("Failed to read input file!\n");
+ exit(1);
+ }
+
+ #
+ # Parse ELF header
+ #
+
+ @eh = unpack("a16n2N5n6", $ibuf);
+
+ #
+ # Make sure this is actually a PowerPC ELF file.
+ #
+
+ if (substr($eh[$e_ident], 0, 4) ne "\177ELF") {
+ printf("The file \"%s\" is not an ELF file.\n", $ifile);
+ exit (1);
+ } elsif ($eh[$e_machine] != 20) {
+ printf("The file \"%s\" is not a PowerPC ELF file.\n", $ifile);
+ exit (1);
+ }
+
+ if ($verbose) {
+ print("File header:\n");
+ printf(" Identifier: %s\n", $eh[$e_ident]);
+ printf(" Type: %d\n", $eh[$e_type]);
+ printf(" Machine: %d\n", $eh[$e_machine]);
+ printf(" Version: %d\n", $eh[$e_version]);
+ printf(" Entry point: 0x%08x\n", $eh[$e_entry]);
+ printf(" Program header offset: 0x%x\n", $eh[$e_phoff]);
+ printf(" Section header offset: 0x%x\n", $eh[$e_shoff]);
+ printf(" Flags: 0x%08x\n", $eh[$e_flags]);
+ printf(" Header size: %d\n", $eh[$e_ehsize]);
+ printf(" Program entry size: %d\n", $eh[$e_phentsize]);
+ printf(" Program table entries: %d\n", $eh[$e_phnum]);
+ printf(" Section header size: %d\n", $eh[$e_shentsize]);
+ printf(" Section table entries: %d\n", $eh[$e_shnum]);
+ printf(" String table section: %d\n", $eh[$e_shstrndx]);
+ }
+
+ #
+ # Find the section header for the string table.
+ #
+
+ $strtable_section_offset = $eh[$e_shoff] +
+ $eh[$e_shstrndx] * $eh[$e_shentsize];
+
+ if ($verbose) {
+ printf("String table section header offset: 0x%x\n",
+ $strtable_section_offset);
+ }
+
+ #
+ # Find the start of the string table.
+ #
+
+ @strh = unpack("N10", substr($ibuf, $strtable_section_offset,
+ $eh[$e_shentsize]));
+
+ if ($verbose) {
+ printf("Section name strings start at: 0x%x, %d bytes.\n",
+ $strh[$sh_offset], $strh[$sh_size]);
+ }
+
+ $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]);
+
+ # Grab each section header and find '.text' and '.bss' sections in
+ # particular.
+
+ if ($verbose) {
+ print("Section headers:\n");
+ print("Idx Name Size Address File off Algn\n");
+ print("--- ------------------------ -------- -------- -------- ----\n");
+ }
+
+ $off = $eh[$e_shoff];
+
+ for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) {
+ @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize]));
+
+ # Take the first section name from the array returned by split.
+
+ ($name) = split(/\000/, substr($names, $sh[$sh_name]));
+
+ if ($verbose) {
+ printf("%3d %-24s %8x %08x %08x %4d\n",
+ $i, $name, $sh[$sh_size], $sh[$sh_addr],
+ $sh[$sh_offset], $sh[$sh_addralign]);
+ }
+
+ # Attempt to find the .text and .bss sections
+
+ if ($name =~ /^\.bss$/) {
+ ($bss_addr, $bss_offset, $bss_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ } elsif ($name =~ /^\.text$/) {
+ ($text_addr, $text_offset, $text_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ } elsif ($linux && ($name =~ /^\image$/)) {
+ $image_found = 1;
+
+ ($image_addr, $image_offset, $image_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ } elsif ($linux && ($name =~ /^\initrd$/)) {
+ $initrd_found = 1;
+
+ ($initrd_addr, $initrd_offset, $initrd_size) =
+ ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
+
+ }
+ }
+
+ printf("Text section - Address: 0x%08x, Size: 0x%08x\n",
+ $text_addr, $text_size);
+ printf("Bss section - Address: 0x%08x, Size: 0x%08x\n",
+ $bss_addr, $bss_size);
+
+ if ($linux) {
+ if ($image_found) {
+ printf("Image section - Address: 0x%08x, Size: 0x%08x\n",
+ $image_addr, $image_size);
+ }
+
+ if ($initrd_found) {
+ printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n",
+ $initrd_addr, $initrd_size);
+ }
+ }
+
+ #
+ # Open output file
+ #
+
+ open(BOOT, ">$ofile") || die "Cannot open output file";
+
+ #
+ # Compute image size
+ #
+
+ $output_size = $bss_offset - $text_offset + $bss_size;
+
+ if ($linux && $image_found) {
+ $output_size += $image_size;
+ }
+
+ if ($linux && $initrd_found) {
+ $output_size += $initrd_size;
+ }
+
+ $num_blocks = $output_size / 512 + 1;
+
+ #
+ # Write IBM PowerPC evaluation board boot_block_t header
+ #
+
+ $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0,
+ $text_addr, 0, 0, 0);
+
+ $bytes = length($header);
+
+ if (($resid = syswrite(BOOT, $header, $bytes)) != $bytes) {
+ die("Could not write boot image header to output file.");
+ }
+
+ printf("Entry point = 0x%08x\n", $text_addr);
+ printf("Image size = 0x%08x (%d bytes) (%d blocks).\n",
+ $output_size, $output_size, $num_blocks);
+
+ #
+ # Write image starting after ELF and program headers and
+ # continuing to beginning of bss
+ #
+
+ $bytes = $bss_offset - $text_offset + $bss_size;
+
+ if (($resid = syswrite(BOOT, $ibuf, $bytes, $text_offset)) != $bytes) {
+ die("Could not write boot image to output file.\n");
+ }
+
+ #
+ # If configured, write out the image and initrd sections as well
+ #
+
+ if ($linux) {
+ if ($image_found) {
+ $bytes = $image_size;
+ if (($resid = syswrite(BOOT, $ibuf, $bytes, $image_offset)) != $bytes) {
+ die("Could not write boot image to output file.\n");
+ }
+ }
+
+ if ($initrd_found) {
+ $bytes = $initrd_size;
+ if (($resid = syswrite(BOOT, $ibuf, $bytes, $initrd_offset)) != $bytes) {
+ die("Could not write boot image to output file.\n");
+ }
+ }
+ }
+
+ #
+ # Pad to a multiple of 512 bytes
+ #
+
+ $pad_size = 512 - (length($header) + $output_size) % 512;
+
+ if ($verbose) {
+ print("Padding boot image by an additional $pad_size bytes.\n");
+ }
+
+ $pad_string = pack(("H8","deadbeef") x 128);
+
+ syswrite(BOOT, $pad_string, $pad_size) or
+ die "Could not pad boot image in output file.\n";
+
+ #
+ # Clean-up and leave
+ #
+
+ close(BOOT);
+
+ print("\nBoot image file \"$ofile\" built successfuly.\n\n");
+
+ exit(0);
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)