📄 mkcommon.pm
字号:
#
# Perl module containing common subs used by other scripts
#
# Note: Not a proper perl module as we don't have the package keyword
#
# Scripts using this module include:
# combinebinary.pl
# img2bin.pl
# mk5301rom.pl
# mkbinrom.pl
# mkimage.pl
#
# Some global variables from the main package are used by mkcommon.pm, so must
# be created as 'our' variables in all scripts which subs which use them:
# our $PATH_TO_THIS_SCRIPT = <path to the main script>
# our $THIS_SCRIPT = <filename (no path) of the main script>
# our $FLASH_MAX_CPUS = <max CPUs allowed>
# our $SIGGEN_TOOL = <name of siggen executable to use>
#
package mkcommon;
use strict;
use warnings;
BEGIN
{
use Exporter ();
our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
@ISA = qw(Exporter);
@EXPORT = qw(
$HEX_NUM_REGEXP
$R_LX_32
$R_LX_REL32
$R_LX_JMP_SLOT
$R_SH_DIR32
$R_SH_RELATIVE
$CPU_ARCH_SH4
$CPU_ARCH_LX
$CPU_ARCH_ST20
$IMAGE_TYPE_RELOC_LIB
$IMAGE_TYPE_DATA
$IMAGE_TYPE_CC_SIGDMA
$CPU_NUMBER_MASK
$CPU_ARCH_MASK
$IMAGE_TYPE_MASK
$IMAGE_FILE_MAGIC_NUM
$SECTION_TYPE_SKIP
$SECTION_TYPE_COPY
$SECTION_TYPE_ZERO
$SECTION_TYPE_RUN_LENGTH
$SECTION_TYPE_DEFLATED
$SECTION_TYPE_SYMBOLS
$SECTION_TYPE_RELOCATIONS
$SECTION_TYPE_LX_BOOT
$PLACEMENT_TYPE_ANYWHERE
$PLACEMENT_TYPE_NONE
$PLACEMENT_TYPE_INPLACE_BLANK
$PLACEMENT_TYPE_INPLACE
$SECTION_TYPE_MASK
$PLACEMENT_TYPE_MASK
%defaultSectionTypes
$FLASH_BOOT_FLAG
$IMG_FILE_HEADER_LEN
$verboseOutput
$useST40Addressing
$LEN_CONFIG_INFO_FOR_BLOCK
$RESERVE_1024_BIT_KEY
$RESERVE_2048_BIT_KEY
&createtmpname
&unlinktmpfiles
&getTools
&getObjcopy
&getReadelf
&getObjdump
&getELFArch
&physMemAddr
&getChipInfo
&listChips
&runSigningTool
&noUndef
&intToLittleEndBytes
&hexStrToByteArray
&padList
&readImgHeader
©SectionsToFile
&readBinFileToStr
&readSigDMAInfoFile
&getCTEoffset
&writeByteArray
&overlaps
);
# your exported package globals go here,
# as well as any optionally exported functions
@EXPORT_OK = qw();
}
our @EXPORT_OK;
use File::Spec::Functions;
use File::Temp qw/:mktemp/;
####################
# Exported Globals #
####################
our $HEX_NUM_REGEXP = "0[Xx][0-9a-fA-F]{1,8}";
# ELF relocation info values
our $R_LX_32 = 2;
our $R_LX_REL32 = 9;
our $R_LX_JMP_SLOT = 25;
our $R_SH_DIR32 = 1;
our $R_SH_RELATIVE = 165;
# Values/masks for the CPU number field in an image file
our $CPU_ARCH_SH4 = 0x00000100;
our $CPU_ARCH_LX = 0x00000200;
our $CPU_ARCH_ST20 = 0x00000300;
our $IMAGE_TYPE_RELOC_LIB = 0x00010000;
our $IMAGE_TYPE_DATA = 0x00020000;
our $IMAGE_TYPE_CC_SIGDMA = 0x00030000;
our $CPU_NUMBER_MASK = 0x000000FF;
our $CPU_ARCH_MASK = 0x0000FF00;
our $IMAGE_TYPE_MASK = 0x00FF0000;
our $IMAGE_FILE_MAGIC_NUM = 0x13A9F17E;
# Section types and placement constants/masks
our $SECTION_TYPE_SKIP = 0x00000000; # No processing required
our $SECTION_TYPE_COPY = 0x00000001; # Copy to RAM
our $SECTION_TYPE_ZERO = 0x00000002; # Zeroing in RAM
our $SECTION_TYPE_RUN_LENGTH = 0x00000003; # Runlength decode to RAM
our $SECTION_TYPE_DEFLATED = 0x00000004; # Inflating to RAM
our $SECTION_TYPE_SYMBOLS = 0x00000005; # ELF symbol table
our $SECTION_TYPE_RELOCATIONS = 0x00000006; # ELF relocations
our $SECTION_TYPE_LX_BOOT = 0x00000007; # .boot for an LX
our $PLACEMENT_TYPE_ANYWHERE = 0x00000000; # Can go anywhere
our $PLACEMENT_TYPE_NONE = 0x10000000; # Has no presence in ROM
our $PLACEMENT_TYPE_INPLACE_BLANK = 0x20000000; # Blank and placed here
our $PLACEMENT_TYPE_INPLACE = 0x30000000; # Must be placed exactly here in ROM
our $SECTION_TYPE_MASK = 0x000000FF; # Mask to just type info
our $PLACEMENT_TYPE_MASK = 0xF0000000; # Mask to just placement info
our %defaultSectionTypes = ("copy" => $PLACEMENT_TYPE_ANYWHERE | $SECTION_TYPE_COPY,
"pic" => $PLACEMENT_TYPE_ANYWHERE | $SECTION_TYPE_SKIP,
"inplace" => $PLACEMENT_TYPE_INPLACE | $SECTION_TYPE_SKIP,
"deflate" => $PLACEMENT_TYPE_ANYWHERE | $SECTION_TYPE_DEFLATED);
our $FLASH_BOOT_FLAG = 0x80000000;
our $IMG_FILE_HEADER_LEN = 4 + # 4 x image file magic
32+ # 32 x description ASCII
4 + # 4 x CPU num
4 + # 4 x stack address
4 + # 4 x entry point address
4 + # 4 x number of sections
# 1st section info:
4 + # 4 x section type
4 + # 4 x source address
4 + # 4 x destination address
4; # 4 x length
our $verboseOutput = 0; # Verbosity of scripts
our $useST40Addressing = 0; # Currently using ST40 addressing - will be set by
# getELFArch, but scripts may set independently too
# Cryptocore values
our $LEN_CONFIG_INFO_FOR_BLOCK = 20; # In bytes (5 entries)
# Length in bytes of .post_(text|rodata)_reserve sections
our $RESERVE_1024_BIT_KEY = 60 + 16 + 128 + $LEN_CONFIG_INFO_FOR_BLOCK;
# The 60 above is the maximum wasted space after the end of the block we are
# signing before we can put the reserved 16 bytes (4 words of the config_table
# entry) to get us to a 64-byte aligned address.
our $RESERVE_2048_BIT_KEY = $RESERVE_1024_BIT_KEY + 128; # Doubled length of digital sig
################
# File private #
################
my $siggen_on_path = 1;
my $publicExponent = undef; # Default used by siggen is 3
my $DEFAULT_PUBLIC_EXPONENT = 3;
my ($objcopy, $readelf, $objdump) = undef;# The binutils tools to use will be stored in here
########
# Subs #
########
#
# Helper subs to manage temp files
#
my @tmpnames = ();
sub createtmpname()
{
my $tmpname = mktemp($::script_bname . "XXXX");
push @tmpnames, $tmpname;
return $tmpname;
}
sub unlinktmpfiles()
{
foreach my $tmpname (@tmpnames)
{
unlink($tmpname);
}
}
#
# Work out which tools to use (must be V2.13 or greater)
# Sets the globals (defined in calling script) $objcopy, $readelf and $objdump
# Note: If an argument is passed it should be either "sh4" or "st200", used to
# restrict which set of tools can be selected.
sub getTools(;$)
{
my $suffix = ($^O eq "MSWin32") ? ".exe" : "";
my ($l_objcopy, $l_readelf, $l_objdump);
my @prefixes = ("sh4", "st200", "st200-");
my $restrict = "";
if (scalar(@_) > 0)
{
$restrict = shift(@_);
@prefixes = grep(/$restrict/, @prefixes);
}
foreach my $path (path())
{
# "st200-" is included as a prefix here as a workaround on windows where not
# all of the shortcuts have a .exe extension, so the tools aren't found.
# I do wonder why the executables have the name st200- in the first place
# when these aren't the documented names though.
foreach my $prefix (@prefixes)
{
$l_objcopy = catfile($path, "${prefix}objcopy${suffix}");
$l_readelf = catfile($path, "${prefix}readelf${suffix}");
$l_objdump = catfile($path, "${prefix}objdump${suffix}");
if ((-x $l_objcopy) && (-x $l_readelf) && (-x $l_objdump))
{
my $tooLow = 0;
foreach my $cmd ($l_objcopy, $l_readelf, $l_objdump)
{
open(HANDLE, "$cmd --version|") or die("unable to open pipe ($!), stopped");
while (<HANDLE>)
{
if (/^GNU [a-z]+ ([0-9]+\.[0-9]+).*$/)
{
close(HANDLE);
if ($1 < "2.13")
{
$tooLow = 1;
}
last;
}
}
last if ($tooLow == 1);
}
if ($tooLow == 0)
{
$objcopy = $l_objcopy;
$readelf = $l_readelf;
$objdump = $l_objdump;
return;
}
}
}
}
die("$restrict binutils not on path or wrong version (min level 2.13), stopped");
}
# Accessor subs for objcopy, readelf and objdump
sub getObjcopy()
{
getTools() if (!defined($objcopy));
return $objcopy;
}
sub getReadelf()
{
getTools() if (!defined($readelf));
return $readelf;
}
sub getObjdump()
{
getTools() if (!defined($objdump));
return $objdump;
}
#
# Sub which uses readelf to return the machine architecture of the input ELF
# file
#
sub getELFArch($)
{
my $elfName = shift(@_);
my $architecture = undef;
my $cmd = getReadelf() . " -h $elfName";
print("Running command: $cmd\n") if ($verboseOutput);
open(OLDERR, ">&STDERR");
close(STDERR);
my $tmpFile = createtmpname();
open(STDERR, ">$tmpFile");
open(HANDLE, "$cmd |") or die("unable to open pipe ($!), stopped");
while (<HANDLE>)
{
if (/^ +Machine: +Hitachi SH\r?$/ || /^ +Machine: +Renesas \/ SuperH SH\r?$/)
{
$architecture = $CPU_ARCH_SH4;
$useST40Addressing = 1;
}
elsif (/^ +Machine: +<unknown>: 64\r?$/ ||
/STMicroelectronics ST200 processor/)
{
$architecture = $CPU_ARCH_LX;
}
}
close(HANDLE);
close(STDERR);
open(STDERR, ">&OLDERR");
close(OLDERR);
if (!defined($architecture))
{
die("failed to identify architecture of $elfName using command $cmd, stopped");
}
return $architecture;
}
#
# Sub to return the physical ST40 address for a given usable address. For an
# ST40 in 29-bit mode this is a matter of bit-twiddling, but for an SE mode
# application we have to check the ELF file to see if the .physrambase symbol is
# the same as the ___rambase symbol when masked to P0, and if not, and the given
# address is within RAM, we have to perform a little calculation!
#
sub physMemAddr($;$)
{
my $physAddr = undef;
my $inAddr = shift(@_);
# This needs to do nothing if the master CPU is an ST200
unless ($useST40Addressing)
{
return $inAddr;
}
# If we were given an ELF file, use it to try and work out how to convert to
# a physical address, otherwise fall-through to using P0 mask conversion a la
# 29-bit mode.
if (scalar(@_) > 0)
{
# 2nd arg is the name of an ELF file to use to work out if we are an SE mode
# application, and how to calculate the physical address from a virtual
# address.
my $elfFile = shift(@_);
my $cmd = getObjdump() . " -t $elfFile";
open(SYMINFO, "$cmd |") || die("unable to open pipe ($!), stopped");
my @interestingSyms = (".physrambase", "___rambase", "___ramsize");
my %addr;
my $line;
READ:while ($line = <SYMINFO>)
{
for my $symbol (@interestingSyms)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -