Import changeset
[linux-flexiantxendom0-3.2.10.git] / arch / ppc / treeboot / mkirimg
1 #!/usr/bin/perl
2 #
3 #    Copyright (c) 1998-1999 TiVo, Inc.
4 #      Original ELF parsing code.
5 #
6 #    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
7 #      Original code from 'mkevimg'.
8 #
9 #    Module name: mkirimg
10 #
11 #    Description:
12 #      Reads an ELF file and assigns global variables 'imageSect_start',
13 #      'imageSect_size', 'initrdSect_start', and 'initrdSect_size' from
14 #      the "image" and "initrd" section header information. It then
15 #      rewrites the input ELF file with assigned globals to an output
16 #      file.
17 #
18 #      An input file, "irSectStart.txt" has the memory address of
19 #      'irSectStart'. The irSectStart memory address is used to find
20 #      the global variables in the ".data" section of the ELF file.
21 #      The 'irSectStart' and the above global variables are defined
22 #      in "irSect.c".
23 #
24 #
25
26 use File::Basename;
27 use Getopt::Std;
28
29 #
30 # usage()
31 #
32 # Description:
33 #   This routine prints out the proper command line usage for this program
34 #
35 # Input(s):
36 #   status - Flag determining what usage information will be printed and what
37 #            the exit status of the program will be after the information is
38 #            printed.
39 #
40 # Output(s):
41 #   N/A
42 #
43 # Returns:
44 #   This subroutine does not return.
45 #
46
47 sub usage {
48   my($status);
49   $status = $_[0];
50
51   printf("Usage: %s [-hvV] <ELF input file> <Evaluation board output file> <irSectStart.txt file>\n",
52          $program);
53
54   if ($status != 0) {
55     printf("Try `%s -h' for more information.\n", $program);
56   }
57
58   if ($status != 1) {
59     print("  -h             Print out this message and exit.\n");
60     print("  -v             Verbose. Print out lots of ELF information.\n");
61     print("  -V             Print out version information and exit.\n");
62   }
63
64   exit($status);
65 }
66
67 #
68 # version()
69 #
70 # Description:
71 #   This routine prints out program version information
72 #
73 # Input(s):
74 #   N/A
75 #
76 # Output(s):
77 #   N/A
78 #
79 # Returns:
80 #   This subroutine does not return.
81 #
82
83 sub version {
84   print("mkirimg Version 1.1.0\n");
85   print("Copyright (c) 1998-1999 TiVo, Inc.\n");
86   print("Copyright (c) 1999 Grant Erickson <grant\@lcse.umn.edu>\n");
87
88   exit (0);
89 }
90
91 #
92 # file_check()
93 #
94 # Description:
95 #   This routine checks an input file to ensure that it exists, is a
96 #   regular file, and is readable.
97 #
98 # Input(s):
99 #   file - Input file to be checked.
100 #
101 # Output(s):
102 #   N/A
103 #
104 # Returns:
105 #   0 if the file exists, is a regular file, and is readable, otherwise -1.
106 #
107
108 sub file_check {
109   my($file);
110   $file = $_[0];
111
112   if (!(-e $file)) {
113      printf("The file \"%s\" does not exist.\n", $file);
114      return (-1);
115   } elsif (!(-f $file)) {
116      printf("The file \"%s\" is not a regular file.\n", $file);
117      return (-1);
118   } elsif (!(-r $file)) {
119      printf("The file \"%s\" is not readable.\n", $file);
120      return (-1);
121   }
122
123   return (0);
124 }
125
126 #
127 # decode_options()
128 #
129 # Description:
130 #   This routine steps through the command-line arguments, parsing out
131 #   recognzied options.
132 #
133 # Input(s):
134 #   N/A
135 #
136 # Output(s):
137 #   N/A
138 #
139 # Returns:
140 #   N/A
141 #
142
143 sub decode_options {
144
145   if (!getopts("hvV")) {
146       usage(1);
147   }
148
149   if ($opt_h) {
150       usage(0);
151   }
152
153   if ($opt_V) {
154       version();
155       exit (0);
156   }
157
158   if ($opt_v) {
159       $verbose = 1;
160   }
161
162   if (!($ElfFile = shift(@ARGV))) {
163       usage(1);
164   }
165
166   if (!($OutputFile = shift(@ARGV))) {
167       usage (1);
168   }
169
170   if (!($IrFile = shift(@ARGV))) {
171       usage (1);
172   }
173
174   if (file_check($ElfFile)) {
175       exit(1);
176   }
177
178   if (file_check($IrFile)) {
179       exit(1);
180   }
181 }
182
183 #
184 # ELF file and section header field numbers
185 #
186
187 require 'elf.pl';
188
189 #
190 # Main program body
191 #
192
193 {
194   $program = basename($0);
195   decode_options();
196
197   open(ELF, "<$ElfFile") || die "Cannot open input file";
198   open(OUTPUT, ">$OutputFile") || die "Cannot open output file";
199   open(IR, "$IrFile") || die "Cannot open input file";
200
201   $ElfFilesize = (-s $ElfFile);
202
203   if (read(ELF, $ibuf, $ElfFilesize) != $ElfFilesize) {
204     print("Failed to read ELF input file!\n");
205     exit(1);
206   }
207
208   if (read(IR, $irbuf, 8) != 8) {
209       print("Failed to read Ir input file!\n");
210       exit(1);
211   }
212
213   #
214   # Parse ELF header
215   #
216
217   @eh = unpack("a16n2N5n6", $ibuf);
218
219   #
220   # Make sure this is actually a PowerPC ELF file.
221   #
222
223   if (substr($eh[$e_ident], 0, 4) ne "\177ELF") {
224       printf("The file \"%s\" is not an ELF file.\n", $ElfFile);
225       exit (1);
226   } elsif ($eh[$e_machine] != 20) {
227       printf("The file \"%s\" is not a PowerPC ELF file.\n", $ElfFile);
228       exit (1);
229   }
230
231   #
232   # Find the section header for the string table.
233   #
234
235   $strtable_section_offset =  $eh[$e_shoff] +
236
237   $eh[$e_shstrndx] * $eh[$e_shentsize];
238
239   if ($verbose) {
240      printf("String table section header offset: 0x%x\n",
241      $strtable_section_offset);
242   }
243
244   #
245   # Find the start of the string table.
246   #
247
248   @strh = unpack("N10", substr($ibuf, $strtable_section_offset,
249                                $eh[$e_shentsize]));
250
251   if ($verbose) {
252      printf("Section name strings start at: 0x%x, %d bytes.\n",
253      $strh[$sh_offset], $strh[$sh_size]);
254   }
255
256   $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]);
257
258   # Grab each section header and find '.data', 'image', and 
259   # 'initrd' sections in particular.
260
261   $off = $eh[$e_shoff];
262   $imageFound = 0;
263   $initrdFound = 0;
264   
265   for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) {
266     @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize]));
267
268     # Take the first section name from the array returned by split.
269
270     ($name) = split(/\000/, substr($names, $sh[$sh_name]));
271
272     # Attempt to find the .data, image, and initrd sections
273
274     if ($name =~ /^\image$/) {
275       ($image_addr, $image_offset, $image_size) =
276         ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
277       $imageFound = 1;
278
279     } elsif ($name =~ /^\initrd$/) {
280       ($initrd_addr, $initrd_offset, $initrd_size) =
281         ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
282       $initrdFound = 1;
283
284     } elsif ($name =~ /^\.data$/) {
285       ($data_addr, $data_offset, $data_size) =
286         ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
287
288     } elsif ($name =~ /^\.bss$/) {
289       ($bss_addr, $bss_offset, $bss_size) =
290         ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]);
291
292     }
293    }
294
295   if ($verbose) {
296     printf("Data section   - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n",
297            $data_addr, $data_size, $data_offset);
298     printf("Bss  section   - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n",
299          $bss_addr, $bss_size, $bss_offset);
300    }
301
302   if ($verbose) {
303     if ($imageFound) {
304       printf("Image section  - Address: 0x%08x, Size: 0x%08x\n",
305              $image_addr, $image_size);
306     } else {
307       printf("Image section not found in file: $ElfFile\n");
308     }
309
310     if ($initrdFound) {
311       printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n",
312              $initrd_addr, $initrd_size);
313     } else {
314       printf("Initrd section not found in file: $ElfFile\n");
315     }
316   }
317
318   # get file offset of irSectStart
319
320   $irSectStartoffset = hex ($irbuf);
321
322   if ($verbose) {
323     printf("irSectStartOffset Address: 0x%08x\n", $irSectStartoffset);
324   }
325
326   # get the offset of global variables 
327
328   $initialOffset = ($irSectStartoffset - $data_addr) + $data_offset + 4;
329
330   # write modified values to OUTPUT file
331
332   syswrite(OUTPUT, $ibuf, $initialOffset);
333
334   if ($imageFound) {
335     $testN = pack ("N2", $bss_addr + $bss_size, $image_size);
336     syswrite(OUTPUT, $testN, length($testN));
337     printf("Updated symbol \"imageSect_start\" to 0x%08x\n",
338            $bss_addr + $bss_size);
339     printf("Updated symbol \"imageSect_size\" to 0x%08x\n", $image_size);
340   } else {
341     syswrite(OUTPUT, $ibuf, 8, $initialOffset);
342   }
343
344   if ($initrdFound) {
345     $testN = pack ("N2", $bss_addr + $bss_size + $image_size, $initrd_size);
346     syswrite(OUTPUT, $testN, length($testN));
347     printf("Updated symbol \"initrdSect_start\" to 0x%08x\n",
348            $bss_addr + $bss_size + $image_size);
349     printf("Updated symbol \"initrdSect_size\" to 0x%08x\n", $initrd_size);
350   } else {
351     syswrite(OUTPUT, $ibuf,8, $initialOffset + 8);
352   }
353
354   syswrite(OUTPUT, $ibuf, $ElfFilesize - ($initialOffset + 16),
355            $initialOffset + 16);
356
357   #
358   # Clean-up and leave
359   #
360
361   close (ELF);
362   close (OUTPUT);
363   close (IR);
364
365   exit (0);
366 }
367