📄 mkcommon.pm
字号:
#
# Reads the header from an image file, does some checks and returns some info
#
sub readImgHeader($$)
{
my $headerBuffer = shift(@_);
my $filename = shift(@_);
my ($magicNum, $desc, $cpuNum, $stackAddr, $entryAddr, $numSections, $secType, $srcAddr, $dstAddr, $secLen) =
unpack("VZ32V8", $headerBuffer);
if ($magicNum != $IMAGE_FILE_MAGIC_NUM)
{
die("$filename does not appear to be a valid image file, stopped");
}
if ($verboseOutput)
{
my $tempString;
my $isRelocLib = 0;
print("\n$filename:\n");
print("\tImage description: $desc\n");
if (($cpuNum & $IMAGE_TYPE_MASK) == $IMAGE_TYPE_RELOC_LIB)
{
$tempString = "Relocatable library";
$isRelocLib = 1;
}
elsif (($cpuNum & $IMAGE_TYPE_MASK) == $IMAGE_TYPE_DATA)
{
$tempString = "Data image";
}
elsif (($cpuNum & $IMAGE_TYPE_MASK) == $IMAGE_TYPE_CC_SIGDMA)
{
$tempString = "Cryptocore SigDMA image";
}
else
{
$tempString = "Standard image";
}
print("\tImage type: $tempString\n");
my $arch = ($cpuNum & $CPU_ARCH_MASK);
$tempString = "Unknown";
$tempString = "ST40" if ($arch == $CPU_ARCH_SH4);
$tempString = "ST200" if ($arch == $CPU_ARCH_LX);
$tempString = "ST20" if ($arch == $CPU_ARCH_ST20);
print("\tArchitecture: $tempString\n");
print("\tFor CPU: " . ($cpuNum & $CPU_NUMBER_MASK) . "\n");
printf("\tStack addr: 0x%08x, ", $stackAddr);
if ($isRelocLib)
{
printf("Uncompressed size: 0x%08x\n", $entryAddr);
}
else
{
printf("Entry addr: 0x%08x\n", $entryAddr);
}
print("\tNumSections: $numSections\n");
printf("\tSec type: 0x%08x, src addr: 0x%08x, dst addr: 0x%08x, sec len: $secLen\n\n",
$secType, $srcAddr, $dstAddr);
}
if (($cpuNum & $CPU_NUMBER_MASK) >= $::FLASH_MAX_CPUS)
{
die("image in $filename is for CPU number " .
($cpuNum & $CPU_NUMBER_MASK) .
" - must be in range 0 to " . ($::FLASH_MAX_CPUS - 1) . ", stopped");
}
return ($magicNum, $desc, $cpuNum, $stackAddr, $entryAddr, $numSections,
$secType, $srcAddr, $dstAddr, $secLen);
}
#
# Routine to copy a list of sections from an ELF file to a binary file
#
# Params: space separated list of names in a string, ELF file, output binary file
#
sub copySectionsToFile($$$)
{
my $nameList = shift(@_);
my $elfFile = shift(@_);
my $outFile = shift(@_);
# These lines should add -j before every section name (for passing to objcopy)
($nameList = $nameList) =~ s/ / -j /g;
($nameList = $nameList) =~ s/^/-j /g;
# Suppress any (harmless) warnings when processing ST200 images with
# objcopy by redirecting STDERR to a temporary file.
my $errFile = createtmpname();
my $dumpCmd = getObjcopy() . " -O binary -I elf32-little $nameList $elfFile $outFile 2>$errFile";
# NOTE: when we output more than one section using objcopy in binary mode,
# padding is inserted (0x00's)
my $status = system($dumpCmd);
die("unable to execute '$dumpCmd' ($status), stopped") unless ($status == 0);
}
#
# Sub to read an entire binary file into a string, which is returned
#
sub readBinFileToStr($)
{
my $filename = shift(@_);
my $str;
open(IN_HANDLE, $filename) or die("unable to open '$filename' (!$), stopped");
binmode(IN_HANDLE);
my $fileLen = (stat($filename))[7];
sysread(IN_HANDLE, $str, $fileLen) or die("unable to read from '$filename' ($!), stopped");
close(IN_HANDLE);
return $str;
}
#
# Sub to read a SigDMA info file, returning information retrieved in an array
#
sub readSigDMAInfoFile($$)
{
my $sigDMAInfoFile = shift(@_);
my $getDataToo = shift(@_);
open(IN_FILE, "<$sigDMAInfoFile") || die("failed to open SigDMA info " .
"file $sigDMAInfoFile ($!), stopped");
my $srcAddr = 0; # Default to being assigned by mkbinrom.pl
my $dstAddr = undef;
my $sigAddr = 0; # Default to being assigned by mkbinrom.pl
my $enAddr = undef;
my $enData = undef;
my $data = "";
my $dmaVCCAddr = undef;
my $dmaVCCValue = undef;
my $dmaSTCAddr = undef;
my $dmaSTCValue = undef;
my $line;
my $readingData = 0;
while ($line = <IN_FILE>)
{
next if ($line =~ /^\s*#/); # Comment line
next if ($line =~ /^\s*$/); # Blank line
if ($readingData)
{
# Remove any comment from $line
if ($line =~ /^([^#]+)#/)
{
$line = $1;
}
# Split line on whitespace and append each word to our binary string, $data
my @words = split(/\s+/, $line);
foreach my $word (@words)
{
if ($word =~ /($HEX_NUM_REGEXP)/)
{
$data .= pack("V", hex($1));
}
else
{
# If it's whitespace, ignore silently...
if ($word !~ /^\s*$/)
{
warn("Warning: Ignoring invalid input in data section of $sigDMAInfoFile - \"$word\"\n");
}
}
}
}
else
{
# We're looking for info lines...or the "[data]" marker
if ($line =~ /^\s*(source|src)_addr(ess)?\s+($HEX_NUM_REGEXP)/)
{
$srcAddr = hex($3);
if ($srcAddr % 32)
{
my $oldSrcAddr = $srcAddr;
$srcAddr &= 0xFFFFFFE0;
my $errStr = sprintf("Warning: SigDMA source address of 0x%08x is not 32 byte aligned - using 0x%08x\n", $oldSrcAddr, $srcAddr);
warn($errStr);
}
}
elsif ($line =~ /^\s*dest(ination)?_addr(ess)?\s+($HEX_NUM_REGEXP)/)
{
$dstAddr = hex($3);
if ($dstAddr % 4)
{
die("SigDMA destination address of 0x%08x is not 4 byte aligned, stopped");
}
}
elsif ($line =~ /^\s*sig(nature)?_addr(ess)?\s+($HEX_NUM_REGEXP)/)
{
$sigAddr = hex($3);
if ($sigAddr % 32)
{
my $errStr = sprintf("Warning: SigDMA signature address of 0x%08x is not 32 byte aligned - ", $sigAddr);
warn($errStr);
$sigAddr &= 0xFFFFFFE0;
printf("using 0x%08x\n", $sigAddr);
}
}
elsif ($line =~ /^\s*en(able)?_addr(ess)?\s+($HEX_NUM_REGEXP)/)
{
$enAddr = hex($3);
if ($enAddr % 4)
{
die("SigDMA enable address of 0x%08x is not 4 byte aligned, stopped");
}
}
elsif ($line =~ /^\s*en(able)?_data\s+($HEX_NUM_REGEXP|[0-9]+)/)
{
$enData = hex($2);
}
elsif ($line =~ /^\s*vcc_addr(ess)?\s+($HEX_NUM_REGEXP|[0-9]+)/)
{
$dmaVCCAddr = hex($2);
}
elsif ($line =~ /^\s*vcc_val(ue)?\s+($HEX_NUM_REGEXP|[0-9]+)/)
{
$dmaVCCValue = hex($2);
}
elsif ($line =~ /^\s*stc_addr(ess)?\s+($HEX_NUM_REGEXP|[0-9]+)/)
{
$dmaSTCAddr = hex($2);
}
elsif ($line =~ /^\s*stc_val(ue)?\s+($HEX_NUM_REGEXP|[0-9]+)/)
{
$dmaSTCValue = hex($2);
}
elsif ($line =~ /^\s*\[data\]/)
{
last if (!$getDataToo);
$readingData = 1;
}
}
}
close(IN_FILE);
# Check all values needed have been filled
die("destination_address not seen in SigDMA info file $sigDMAInfoFile, stopped") if (!defined($dstAddr));
die("enable_address not seen in SigDMA info file $sigDMAInfoFile, stopped") if (!defined($enAddr));
die("enable_data not seen in SigDMA info file $sigDMAInfoFile, stopped") if (!defined($enData));
if ($getDataToo && length($data) == 0)
{
die("supposed to retrieve data from $sigDMAInfoFile, but none found, stopped");
}
# All done
return ($srcAddr, $dstAddr, $sigAddr, $enAddr, $enData, $data, $dmaVCCAddr,
$dmaVCCValue, $dmaSTCAddr, $dmaSTCValue);
}
#
# Sub to check a section is a reserve section (.post_(text|rodata)_reserve and
# return the offset of the config table entry. -1 is returned if
# this is not a reserve section. A reference to section info is passed in,
# which takes the form [secType, srcAddr, destAddr, size, data]. The second
# argument is non-zero if the caller wishes to check for the presence of the
# 0xDEADADDA value in the next block config table entry address.
#
sub getCTEoffset($$)
{
my $sec = shift(@_);
my $checkDeadAdda = shift(@_);
if ($sec->{len} == $RESERVE_1024_BIT_KEY || $sec->{len} == $RESERVE_2048_BIT_KEY)
{
my $lenDigitalSignature = 128;
if ($sec->{len} == $RESERVE_2048_BIT_KEY)
{
$lenDigitalSignature += 128;
}
# We don't have section names in .img files, so we can only use the
# size, type and content of sections to identify them as reserve
# sections
if (($sec->{type} & $defaultSectionTypes{"copy"}) == $defaultSectionTypes{"copy"} ||
($sec->{type} & $defaultSectionTypes{"inplace"}) == $defaultSectionTypes{"inplace"})
{
# The 0xDEADADDA word should be in the location we expect to put the
# next_block_cfg_add field (only check if told to)
# In order to help us out, mkimage.pl puts the size of the section this is a
# reserve section for, in the first word of this section's data.
my $signedBlockLen = unpack("V", $sec->{data});
if ($signedBlockLen < 4)
{
# Signed section should be at least 4 bytes long (without padding to the
# correct size).
return -1;
}
# $padSize is the amount of padding to the place the signature will go
my $padSize = 16; # We always have at least 16 bytes padding to ensure
# code cannot be in the last 16 bytes of the signed
# region
my $misSize = ($signedBlockLen + $padSize) % 64;
if ($misSize)
{
$padSize += 64 - $misSize;
}
my $cteOffset = $padSize + $lenDigitalSignature;
if ($checkDeadAdda)
{
my $checkStr = substr($sec->{data}, $cteOffset + 16, 4);
if ($checkStr ne pack("V", 0xDEADADDA))
{
# The magic number 0xDEADADDA was not in the right place - return -1
return -1;
}
}
return $cteOffset;
}
}
# Not a reserve section - return -1.
return -1;
}
#
# Write a given array of byte values to the given filename as binary (filename
# is 1st arg and should include the mode - append or write as > or >>).
# Undefined values in the array will be padded with 0xFF.
#
sub writeByteArray($$)
{
my $filename = shift(@_);
my $byteArrayRef = shift(@_);
open(OUT_FILE, "$filename") || die("could not open $filename for writing, stopped");
binmode(OUT_FILE);
my $noUndefListRef = noUndef(0, $byteArrayRef, 0xFF);
syswrite(OUT_FILE, pack("C*", @$noUndefListRef), scalar(@$byteArrayRef));
close(OUT_FILE);
print("Written " . scalar(@$byteArrayRef) . " bytes to $filename\n") if ($verboseOutput);
}
#
# Sub which returns 0 if the 2 ranges specified overlap each other.
# Args: start range 1 (inclusive)
# end range 1 (exclusive)
# start range 2 (inclusive)
# end range 2 (exclusive)
sub overlaps($$$$)
{
my $s1 = shift(@_);
my $e1 = shift(@_);
my $s2 = shift(@_);
my $e2 = shift(@_);
# Zero length?
if ($s1 == $e1 || $s2 == $e2)
{
return 0;
}
if ($s1 > $s2)
{
if ($s1 < $e2)
{
return 1;
}
}
else
{
if ($s2 < $e1)
{
return 1;
}
}
return 0;
}
return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -