X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/375bfab5d5bf685ac66e28f23da33e8a995d6a2c..40687c51624402412a0b6734bfb57609113f7f1d:/scripts/slugimage.pl diff --git a/scripts/slugimage.pl b/scripts/slugimage.pl index 541325dd6..deac6ac6d 100755 --- a/scripts/slugimage.pl +++ b/scripts/slugimage.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # # SlugImage : Manipulate NSLU2 firmware images # Dwayne Fontenot (jacques) @@ -391,10 +391,9 @@ sub readInFirmware { my($filename, $partitions_ref) = @_; my($firmware_buf); - my($total_length) = 0x800000; open FILE,$filename or die "Can't find firmware image \"$filename\": $!\n"; - read FILE,$firmware_buf,$total_length or die "Can't read $total_length bytes from \"$filename\": $!\n"; + read FILE,$firmware_buf,$flash_len or die "Can't read $flash_len bytes from \"$filename\": $!\n"; close FILE or die "Can't close \"$filename\": $!\n"; $debug and printf("Read 0x%08X bytes from \"%s\"\n", length($firmware_buf), $filename); @@ -410,7 +409,7 @@ sub readInFirmware { } else { - # Slurp up the data, based on whether a header is present or not + # Slurp up the data, based on whether a header and/or data is present or not if ($_->{'header'}) { # Read the length, and grab the data based on the length. @@ -422,6 +421,11 @@ sub readInFirmware { $_->{'data'} = substr($firmware_buf, $_->{'offset'} + $_->{'header'}, $data_len); } } + elsif ($_->{'pseudo'} and not defined $_->{'file'} and + (substr($firmware_buf, $_->{'offset'}, $_->{'size'}) eq + (pack("C", 0xff) x $_->{'size'}))) { + $debug and printf("Skipping empty pseudo partition <%s>\n", $_->{'name'}); + } else { # Grab the whole partition, using the maximum size. @@ -557,6 +561,11 @@ sub readInFirmwareParts { sub layoutPartitions { my(@partitions) = @_; + # Find the kernel partition, and save a pointer to it for later use + my $kernel; + map { ($_->{'name'} eq "Kernel") && ($kernel = $_); } @partitions; + $kernel or die "Couldn't find the kernel partition\n"; + # Find the last variable size partition, and save a pointer to it for later use my $lastdisk; my $directory_offset; @@ -588,66 +597,33 @@ sub layoutPartitions { $debug and printf("Pointer is 0x%08X\n", $pointer); - # If this is the last variable size partition, then fill the rest of the space. - if ($_->{'name'} eq $lastdisk->{'name'}) { - $_->{'size'} = paddedSize($directory_offset + $flash_start - $pointer); - $debug and printf("Padding last variable partition <%s> to 0x%08X bytes\n", $_->{'name'}, $_->{'size'}); - } - - # Handle requests for partition creation first. - if (defined $_->{'size'} and not defined $_->{'data'} and ($_->{'name'} ne "FIS directory")) { - - # A zero size is a request to fill all available space. - if ($_->{'size'} == 0) { - # Grab the start of the FIS directory, and use all the space up to there. - $_->{'size'} = paddedSize($directory_offset + $flash_start - $pointer); - - # Create an empty partition of the requested size. - $_->{'data'} = padBytes("", $_->{'size'}); - - $debug and printf("Creating empty partition <%s> of 0x%08X bytes\n", $_->{'name'}, $_->{'size'}); - } - - if (not defined $_->{'offset'}) { - # Check to make sure that the requested size is not too large. - if (($pointer + $_->{'size'}) > ($flash_start + $directory_offset)) { - die "Ran out of flash space in <", $_->{'name'}, ">\n"; - } - } - else { - # Check to make sure that the requested size is not too large. - if (($_->{'offset'} + $_->{'size'}) > ($flash_start + $directory_offset)) { - die "Ran out of flash space in <", $_->{'name'}, ">\n"; - } + # Determine the start and offset of the current partition. + if (defined $_->{'offset'}) { + $_->{'start'} = $flash_start + $_->{'offset'}; + # Check for running past the defined start of the partition. + if (($pointer > $_->{'start'}) and not $_->{'pseudo'}) { + die sprintf("Ran out of flash space before <%s> - %s too large.\n", $_->{'name'}, + sprintf("0x%05X bytes", ($pointer - $_->{'start'}))); } } - # Then handle known partitions, and allocate them. - if (defined $_->{'size'}) { - - # Determine the start and offset of the current partition. - if (defined $_->{'offset'}) { - $_->{'start'} = $flash_start + $_->{'offset'}; - } - - # If offset is not defined, then calculate it. - else { - $_->{'start'} = $pointer; - $_->{'offset'} = $_->{'start'} - $flash_start; - } + # If offset is not defined, then calculate it. + else { + $_->{'start'} = $pointer; + $_->{'offset'} = $_->{'start'} - $flash_start; + } - my $size = defined $_->{'data'} ? length($_->{'data'}) : 0; + my $size = defined $_->{'data'} ? length($_->{'data'}) : 0; - # Add skip regions for the partitions with headers. - if ($_->{'header'} > 0) { - # Define the skip region for the initial Sercomm header. - push(@{$_->{'skips'}}, - { 'offset' => 0, 'size' => $_->{'header'}, 'data' => undef }); - # Allow for the Sercomm header to be prepended to the data. - $size += $_->{'header'}; - } + # Add skip regions for the partitions with headers. + if ($_->{'header'} > 0) { + # Define the skip region for the initial Sercomm header. + push(@{$_->{'skips'}}, + { 'offset' => 0, 'size' => $_->{'header'}, 'data' => undef }); + # Allow for the Sercomm header to be prepended to the data. + $size += $_->{'header'}; - # Determine if the partition requires a Sercomm skip region. + # Determine if the partition overlaps the ramdisk boundary. if (($_->{'offset'} < $ramdisk_offset) and (($_->{'offset'} + $size) > $ramdisk_offset)) { # Define the skip region for the inline Sercomm header. @@ -657,36 +633,64 @@ sub layoutPartitions { # Allow for the Sercomm header to be inserted in the data. $size += 16; } + } - # Extend to another block if required. - if ($size > $_->{'size'}) { - $_->{'size'} = $size; - printf("Extending partition <%s> to 0x%08X bytes\n", $_->{'name'}, $_->{'size'}); - } + # Partitions without headers cannot have skip regions. + elsif (($_->{'offset'} <= $ramdisk_offset) and + (($_->{'offset'} + $size) > $ramdisk_offset)) { + # Pad the kernel until it extends past the ramdisk offset. + push(@{$kernel->{'skips'}}, + { 'offset' => ($ramdisk_offset - $kernel->{'offset'}), 'size' => 16, + 'data' => pack("N4", $block_size) }); + $kernel->{'size'} = $ramdisk_offset - $kernel->{'offset'} + $block_size; + $kernel->{'data'} = padBytes($kernel->{'data'}, + $kernel->{'size'} - $kernel->{'header'} - 16); + $_->{'offset'} = $ramdisk_offset + $block_size; + $_->{'start'} = $flash_start + $_->{'offset'}; + $pointer = $_->{'start'}; + $debug and printf("Extending kernel partition past ramdisk offset.\n"); + } - # Keep the user appraised ... - $debug and printf("Allocated <%s> from 0x%08X to 0x%08X (%s / %s)\n", - $_->{'name'}, $_->{'start'}, $_->{'start'} + $_->{'size'}, - ($size >= $block_size ? - sprintf("%d blocks", numBlocks($size)) : - sprintf("0x%05X bytes", $size)), - ($_->{'size'} >= $block_size ? - sprintf("%d blocks", numBlocks($_->{'size'})) : - sprintf("0x%05X bytes", $_->{'size'}))); + # If this is the last variable size partition, then fill the rest of the space. + if ($_->{'name'} eq $lastdisk->{'name'}) { + $_->{'size'} = paddedSize($directory_offset + $flash_start - $pointer); + $debug and printf("Padding last variable partition <%s> to 0x%08X bytes\n", $_->{'name'}, $_->{'size'}); + } + + die sprintf("Partition size not defined in <%s>.\n", $_->{'name'}) + unless defined $_->{'size'}; - # Check to make sure we have not run out of room. - if (($_->{'start'} + $_->{'size'}) > ($flash_start + $flash_len)) { - die "Ran out of flash space in <", $_->{'name'}, ">\n"; + # Extend to another block if required. + if ($size > $_->{'size'}) { + if ($_->{'name'} eq $lastdisk->{'name'}) { + die sprintf("Ran out of flash space in <%s> - %s too large.\n", $_->{'name'}, + sprintf("0x%05X bytes", ($size - $_->{'size'}))); } + $_->{'size'} = $size; + printf("Extending partition <%s> to 0x%08X bytes\n", $_->{'name'}, $_->{'size'}); + } - $debug and printf("Moving pointer from 0x%08X to 0x%08X (0x%08X + 0x%08X)\n", - $pointer, paddedSize($_->{'start'} + $_->{'size'}), - $_->{'start'}, $_->{'size'}); + # Keep the user appraised ... + $debug and printf("Allocated <%s> from 0x%08X to 0x%08X (%s / %s)\n", + $_->{'name'}, $_->{'start'}, $_->{'start'} + $_->{'size'}, + ($size >= $block_size ? + sprintf("%d blocks", numBlocks($size)) : + sprintf("0x%05X bytes", $size)), + ($_->{'size'} >= $block_size ? + sprintf("%d blocks", numBlocks($_->{'size'})) : + sprintf("0x%05X bytes", $_->{'size'}))); + + # Check to make sure we have not run out of room. + if (($_->{'start'} + $_->{'size'}) > ($flash_start + $flash_len)) { + die "Ran out of flash space in <", $_->{'name'}, ">\n"; + } - # Move the pointer up, in preparation for the next partition. - $pointer = paddedSize($_->{'start'} + $_->{'size'}); + $debug and printf("Moving pointer from 0x%08X to 0x%08X (0x%08X + 0x%08X)\n", + $pointer, paddedSize($_->{'start'} + $_->{'size'}), + $_->{'start'}, $_->{'size'}); - } + # Move the pointer up, in preparation for the next partition. + $pointer = paddedSize($_->{'start'} + $_->{'size'}); } @partitions; @@ -916,7 +920,7 @@ sub defaultPartitions { 'offset'=>0x007f8000, 'size'=>0x00004000, 'variable'=>0, 'header'=>0, 'pseudo'=>1, 'data'=>undef, 'byteswap'=>0}, {'name'=>'Microcode', 'file'=>'NPE-B', - 'offset'=>0x007fc000, 'size'=>0x00003ff0, + 'offset'=>0x007fc000, 'size'=>0x00003fe0, 'variable'=>0, 'header'=>16, 'pseudo'=>1, 'data'=>undef, 'byteswap'=>0}, {'name'=>'Trailer', 'file'=>'Trailer', 'offset'=>0x007ffff0, 'size'=>0x00000010, @@ -925,7 +929,7 @@ sub defaultPartitions { # Main routine starts here ... -my($unpack, $pack, $little, $input, $output, $redboot); +my($unpack, $pack, $little, $fatflash, $input, $output, $redboot); my($kernel, $sysconf, $ramdisk, $fisdir); my($microcode, $trailer, $ethaddr, $loader); @@ -941,6 +945,7 @@ if (!GetOptions("d|debug" => \$debug, "u|unpack" => \$unpack, "p|pack" => \$pack, "l|little" => \$little, + "F|fatflash" => \$fatflash, "i|input=s" => \$input, "o|output=s" => \$output, "b|redboot=s" => \$redboot, @@ -960,6 +965,7 @@ if (!GetOptions("d|debug" => \$debug, print " [-u|--unpack] Unpack a firmware image\n"; print " [-p|--pack] Pack a firmware image\n"; print " [-l|--little] Convert Kernel and Ramdisk to little-endian\n"; + print " [-F|--fatflash] Generate an image for 16MB flash\n"; print " [-i|--input] Input firmware image filename\n"; print " [-o|--output] Output firmware image filename\n"; print " [-b|--redboot] Input/Output RedBoot filename\n"; @@ -1042,6 +1048,18 @@ if (defined $little) { } @partitions; } +if (defined $fatflash) { + $flash_len = 0x01000000; + map { + if (($_->{'name'} eq 'FIS directory') or + ($_->{'name'} eq 'Loader config') or + ($_->{'name'} eq 'Microcode') or + ($_->{'name'} eq 'Trailer')) { + $_->{'offset'} += 0x00800000; + } + } @partitions; +} + if (defined $ethaddr) { map { if ($_->{'name'} eq 'EthAddr') { @@ -1110,10 +1128,7 @@ if (defined $ramdisk) { if (defined $size) { $entry{'size'} = $size * $block_size; # Create an empty partition of the requested size. - $entry{'data'} = padBytes("", $entry{'size'}); - if ($entry{'header'}) { - $entry{'data'} = padBytes("", $entry{'size'} - $entry{'header'}); - } + $entry{'data'} = padBytes("", $entry{'size'} - $entry{'header'}); } \%entry;