#!/usr/bin/perl -w # # alteon_genfw.pl # # tjd 22.03.99 as an alternative to Alteon's genfw utility. # # Call as 'alteon_genfw.pl' [-p] # This is in no way guaranteed to work outside of linux/binutils 2.9.1 # # Declarations # sub usage; sub fail; # # Defaults # $prefix = 'alt'; $headerfile = ''; $release = ''; $objdump = 'mips-any-elf-objdump'; %rel = ('MAJOR' => 6, 'MINOR' => 6, 'FIX' => 6); %sizes = ("MAX_TEXT_LEN" => (65536 * 32), "MAX_DATA_LEN" => (65536 * 32), "MAX_RODATA_LEN" => (65536 * 32), "MAX_BSS_SIZE" => (65536 * 32), "MAX_SBSS_SIZE" => (65536 * 32)); # # Command line # if ($#ARGV < 1) { &usage(); } while ($ARGV[0] =~ /^-p/) { $prefix = shift(); $prefix =~ s/^-p//; if ($prefix eq '') { $prefix = shift(); } if ($#ARGV < 1) { &usage(); } } while ($ARGV[0] =~ /^-h/) { $headerfile = shift(); $headerfile =~ s/^-h//; if ($headerfile eq '') { $headerfile = shift(); } if ($#ARGV < 1) { &usage(); } } while ($ARGV[0] =~ /^-r/) { $release = shift(); $release =~ s/^-r//; if ($release eq '') { $release = shift(); } if ($#ARGV < 1) { &usage(); } } # # Read release.h # if ($release) { open (IN,"<$release") or fail ("can't read $release"); while () { if (/^\s*#define\s+RELEASE_[^_]+$/) { s/^\s*#define\s+RELEASE_(.*)$/$1/; @words = split; $rel{$words[0]} = $words[1]; } } close IN; } # # Read the supplied header file. # We lose #ifs, mulitiline #defines, and multiple #defines. Which is # exactly the behaviour of Alteon's parsefile.c, so it's no problem. # if ($headerfile) { open (IN,"<$headerfile") or fail ("can't read $headerfile"); while () { if (/^\s*#define/) { s/^\s*#define\s+(\S.*)$/$1/; @words = split; $key = shift(@words); if (exists ($sizes{$key})) { $sizes{$key} = eval "\$ans = ". join (' ', @words) . ";"; } } } close IN; } # # Build the header file. # open (OUT, ">$ARGV[1]") or &fail ("can't open $ARGV[1] for writing"); print OUT "/*\n * Generated by $0\n */\n"; if ($release) { print OUT "\n/* These values are from $release */\n\n"; } else { print OUT "\n/* These values are completely arbitrary */\n\n"; } print OUT "int ${prefix}FwReleaseMajor = $rel{'MAJOR'}; int ${prefix}FwReleaseMinor = $rel{'MINOR'}; int ${prefix}FwReleaseFix = $rel{'FIX'}; "; # # Pick out the start address # open (IN, "$objdump -f $ARGV[0] |") or &fail ("can't objdump -f $ARGV[0]"); loop1: while () { next loop1 if (/^\s*$/); @words = split(); next loop1 if (($#words != 2) or ($words[0] !~ /start/i) or ($words[1] !~ /address/i)); if ($words[2] !~ /^[0-9a-fA-Fx]+$/) { fail ("coudn't parse objdump output.\nFailed on " . join (@words, " ")); } print OUT "\n/* From \`$objdump -f $ARGV[0]\` */\n\n"; print OUT "u32 ${prefix}FwStartAddr = $words[2];\n"; last loop1; } while () {}; # No sigpipe for us, thanks close IN; # # Now, we need address & length for Text, Rodata, Data, Sbss, Bss. # open (IN, "$objdump -h $ARGV[0] |") or &fail ("can't objdump -h $ARGV[0]"); %addresses = (); %lengths = (); loop2: while () { next loop2 if (/^\s*$/); # blank lines @words = split(); next loop2 if (($#words != 6) or ($words[1] !~ /^\./)); $section = $words[1]; $section =~ s/^\.//; $section = ucfirst($section); $addresses{$section} = "0x$words[3]"; $lengths{$section} = "0x$words[2]"; } print OUT "\n/* From \`$objdump -h $ARGV[0]\` */\n\n"; # A few more values than we intended but what the hell... foreach $key (keys %addresses) { print OUT "u32 ${prefix}Fw${key}Addr = $addresses{$key};\n"; print OUT "int ${prefix}Fw${key}Len = $lengths{$key};\n"; } while () {}; close IN; # # Now the firmware, coded as an array... # open (IN, "$objdump -s $ARGV[0] |") or &fail ("can't objdump -s $ARGV[0]"); print OUT "\n/* From \`$objdump -s $ARGV[0]\` */\n\n"; $printnums = 0; loop3: while () { if (/^Contents of section/i) { print OUT " 0x0 };\n" if $printnums; $printnums = 0; s/^Contents of section\s*\.([^\s:\.]+):\s*$/$1/; $section = ucfirst; if ($section eq "Text" or $section eq "Data" or $section eq "Rodata") { print OUT "u32 ${prefix}Fw${section}[(MAX_TEXT_LEN/4) + 1] " . "__initdata = {"; $printnums = 1; } next loop3; } if ($printnums) { @words = split; shift @words; # lose the address pop @words; # lose the ASCII dump print OUT "\n"; foreach $i (@words) { print OUT " 0x$i," if ($i =~ /^[0-90a-fA-F]{8}$/); } } } print OUT "/*\n * EOF\n */\n"; while () {}; close IN; close OUT; exit 0; # # Subroutines # sub usage { print "$0 [-p] [-h] [-r] (all parameters are position dependant) -p = prefix constants with string, default is alt. -h = hard allocated sizes of constants with include file = source file = destination file -r = location of Alteon's \"release.h\", from drivers tarball "; exit 0; } sub fail { print STDERR "Error: $_[0]\n"; exit -1; } # # EOF #