📄 mkbinrom.pl
字号:
my $endOffset = $offset + length($$binaryRef);
# We first check to see if we overlap any used ranges. If not we call
# replaceBytesInFlashFile to add the data
for (my $count = 0; $count < @usedRanges; $count++)
{
last if ($offset < $usedRanges[$count][0]);
if (overlaps($offset, $endOffset, $usedRanges[$count][0], $usedRanges[$count][1]))
{
my $errStr = sprintf("could not add $desc at 0x%08x to 0x%08x - overlaps existing data in range 0x%08x to 0x%08x, stopped",
$offset, $endOffset, $usedRanges[$count][0], $usedRanges[$count][1]);
die($errStr);
}
}
replaceBinaryInFlashFile($desc, $offset, $binaryRef, "Added");
}
#
# Given an offset from $FLASH_START and a list of bytes, puts the bytes in the
# FLASH file.
# Args: description of what we're putting in place
# offset
# reference to list of bytes
# optional override string for "Replaced" in the verbose output
#
sub replaceBytesInFlashFile($$$;$)
{
my $desc = shift(@_);
my $offset = shift(@_);
my $byteArrayRef = shift(@_);
my $action;
if (@_)
{
$action = shift(@_);
}
else
{
$action = "Replaced";
}
replaceBinaryInFlashFile($desc, $offset, \pack("C*", @$byteArrayRef), $action);
}
#
# Given an offset from $FLASH_START and binary string, puts the binary in the
# FLASH file.
# Args: description of what we're putting in place
# offset
# binary string
# optional override string for "Replaced" in the verbose output
#
sub replaceBinaryInFlashFile($$$;$)
{
my $desc = shift(@_);
my $offset = shift(@_);
my $binaryRef = shift(@_);
my $action;
if (@_)
{
$action = shift(@_);
}
else
{
$action = "Replaced";
}
die("output binary file would exceed 512MB. If this is not in error edit this script, stopped") if ($offset > 512 * 1024 * 1024);
my $topByte = $offset + length($$binaryRef) - 1;
my $eofOff = sysseek(FLASHFILE, 0, 2);
if ($offset > $eofOff)
{
# Extending size of file - write 0xff's in the gap (default unprogrammed
# value for bytes in FLASH)
syswrite(FLASHFILE, pack("C", 0xff) x ($offset - $eofOff));
}
if (sysseek(FLASHFILE, $offset, 0) != $offset)
{
die("failed to seek to offset $offset in internal representation of FLASH, stopped");
}
syswrite(FLASHFILE, $$binaryRef);
# Update @usedRanges if necessary
useRange($offset, $topByte);
printf("$action %d bytes in FLASH, range 0x%08x to 0x%08x ($desc)\n",
length($$binaryRef), $offset, $topByte) if ($verboseOutput);
if ($verboseOutput > 2)
{
print("Bytes written:\n");
my $count = 0;
while ($count < length($$binaryRef))
{
print(join(" ", map(sprintf("%02x", $_), unpack("C32", substr($$binaryRef, $count)))) . "\n");
$count += 32;
}
}
}
#
# Extend the size of the FlashFile to cover the given offset - do not call
# useRange as we don't actually want to prevent anything overwriting the new
# bytes which will initially be 0xFF.
#
sub extendFlashFileToOffset($)
{
my $offset = shift(@_);
my $eofOff = sysseek(FLASHFILE, 0, 2);
if ($offset > $eofOff)
{
# Extending size of file - write 0xff's in the gap (default unprogramed
# value for bytes in FLASH)
syswrite(FLASHFILE, pack("C", 0xff) x ($offset - $eofOff));
}
printf("Extended FLASH to cover offset 0x%08x\n", $offset) if ($verboseOutput > 2);
}
#
# Sub to copy a chunk of the FLASH file to another binary file
#
sub copyFlashFile($$$)
{
my $filename = shift(@_);
my $offset = shift(@_);
my $endOffset = shift(@_);
my $size = $endOffset - $offset;
my $written = 0;
open(OUT_FILE, "$filename") || die("could not open $filename for writing, stopped");
binmode(OUT_FILE);
while ($offset < $endOffset)
{
my $chunkEnd = $offset + (512 * 1024); # Read in 512KB chunks
if ($chunkEnd > $endOffset)
{
$chunkEnd = $endOffset;
}
my $binary = getFlashFileBinary($offset, $chunkEnd);
$written += syswrite(OUT_FILE, $binary);
$offset = $chunkEnd;
}
if ($written != $size)
{
die("failed to write " . $size . " bytes from FLASH representation to $filename, stopped");
}
close(OUT_FILE);
}
#
# Given 2 offsets from $FLASH_START, returns a reference to a byte array of the
# contents.
#
sub getFlashFileBytes($$)
{
my $offset1 = shift(@_);
my $offset2 = shift(@_);
my $binary = getFlashFileBinary($offset1, $offset2);
my $binaryLen = length($binary);
my @byteArray = unpack("C$binaryLen", $binary);
return \@byteArray;
}
#
# Given 2 offsets from $FLASH_START, returns a binary string of the contents.
# Will pad the string with 0xFF's if request is longer than what is known, and
# extend the size of the FlashFile to cover it.
#
sub getFlashFileBinary($$)
{
my $offset1 = shift(@_);
my $offset2 = shift(@_);
die("reverse access of range in FLASH requested, stopped") if ($offset2 <= $offset1);
my $len = $offset2 - $offset1;
my $binary;
if (sysseek(FLASHFILE, $offset1, 0) != $offset1)
{
die("failed to seek to offset $offset1 in internal representation of FLASH, stopped");
}
my $binaryLen = sysread(FLASHFILE, $binary, $len);
if (!defined($binaryLen))
{
die("failed to read data from internal representation of FLASH ($!), stopped");
}
if ($binaryLen < $len)
{
$binary .= pack("C", 0xFF) x ($len - $binaryLen);
extendFlashFileToOffset($offset2);
}
return $binary;
}
#
# Directly modify our representation of FLASH with relocations using 1st arg as
# offset, section info in 2nd arg, architecture in 3rd arg, and the symbols and
# relocations section numbers in @sectionInfo as the 4th and 5th args.
#
sub performRelocations($$$$$)
{
my $ffOffset = shift(@_);
my $sectionInfoRef = shift(@_);
my @sectionInfo = @$sectionInfoRef;
my $arch = shift(@_);
my $symbolsSection = shift(@_);
my $relocationsSection = shift(@_);
print("Performing relocations...\n") if ($verboseOutput);
if ($arch != $CPU_ARCH_LX && $arch != $CPU_ARCH_SH4)
{
die("architecture type $arch detected, but unsupported by relocation code, stopped");
}
my $relocData = $sectionInfo[$relocationsSection]{data};
my $numRelocs = $sectionInfo[$relocationsSection]{len} / 12;
my $symbolData = $sectionInfo[$symbolsSection]{data};
my $numSyms = $sectionInfo[$symbolsSection]{len} / (12 + 1 + 1 + 2);
for (my $count = 0; $count < $numRelocs; $count++)
{
my %curReloc;
my $value;
($curReloc{offset}, $curReloc{info}, $curReloc{addend}) =
unpack("VVV", substr($relocData, $count * 12, 12));
if (($curReloc{info} & 0xFF) == $R_LX_32 ||
($curReloc{info} & 0xFF) == $R_LX_JMP_SLOT ||
($curReloc{info} & 0xFF) == $R_SH_DIR32)
{
my $symbol = $curReloc{info} >> 8;
if ($symbol >= $numSyms)
{
die("invalid relocation symbol reference ($symbol), stopped");
}
$value = $FLASH_START + $ffOffset +
unpack("V", substr($sectionInfo[$symbolsSection]{data}, ($symbol * 16) + 4, 4));
}
elsif (($curReloc{info} & 0xFF) == $R_SH_RELATIVE ||
($curReloc{info} & 0xFF) == $R_LX_REL32)
{
$value = $FLASH_START + $ffOffset + $curReloc{addend};
}
else
{
die("unsupported relocation (type " . ($curReloc{info} & 0xFF) . "), stopped");
}
replaceBinaryInFlashFile("relocation", $ffOffset + $curReloc{offset}, \pack("V", $value));
}
print("Relocations complete.\n") if ($verboseOutput);
}
#
# Sub that processes a boot vector image file directly into our representation
# of FLASH.
#
sub processBootVector($)
{
my $bootVecFile = shift(@_);
# If it's an ELF file, convert it to an image file and change $bootVecFile accordingly
$bootVecFile = convertIfElf("bootvec", $bootVecFile);
# Strip any extra stuff from the filename in case conversion failed
$bootVecFile =~ /^((?:[a-zA-Z]\:\\)?[^\@\:\%]+)/;
$bootVecFile = $1;
my $bootVecBuffer = "";
open(IN_FILE, $bootVecFile) || die("failed to open boot vector file " .
"$bootVecFile ($!), stopped");
binmode(IN_FILE);
# Read header information
sysread(IN_FILE, $bootVecBuffer, $IMG_FILE_HEADER_LEN);
my ($magicNum, $desc, $cpuNum, $stackAddr, $entryAddr, $numSections, $secType, $srcAddr, $dstAddr, $secLen) =
readImgHeader($bootVecBuffer, $bootVecFile);
if ($numSections != 1)
{
die("boot vectors must have just 1 section, stopped");
}
my $realCpuNum = $cpuNum & $CPU_NUMBER_MASK;
if ($realCpuNum == 0)
{
# This is the master CPU's boot vector. The architecture of this file is
# the architecture of the CPU which will copy from ROM to RAM - the master
# CPU.
$useST40Addressing = (($cpuNum & $CPU_ARCH_MASK) == $CPU_ARCH_SH4);
}
# Length of section must be less than or equal to $FLASH_BOOT_VECTOR_SIZE
if ($secLen > $FLASH_BOOT_VECTOR_SIZE)
{
die("boot vector in $bootVecFile is too big - is $secLen bytes, but " .
"must be less than $FLASH_BOOT_VECTOR_SIZE, stopped");
}
my $calcLoadAddr = ($realCpuNum * $FLASH_BOOT_VECTOR_SIZE) + $FLASH_START;
if ($secType == $PLACEMENT_TYPE_INPLACE)
{
if ($calcLoadAddr != $srcAddr || $calcLoadAddr != $dstAddr)
{
die("boot vector in $bootVecFile has a run in-place section, but " .
"it was expected to be at $calcLoadAddr, not $srcAddr, stopped");
}
}
# Put the description in position
$desc .= pack("C", 0) x (32 - length($desc)) if (length($desc) < 32);
replaceBinaryInFlashFile("Boot vector description for CPU $realCpuNum",
($FLASH_BOOTVEC_DESC_OFF + ($realCpuNum * 0x20)),
\$desc);
# Put the code into our representation of FLASH
my $code = "";
sysread(IN_FILE, $code, $secLen);
close(IN_FILE);
$code .= pack("C*", 0) x (40 - length($code)) if (length($code) < 40);
addBinaryToFlashFile("Boot vector for CPU $realCpuNum", ($realCpuNum * 0x40),
\$code);
}
#
# Sub that processes a bootstrap image file into our representation of FLASH.
# Returns the top address used.
#
sub processBootstrap($)
{
my $bootstrapFile = shift(@_);
my $topAddr = 0;
# If it's an ELF file, convert it to an image file and change $bootstrapFile
# accordingly
$bootstrapFile = convertIfElf("bootstrap", $bootstrapFile);
# Strip any extra stuff from the filename
$bootstrapFile =~ /^((?:[a-zA-Z]\:\\)?[^\@\:\%]+)/;
$bootstrapFile = $1;
my $bootstrapBuffer = "";
open(IN_FILE, $bootstrapFile) || die("failed to open bootstrap file $bootstrapFile ($!), stopped");
binmode(IN_FILE);
# Read header information
sysread(IN_FILE, $bootstrapBuffer, $IMG_FILE_HEADER_LEN);
my ($magicNum, $desc, $cpuNum, $stackAddr, $entryAddr, $numSections, $secType, $srcAddr, $dstAddr, $secLen) =
readImgHeader($bootstrapBuffer, $bootstrapFile);
if ($numSections < 1)
{
die("bootstraps should contain 1 or more sections - usually a code " .
"section and optional SYMBOLS and RELOCATIONS sections, stopped");
}
my $realCpuNum = ($cpuNum & $CPU_NUMBER_MASK);
my $cpuArchType = ($cpuNum & $CPU_ARCH_MASK);
# Check section type
if (($secType & $SECTION_TYPE_MASK) != $SECTION_TYPE_SKIP)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -