⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mkcommon.pm

📁 采用ST20 CPU的机顶盒的烧写程序
💻 PM
📖 第 1 页 / 共 3 页
字号:
#
# 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
                    &copySectionsToFile
                    &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 + -