Advertisement
SaintAnd

python2.GPTParserTool.py

Dec 2nd, 2022
1,034
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 124.22 KB | None | 0 0
  1. #!/usr/bin/python
  2. #===========================================================================
  3.      
  4. #  This script parses "partition.xml" and creates numerous output files
  5. #  specifically, partition.bin, rawprogram.xml
  6.  
  7. # REFERENCES
  8.  
  9. #  $Header: //components/rel/config.glue/8.0/storage/ptool.py#4 $
  10. #  $DateTime: 2017/04/28 21:47:00 $
  11. #  $Author: pwbldsvc $
  12.  
  13. # when          who     what, where, why
  14. # --------      ---     -------------------------------------------------------
  15. # 2016-04-05    wek     Grow the last partition if the configuration option says so.
  16. # 2015-08-04    wek     Bring in multiple changes done to ptool, for example, handle 4k sector size.
  17. # 2013-04-01    ah      Fixed rawprogram0_BLANK.xml to have correct size on last partition if GROW='true'
  18. # 2012-08-20    ah      Allow "uniqueguid" in partition.xml
  19. # 2012-08-16    ah      Fixed bug if PERFORMANCE_BOUNDARY_IN_KB wasn't specified
  20. # 2012-08-14    ah      PERFORMANCE_BOUNDARY_IN_KB can now be an individual partition tag
  21. # 2012-07-06    ah      More user friendly with ShowPartitionExample()
  22. # 2012-04-30    ah      GPT Attributes bits corrected
  23. # 2012-02-24    ah      Much cleaner code - fixes for configurable sector sizes
  24. # 2012-02-15    ah      Minor fix when 'SECTOR_SIZE_IN_BYTES' is not defined
  25. # 2012-01-13    ah      Fixed bug where rawprogram.xml was reporting numsectors off by 1
  26. # 2011-11-22    ah      Added SECTOR_SIZE_IN_BYTES option (defaults to 512)
  27. # 2011-11-17    ah      Added force128 partitions, option -k
  28. # 2011-11-14    ah      Enabled zeroout tag for GPT
  29. # 2011-10-19    ah      Not allowing empty <physical_partition> tags in partition.xml - makes multiple PHY partitions work
  30. # 2011-09-23    ah      GPT num partitions in table not fixed to 128, respecting partition table attributes now
  31. # 2011-08-12    ah      Added ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY, WRITE_PROTECT_GPT_PARTITION_TABLE
  32. # 2011-08-11    ah      Added Unique GUID option or Sequential -g (default is unique)
  33. # 2011-08-09    ah      Fix alignment issue for WPG<64MB - Fixed GPT off by 1 sector issue
  34. # 2011-08-04    ah      Now allowing -t option to specify output directory for files
  35. # 2011-07-26    ah      Much better error message if GUID invalid, fixed 'grow' partition size (patch)
  36. # 2011-07-21    ah      Major revision, using getopt(), auto-discovering GPT or MBR
  37. # 2011-07-13    ah      Corrected sparse support
  38. # 2011-06-01    ah      Added sparse support for GPT - corrected size of last partition
  39. # 2011-05-26    ah      Adds "zeroout" tag (wiping GPT) and "sparse" file support
  40. # 2011-05-21    ab      Undoing hack for boot to wipe out sector 1
  41. # 2011-05-17    ah      removing GPT sectors is simpler now, compatible with 8960 tz.mbn issue
  42. # 2011-05-06    ah      MBR partition tables now nuke any trace of GPT (request from boot team)
  43. # 2011-04-26    ah      temporarily removed 'start_byte_hex':szStartByte for QPST compatibility
  44. # 2011-03-23    ah      ensured last partition is size 0 for rawprogram.xml
  45. # 2011-03-22    ah      rawprogram for GPT for 'grow' partition, since mjsdload.cmm couldn't handle big number
  46. # 2011-03-22    ah      Corrected final disk size patch (off by 1 sector), corrected GPT labels (uni-code)
  47. # 2011-03-18    ah      Fixed default bug for DISK_SIGNATURE, align_wpb -> align
  48. # 2011-03-16    ah      New DISK_SIGNATURE tag added for MBR partitions, Split partition0.bin into
  49. #                       MBR0.bin and EBR0.bin, Corrected bug in backup GPT DISK patching
  50. # 2011-03-10    ah      Removes loadpt.cmm, splits partition0.bin to MBR0.bin, EBR0.bin
  51. # 2011-03-09    ah      Much more error checking, cleaner, adds "align_wpb" tag
  52. # 2011-02-14    ah      Added patching of DISK for GPT
  53. # 2011-02-02    ah      Allow MBR Type to be specified as "4C" or "0x4C"
  54. # 2011-25-01    ah      Outputs "patch.xml" as well, allows more optimal partition alignment
  55. # 2010-12-01    ah      Matching QPST, all EXT partitions 64MB aligned (configurable actually)
  56. #                       More error checking, Removed CHS option, GPT output is 2 files (primary and backup)
  57. # 2010-10-26    ah      better error checking, corrected typo on physical_partition for > 0
  58. # 2010-10-25    ah      adds GPT, CFILE output, various other features
  59. # 2010-10-08    ah      released to remove compile errors of missing PERL script modules
  60.  
  61. # Copyright (c) 2007-2016
  62. # Qualcomm Technologies Incorporated.
  63. # All Rights Reserved.
  64. # Qualcomm Confidential and Proprietary
  65. # ===========================================================================*/
  66.  
  67. import sys,os,getopt
  68. import random,math
  69. import re
  70. import struct
  71. from types import *
  72. from time import sleep
  73.  
  74. if sys.version_info < (2,5):
  75.     sys.stdout.write("\n\nERROR: This script needs Python version 2.5 or greater, detected as ")
  76.     print sys.version_info
  77.     sys.exit()  # error
  78.  
  79. from xml.etree import ElementTree as ET
  80. #from elementtree.ElementTree import ElementTree
  81. from xml.etree.ElementTree import Element, SubElement, Comment, tostring
  82. from xml.dom import minidom
  83.  
  84. OutputFolder            = ""
  85.  
  86. LastPartitionBeginsAt = 0
  87. HashInstructions       = {}
  88. tempVar = 5
  89.  
  90. NumPhyPartitions        = 0
  91. PartitionCollection     = []        # An array of Partition objects. Partition is a hash of information about partition
  92. PhyPartition            = {}        # An array of PartitionCollection objects
  93.  
  94. MinSectorsNeeded        = 0
  95. # Ex. PhyPartition[0] holds the PartitionCollection that holds all the info for partitions in PHY partition 0
  96.  
  97. AvailablePartitions = {}
  98. XMLFile = "module_common.py"
  99.  
  100. ExtendedPartitionBegins= 0
  101. instructions           = []
  102. HashStruct             = {}
  103.  
  104. StructPartitions       = []
  105. StructAdditionalFields = []
  106. AllPartitions          = {}
  107.  
  108. PARTITION_SYSTEM_GUID       =  0x3BC93EC9A0004BBA11D2F81FC12A7328
  109. PARTITION_MSFT_RESERVED_GUID=  0xAE1502F02DF97D814DB80B5CE3C9E316
  110. PARTITION_BASIC_DATA_GUID   =  0xC79926B7B668C0874433B9E5EBD0A0A2
  111.  
  112. SECTOR_SIZE_IN_BYTES = 512   # This can be over ridden in the partition.xml file
  113.  
  114. PrimaryGPT  = [0]*17408  # This gets redefined later based on SECTOR_SIZE_IN_BYTES This is LBA 0 to 33 (34 sectors total)    (start of disk)
  115. BackupGPT   = [0]*16896  # This gets redefined later based on SECTOR_SIZE_IN_BYTES This is LBA-33 to -1 (33 sectors total)   (end of disk)
  116.  
  117. EmptyGPT  = [0]*17408  # This gets redefined later based on SECTOR_SIZE_IN_BYTES This is LBA 0 to 33 (34 sectors total)    (start of disk)
  118.  
  119. PrimaryGPTNumLBAs=len(PrimaryGPT)/SECTOR_SIZE_IN_BYTES
  120. BackupGPTNumLBAs =len(BackupGPT)/SECTOR_SIZE_IN_BYTES
  121.  
  122. ## Note that these HashInstructions are updated by the XML file
  123.  
  124. HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']        = 64*1024
  125. HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']    = True
  126. HashInstructions['DISK_SIGNATURE']                      = 0x0
  127.  
  128. MBR         = [0]*SECTOR_SIZE_IN_BYTES
  129. EBR         = [0]*SECTOR_SIZE_IN_BYTES
  130.  
  131. hash_w       = [{'start_sector':0,'num_sectors':(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES),
  132.                  'end_sector':(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES)-1,'physical_partition_number':0,'boundary_num':0,'num_boundaries_covered':1}]
  133. NumWPregions = 0
  134.  
  135. def ShowPartitionExample():
  136.     print "Your \"partition.xml\" file needs to look like something like this below"
  137.     print "\t(i.e. notice the *multiple* physical_partition tags)\n"
  138.     print "<!-- This is physical partition 0 -->"
  139.     print "<physical_partition>"
  140.     print "  <partition label=\"SBL1\" size_in_kb=\"100\" type=\"DEA0BA2C-CBDD-4805-B4F9-F428251C3E98\" filename=\"sbl1.mbn\"/>"
  141.     print "</physical_partition>"
  142.     print " "
  143.     print "<!-- This is physical partition 1 -->"
  144.     print "<physical_partition>"
  145.     print "  <partition label=\"SBL2\" size_in_kb=\"200\" type=\"8C6B52AD-8A9E-4398-AD09-AE916E53AE2D\" filename=\"sbl2.mbn\"/>"
  146.     print "</physical_partition>"
  147.  
  148. def ConvertKBtoSectors(x):
  149.     ## 1KB / SECTOR_SIZE_IN_BYTES normally means return 2 (i.e. with SECTOR_SIZE_IN_BYTES=512)
  150.     ## 2KB / SECTOR_SIZE_IN_BYTES normally means return 4 (i.e. with SECTOR_SIZE_IN_BYTES=512)
  151.     return int((x*1024)/SECTOR_SIZE_IN_BYTES)
  152.  
  153. def UpdatePatch(StartSector,ByteOffset,PHYPartition,size_in_bytes,szvalue,szfilename,szwhat):
  154.     global PatchesXML
  155.  
  156.     SubElement(PatchesXML, 'patch', {'start_sector':StartSector, 'byte_offset':ByteOffset,
  157.                                      'physical_partition_number':str(PHYPartition), 'size_in_bytes':str(size_in_bytes),
  158.                                      'value':szvalue, 'filename':szfilename, 'SECTOR_SIZE_IN_BYTES':str(SECTOR_SIZE_IN_BYTES), 'what':szwhat   })
  159.  
  160.                    
  161. def UpdateRawProgram(RawProgramXML, StartSector, size_in_KB, PHYPartition, file_sector_offset, num_partition_sectors, filename, sparse, label,readbackverify='false', partofsingleimage='false'):
  162.     if StartSector<0:
  163.         szStartSector = "NUM_DISK_SECTORS%d." % StartSector      ## as in NUM_DISK_SECTORS-33 since %d=-33
  164.         szStartByte   = "(%d*NUM_DISK_SECTORS)%d." % (SECTOR_SIZE_IN_BYTES,StartSector*SECTOR_SIZE_IN_BYTES)
  165.     else:
  166.         #print "\nTo be here means StartSector>0"
  167.         #print "UpdateRawProgram StartSector=",StartSector
  168.         #print "StartSector=",type(StartSector)
  169.         #print "-----------------------------------------"
  170.        
  171.         szStartByte   = str(hex(StartSector*SECTOR_SIZE_IN_BYTES))
  172.         szStartSector = str(StartSector)
  173.  
  174.     #import pdb; pdb.set_trace()
  175.  
  176.     if num_partition_sectors<=0:
  177.         #print "*"*78
  178.         #print "WARNING: num_partition_sectors is %d for '%s' PHYPartition=%d, setting it to 0" % (num_partition_sectors,label,PHYPartition)
  179.         #print "\tThis can happen if you only have 1 partition and thus it is the grow partition"
  180.         num_partition_sectors = 0
  181.         size_in_KB = 0
  182.  
  183.     if erasefirst:
  184.         if label!="cdt":
  185.             SubElement(RawProgramXML, 'erase', {'start_sector':szStartSector, 'physical_partition_number':str(PHYPartition),
  186.                                                 'num_partition_sectors':str(num_partition_sectors), 'filename':filename,
  187.                                                 'SECTOR_SIZE_IN_BYTES':str(SECTOR_SIZE_IN_BYTES) })
  188.  
  189.  
  190.     SubElement(RawProgramXML, 'program', {'start_sector':szStartSector, 'size_in_KB':str(size_in_KB), 'physical_partition_number':str(PHYPartition), 'partofsingleimage':partofsingleimage,
  191.                                           'file_sector_offset':str(file_sector_offset), 'num_partition_sectors':str(num_partition_sectors), 'readbackverify':readbackverify,
  192.                                           'filename':filename,  'sparse':sparse, 'start_byte_hex':szStartByte,  'SECTOR_SIZE_IN_BYTES':str(SECTOR_SIZE_IN_BYTES), 'label':label       })                                              
  193.  
  194.  
  195.     #iter = RawProgramXML.getiterator()
  196.     #for element in iter:
  197.     #    print "\nElement:" , element.tag, " : ", element.text   # thins like image,primary,extended etc
  198.     #    if element.keys():
  199.     #        print "\tAttributes:"
  200.  
  201.     #        for name, value in element.items():
  202.     #            print "\t\tName: '%s'=>'%s' " % (name,value)
  203.  
  204.  
  205.     #import pdb; pdb.set_trace()
  206.  
  207.                    
  208.                    
  209. def PrintBigWarning(sz):
  210.     print "\t                          _             "
  211.     print "\t                         (_)            "
  212.     print "\t__      ____ _ _ __ _ __  _ _ __   __ _ "
  213.     print "\t\\ \\ /\\ / / _` | '__| '_ \\| | '_ \\ / _` |"
  214.     print "\t \\ V  V / (_| | |  | | | | | | | | (_| |"
  215.     print "\t  \\_/\\_/ \\__,_|_|  |_| |_|_|_| |_|\\__, |"
  216.     print "\t                                   __/ |"
  217.     print "\t                                  |___/ \n"
  218.  
  219.     if len(sz)>0:
  220.         print sz
  221.  
  222. def ValidGUIDForm(GUID):
  223.  
  224.     if type(GUID) is not str:
  225.         GUID = str(GUID)
  226.  
  227.     print "Testing if GUID=",GUID
  228.  
  229.     m = re.search("0x([a-fA-F\d]{32})$", GUID)     #0xC79926B7B668C0874433B9E5EBD0A0A2
  230.     if type(m) is not NoneType:
  231.         return True
  232.  
  233.     m = re.search("([a-fA-F\d]{8})-([a-fA-F\d]{4})-([a-fA-F\d]{4})-([a-fA-F\d]{2})([a-fA-F\d]{2})-([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})", GUID)
  234.     if type(m) is not NoneType:
  235.         return True
  236.  
  237.     print "GUID does not match regular expression"
  238.  
  239.     return False
  240.  
  241. def ValidateTYPE(Type):
  242.     # for type I must support the original "4C" and if they put "0x4C"
  243.  
  244.     if type(Type) is int:
  245.         if Type>=0 and Type<=255:
  246.             return Type
  247.  
  248.     if type(Type) is not str:
  249.         Type = str(Type)
  250.  
  251.     m = re.search("^(0x)?([a-fA-F\d][a-fA-F\d]?)$", Type)
  252.     if type(m) is NoneType:
  253.         print "\tWARNING: Type \"%s\" is not in the form 0x4C" % Type
  254.         sys.exit(1)
  255.     else:
  256.         #print m.group(2)
  257.         #print "---------"
  258.         #print "\tType is \"0x%X\"" % Type
  259.         return int(m.group(2),16)
  260.  
  261. def ValidateGUID(GUID):
  262.  
  263.     if type(GUID) is not str:
  264.         GUID = str(GUID)
  265.  
  266.     print "Looking to validate GUID=",GUID
  267.  
  268.     m = re.search("0x([a-fA-F\d]{32})$", GUID)     #0xC79926B7B668C0874433B9E5EBD0A0A2
  269.     if type(m) is not NoneType:
  270.         tempGUID = int(m.group(1),16)
  271.         print "\tGUID \"%s\"" % GUID
  272.  
  273.         if tempGUID == PARTITION_SYSTEM_GUID:
  274.             print "\tPARTITION_SYSTEM_GUID detected\n"
  275.         elif tempGUID == PARTITION_MSFT_RESERVED_GUID:
  276.             print "\tPARTITION_MSFT_RESERVED_GUID detected\n"
  277.         elif tempGUID == PARTITION_BASIC_DATA_GUID:
  278.             print "\tPARTITION_BASIC_DATA_GUID detected\n"
  279.         else:
  280.             print "\tUNKNOWN PARTITION_GUID detected\n"
  281.  
  282.         return tempGUID
  283.    
  284.     else:
  285.         #ebd0a0a2-b9e5-4433-87c0-68b6b72699c7  --> #0x C7 99 26 B7 B6 68 C087 4433 B9E5 EBD0A0A2
  286.         m = re.search("([a-fA-F\d]{8})-([a-fA-F\d]{4})-([a-fA-F\d]{4})-([a-fA-F\d]{2})([a-fA-F\d]{2})-([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})", GUID)
  287.         if type(m) is not NoneType:
  288.             print "Found more advanced type"
  289.             tempGUID = (int(m.group(4),16)<<64) | (int(m.group(3),16)<<48) | (int(m.group(2),16)<<32) | int(m.group(1),16)
  290.             tempGUID|= (int(m.group(8),16)<<96) | (int(m.group(7),16)<<88) | (int(m.group(6),16)<<80) | (int(m.group(5),16)<<72)
  291.             tempGUID|= (int(m.group(11),16)<<120)| (int(m.group(10),16)<<112)| (int(m.group(9),16)<<104)
  292.             print "** CONVERTED GUID \"%s\" is FOUND --> 0x%X" % (GUID,tempGUID)
  293.             return tempGUID
  294.         else:
  295.             print "\nWARNING: "+"-"*78
  296.             print "*"*78
  297.             print "WARNING: GUID \"%s\" is not in the form ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" % GUID
  298.             print "*"*78
  299.             print "WARNING"+"-"*78+"\n"
  300.             print "Converted to PARTITION_BASIC_DATA_GUID (0xC79926B7B668C0874433B9E5EBD0A0A2)\n"
  301.             return PARTITION_BASIC_DATA_GUID    
  302.    
  303. def EnsureDirectoryExists(filename):
  304.     dir = os.path.dirname(filename)
  305.  
  306.     try:
  307.         os.stat(dir)
  308.     except:
  309.         os.makedirs(dir)
  310.  
  311. def WriteGPT(GPTMAIN, GPTBACKUP, GPTEMPTY):
  312.     global opfile,PrimaryGPT,BackupGPT,GPTBOTH
  313.     #for b in PrimaryGPT:
  314.     #    opfile.write(struct.pack("B", b))
  315.     #for b in BackupGPT:
  316.     #    opfile.write(struct.pack("B", b))
  317.        
  318.     ofile = open(GPTMAIN, "wb")
  319.     for b in PrimaryGPT:
  320.         ofile.write(struct.pack("B", b))
  321.     ofile.close()
  322.  
  323.     print "\nCreated \"%s\"\t\t\t<-- Primary GPT partition tables + protective MBR" % GPTMAIN
  324.  
  325.     ofile = open(GPTBACKUP, "wb")
  326.     for b in BackupGPT:
  327.         ofile.write(struct.pack("B", b))
  328.     ofile.close()
  329.  
  330.     print "Created \"%s\"\t\t<-- Backup GPT partition tables" % GPTBACKUP
  331.  
  332.     ofile = open(GPTBOTH, "wb")
  333.     for b in PrimaryGPT:
  334.         ofile.write(struct.pack("B", b))
  335.     for b in BackupGPT:
  336.         ofile.write(struct.pack("B", b))
  337.     ofile.close()
  338.  
  339.     print "Created \"%s\" \t\t<-- you can run 'perl parseGPT.pl %s'" % (GPTBOTH,GPTBOTH)
  340.  
  341.     ## EmptyGPT is just all 0's, let's fill in the correct data
  342.     FillInEmptyGPT()
  343.  
  344.     ofile = open(GPTEMPTY, "wb")
  345.     for b in EmptyGPT:
  346.         ofile.write(struct.pack("B", b))
  347.     ofile.close()
  348.  
  349.     print "Created \"%s\"\t\t<-- Empty GPT partition table, use to force EDL mode (very useful)" % GPTEMPTY
  350.  
  351. def FillInEmptyGPT():
  352.     global EmptyGPT
  353.  
  354.     i=SECTOR_SIZE_IN_BYTES+16
  355.     EmptyGPT[0:i]       = PrimaryGPT[0:i]  ## this copies up to EFI PART, REVISION and HEADER SIZE
  356.     EmptyGPT[i:i+4]     = [0xD6, 0x51, 0x5B, 0x44] # CRC32
  357.     i+=8
  358.     EmptyGPT[i:i+1]     = [0x01] # Current LBA
  359.     i+=16
  360.     EmptyGPT[i:i+1]     = [0x22] # First useable LBA
  361.     i+=16
  362.     EmptyGPT[i:i+16]    = [0x32, 0x1B, 0x10, 0x98, 0xE2, 0xBB, 0xF2, 0x4B, 0xA0, 0x6E, 0x2B, 0xB3, 0x3D, 0x00, 0x0C, 0x20] # DISK GUID
  363.     i+=16
  364.     EmptyGPT[i:i+1]     = [0x02] # Starting LBA
  365.     i+=8
  366.     EmptyGPT[i:i+16]    = [0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x04, 0x87, 0x5D, 0x3C, 0x00, 0x00, 0x00, 0x00] # Num Entries, Size of Array, CRC
  367.  
  368.     i=2*SECTOR_SIZE_IN_BYTES+16
  369.     EmptyGPT[i:i+16]    = [0x6B, 0xCA, 0x1F, 0xEF, 0x31, 0x26, 0xC9, 0x95, 0x5C, 0x13, 0x61, 0xEB, 0x3F, 0xCF, 0x87, 0xF9]  # unique GUID
  370.     i+=16
  371.     EmptyGPT[i:i+1]     = [0x22] # first LBA
  372.     i+=8
  373.     EmptyGPT[i:i+2]     = [0x21, 0x02]  # last LBA
  374.     i+=16
  375.     EmptyGPT[i:i+9]     = [0x65, 0x00, 0x6D, 0x00, 0x70, 0x00, 0x74, 0x00, 0x79]    # unicode "empty" partition name
  376.  
  377.    
  378.  
  379. def UpdatePrimaryGPT(value,length,i):
  380.     global PrimaryGPT
  381.     for b in range(length):
  382.         PrimaryGPT[i] = ((value>>(b*8)) & 0xFF) ; i+=1
  383.     return i
  384.  
  385. def UpdateBackupGPT(value,length,i):
  386.     global BackupGPT
  387.     for b in range(length):
  388.         BackupGPT[i] = ((value>>(b*8)) & 0xFF) ; i+=1
  389.     return i
  390.  
  391. def ShowBackupGPT(sector):
  392.     global BackupGPT
  393.     print "Sector: %d" % sector
  394.     for j in range(32):
  395.         for i in range(16):
  396.             sys.stdout.write("%.2X " % BackupGPT[i+j*16+sector*SECTOR_SIZE_IN_BYTES])
  397.         print " "
  398.     print " "
  399.  
  400. def CreateFileOfZeros(filename,num_sectors):
  401.  
  402.     try:
  403.         opfile = open(filename, "w+b")
  404.     except Exception, x:
  405.         print "ERROR: Could not create '%s', cwd=%s" % (filename,os.getcwd() )
  406.         print "REASON: %s" % (x)
  407.         sys.exit(1)
  408.        
  409.     temp = [0]*(SECTOR_SIZE_IN_BYTES*num_sectors)
  410.     zeros = struct.pack("%iB"%(SECTOR_SIZE_IN_BYTES*num_sectors),*temp)
  411.     try:
  412.         opfile.write(zeros)
  413.     except Exception, x:
  414.         print "ERROR: Could not write zeros to '%s'\nREASON: %s" % (filename,x)
  415.         sys.exit(1)
  416.    
  417.     try:
  418.         opfile.close()
  419.     except Exception, x:
  420.         print "\tWARNING: Could not close %s" % filename
  421.         print "REASON: %s" % (x)
  422.  
  423.     print "Created \"%s\"\t\t<-- full of binary zeros - used by \"wipe\" rawprogram files" % filename
  424.            
  425. def CreateErasingRawProgramFiles():
  426.  
  427.     CreateFileOfZeros("zeros_1sector.bin",1)
  428.     CreateFileOfZeros("zeros_%dsectors.bin" % BackupGPTNumLBAs,BackupGPTNumLBAs)
  429.  
  430.     ##import pdb; pdb.set_trace()
  431.     for i in range(8):  # PHY partitions 0 to 7 exist (with 4,5,6,7 as GPPs)
  432.         if i==3:
  433.             continue    # no such PHY partition as of Feb 23, 2012
  434.         temp = Element('data')
  435.         temp.append(Comment('NOTE: This is an ** Autogenerated file **'))
  436.         temp.append(Comment('NOTE: Sector size is %ibytes'%SECTOR_SIZE_IN_BYTES))
  437.  
  438.         UpdateRawProgram(temp,0, 0.5, i, 0, 1, "zeros_33sectors.bin", "false", "Overwrite MBR sector")
  439.         UpdateRawProgram(temp,1, BackupGPTNumLBAs*SECTOR_SIZE_IN_BYTES/1024.0, i, 0, BackupGPTNumLBAs, "zeros_%dsectors.bin" % BackupGPTNumLBAs, "false", "Overwrite Primary GPT Sectors")
  440.         UpdateRawProgram(temp,-BackupGPTNumLBAs, BackupGPTNumLBAs*SECTOR_SIZE_IN_BYTES/1024.0, i, 0, BackupGPTNumLBAs, "zeros_%dsectors.bin" % BackupGPTNumLBAs, "false", "Overwrite Backup GPT Sectors")
  441.  
  442.         RAW_PROGRAM = '%swipe_rawprogram_PHY%d.xml' % (OutputFolder,i)
  443.  
  444.         opfile = open(RAW_PROGRAM, "w")
  445.         opfile.write( prettify(temp) )
  446.         opfile.close()
  447.         print "Created \"%s\"\t<-- Used to *wipe/erase* partition information" % RAW_PROGRAM
  448.  
  449.    
  450. NumPartitions       = 0
  451. SizeOfPartitionArray= 0
  452.  
  453. def CreateGPTPartitionTable(PhysicalPartitionNumber,UserProvided=False):
  454.     global opfile,PhyPartition,PrimaryGPT,BackupGPT,EmptyGPT,RawProgramXML, GPTMAIN, GPTBACKUP, GPTBOTH, RAW_PROGRAM, PATCHES, PrimaryGPTNumLBAs, BackupGPTNumLBAs
  455.  
  456.     print "\n\nMaking GUID Partitioning Table (GPT)"
  457.  
  458.     #PrintBanner("instructions")
  459.  
  460.     #print "\nGoing through partitions listed in XML file"
  461.  
  462.     ## Step 2. Move through partitions resizing as needed based on WRITE_PROTECT_BOUNDARY_IN_KB
  463.  
  464.     #print "\n\n--------------------------------------------------------"
  465.     #print "This is the order of the partitions"
  466.     # I most likely need to resize at least one partition below to the WRITE_PROTECT_BOUNDARY_IN_KB boundary
  467.     #for k in range(len(PhyPartition)):
  468.  
  469.     k = PhysicalPartitionNumber
  470.  
  471.     GPTMAIN                     = '%sgpt_main%d.bin'        % (OutputFolder,k)
  472.     GPTEMPTY                    = '%sgpt_empty%d.bin'       % (OutputFolder,k)
  473.     GPTBACKUP                   = '%sgpt_backup%d.bin'      % (OutputFolder,k)
  474.     GPTBOTH                     = '%sgpt_both%d.bin'        % (OutputFolder,k)
  475.     RAW_PROGRAM                 = '%srawprogram%d.xml'      % (OutputFolder,k)
  476.     RAW_PROGRAM_WIPE_PARTITIONS = '%srawprogram%d_WIPE_PARTITIONS.xml'% (OutputFolder,k)
  477.     RAW_PROGRAM_BLANK_GPT       = '%srawprogram%d_BLANK_GPT.xml'% (OutputFolder,k)
  478.     PATCHES                     = '%spatch%i.xml'           % (OutputFolder,k)
  479.  
  480.     #for k in range(1):
  481.  
  482.     #PrimaryGPT = [0]*(34*SECTOR_SIZE_IN_BYTES)  # This is LBA 0 to 33 (34 sectors total)    (start of disk)
  483.     #BackupGPT  = [0]*(33*SECTOR_SIZE_IN_BYTES)  # This is LBA-33 to -1 (33 sectors total)   (end of disk)
  484.     if SECTOR_SIZE_IN_BYTES==4096:
  485.         PrimaryGPT = [0]*(1*SECTOR_SIZE_IN_BYTES+1*SECTOR_SIZE_IN_BYTES+4*SECTOR_SIZE_IN_BYTES)
  486.         BackupGPT  = [0]*(1*SECTOR_SIZE_IN_BYTES+4*SECTOR_SIZE_IN_BYTES)
  487.         EmptyGPT   = [0]*(1*SECTOR_SIZE_IN_BYTES+1*SECTOR_SIZE_IN_BYTES+4*SECTOR_SIZE_IN_BYTES)
  488.     else:
  489.         PrimaryGPT = [0]*(34*SECTOR_SIZE_IN_BYTES)  # This is LBA 0 to 33 (34 sectors total)    (start of disk)
  490.         BackupGPT  = [0]*(33*SECTOR_SIZE_IN_BYTES)  # This is LBA-33 to -1 (33 sectors total)   (end of disk)
  491.         EmptyGPT   = [0]*(34*SECTOR_SIZE_IN_BYTES)  # This is LBA 0 to 33 (34 sectors total)    (start of disk)
  492.  
  493.  
  494.     ## ---------------------------------------------------------------------------------
  495.     ## Step 2. Move through xml definition and figure out partitions sizes
  496.     ## ---------------------------------------------------------------------------------
  497.  
  498.     PrimaryGPTNumLBAs=len(PrimaryGPT)/SECTOR_SIZE_IN_BYTES
  499.     BackupGPTNumLBAs =len(BackupGPT)/SECTOR_SIZE_IN_BYTES
  500.     i           = 2*SECTOR_SIZE_IN_BYTES    ## partition arrays begin here
  501.    
  502.     if (PhyPartition[0][0]['firstlba']) >= 0:
  503.     FirstLBA    =  PhyPartition[0][0]['firstlba']
  504.     print "\nForcing start LBA to %i" % FirstLBA
  505.     else:
  506.     FirstLBA    = PrimaryGPTNumLBAs
  507.     LastLBA     = FirstLBA               ## Make these equal at first
  508.  
  509.     if HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] is True:
  510.         UpdateWPhash(FirstLBA, 0)   # make sure 1st write protect boundary is setup correctly
  511.  
  512.     #print "len(PhyPartition)=%d and k=%d" % (len(PhyPartition),k)
  513.    
  514.     if(k>=len(PhyPartition)):
  515.         if UserProvided==True:
  516.             print "\nERROR: PHY Partition %i of %i not found" % (k,len(PhyPartition))
  517.             print "\nERROR: PHY Partition %i of %i not found\n\n" % (k,len(PhyPartition))
  518.             ShowPartitionExample()
  519.             sys.exit()
  520.         else:
  521.             print "\nERROR: PHY Partition %i of %i not found\n\n" % (k,len(PhyPartition))
  522.             return  ## Automatically trying to do 0 to 7, and some don't exist, which is to be expected
  523.  
  524.     SectorsTillNextBoundary = 0
  525.  
  526.  
  527.     print "\n\nOn PHY Partition %d that has %d partitions" % (k,len(PhyPartition[k]))
  528.     for j in range(len(PhyPartition[k])):
  529.         #print "\nPartition name='%s' (readonly=%s)" % (PhyPartition[k][j]['label'], PhyPartition[k][j]['readonly'])
  530.         #print "\tat sector location %d (%d KB or %.2f MB) and LastLBA=%d" % (FirstLBA,FirstLBA/2,FirstLBA/2048,LastLBA)
  531.         #print "%d of %d with label %s" %(j,len(PhyPartition[k]),PhyPartition[k][j]['label'])
  532.  
  533.         print "\n"+"="*78
  534.         print " _   (\"-._   (\"-._   (\"-._   (\"-._   (\"-._   (\"-._   (\"-._   (\"-._   (\"-."
  535.         print "   )   )   )   )   )   )   )   )   )   )   )   )   )   )   )   )   )   )"
  536.         print "  (_,-\"   (_,-\"   (_,-\"   (_,-\"   (_,-\"   (_,-\"   (_,-\"   (_,-\"   (_,-\""
  537.         print "="*78
  538.  
  539.     if (PhyPartition[k][j]['firstlba']) >= 0:
  540.         FirstLBA    =  PhyPartition[k][j]['firstlba']
  541.         print "\nForcing start LBA to %i" % FirstLBA
  542.  
  543.         PhyPartition[k][j]['size_in_kb'] = int(PhyPartition[k][j]['size_in_kb'])
  544.         print "\n\n%d of %d \"%s\" (readonly=%s) and size=%dKB (%dMB) (%i sectors with %i bytes/sector)" %(j+1,len(PhyPartition[k]),PhyPartition[k][j]['label'],PhyPartition[k][j]['readonly'],PhyPartition[k][j]['size_in_kb'],PhyPartition[k][j]['size_in_kb']/1024,ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb']),SECTOR_SIZE_IN_BYTES)
  545.  
  546.         if (PhyPartition[k][j]['size_in_kb']*1024)%SECTOR_SIZE_IN_BYTES>0:
  547.             ## Have a remainder, need to round up to next full sector
  548.             TempResult = (PhyPartition[k][j]['size_in_kb']*1024)/SECTOR_SIZE_IN_BYTES
  549.             TempResult +=1
  550.             PhyPartition[k][j]['size_in_kb'] = (TempResult * SECTOR_SIZE_IN_BYTES)/1024
  551.  
  552.             ##import pdb; pdb.set_trace() ## verifying sizes
  553.        
  554.     if HashInstructions['PERFORMANCE_BOUNDARY_IN_KB']>0 and HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] is False:
  555.         PrintBigWarning("WARNING: HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'] is %i KB\n\tbut HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] is FALSE!!\n\n" % HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'])
  556.         PrintBigWarning("WARNING: This means partitions will *NOT* be aligned to a HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'] of %i KB !!\n\n" % HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'])
  557.         print "To correct this, partition.xml should look like this\n"
  558.         print "\t<parser_instructions>"
  559.         print "\t\tPERFORMANCE_BOUNDARY_IN_KB = %i" % Partition['PERFORMANCE_BOUNDARY_IN_KB']
  560.         print "\t\tALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY=true"
  561.         print "\t</parser_instructions>\n\n"
  562.    
  563.         if HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] is True:
  564.             ## to be here means this partition *must* be on an ALIGN boundary
  565.             print "\tAlignment is to %iKB" % PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']
  566.             SectorsTillNextBoundary = ReturnNumSectorsTillBoundary(FirstLBA,PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']) ## hi
  567.             if SectorsTillNextBoundary>0:
  568.                 print "\tSectorsTillNextBoundary=%d, FirstLBA=%d it needs to be moved to be aligned to %d" % (SectorsTillNextBoundary,FirstLBA,FirstLBA + SectorsTillNextBoundary)
  569.                 ##print "\tPhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']=",PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']
  570.                 FirstLBA += SectorsTillNextBoundary
  571.     else:
  572.         if PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']>0:
  573.             print "\tThis partition is *NOT* aligned to a performance boundary\n"
  574.    
  575.         if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0:
  576.             SectorsTillNextBoundary = ReturnNumSectorsTillBoundary(FirstLBA,HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'])
  577.  
  578.         if PhyPartition[k][j]['readonly']=="true":
  579.             ## to be here means this partition is read-only, so see if we need to move the start
  580.             if FirstLBA <= hash_w[NumWPregions]["end_sector"]:
  581.                 print "\tWe *don't* need to move FirstLBA (%d) since it's covered by the end of the current WP region (%d)" % (FirstLBA,hash_w[NumWPregions]["end_sector"])
  582.                 pass
  583.             else:
  584.                 print "\tFirstLBA (%d) is *not* covered by the end of the WP region (%d),\n\tit needs to be moved to be aligned to %d" % (FirstLBA,hash_w[NumWPregions]["end_sector"],FirstLBA + SectorsTillNextBoundary)
  585.                 FirstLBA += SectorsTillNextBoundary
  586.  
  587.         else:
  588.             print "\n\tThis partition is *NOT* readonly"
  589.             ## to be here means this partition is writeable, so see if we need to move the start
  590.             if FirstLBA <= hash_w[NumWPregions]["end_sector"]:
  591.                 print "\tWe *need* to move FirstLBA (%d) since it's covered by the end of the current WP region (%d)" % (FirstLBA,hash_w[NumWPregions]["end_sector"])
  592.                 print "\nhash_w[NumWPregions]['end_sector']=%i" % hash_w[NumWPregions]["end_sector"];
  593.                 print "FirstLBA=%i\n" %FirstLBA;
  594.                 FirstLBA += SectorsTillNextBoundary
  595.  
  596.                 print "\tFirstLBA is now %d" % (FirstLBA)
  597.             else:
  598.                 #print "Great, We *don't* need to move FirstLBA (%d) since it's *not* covered by the end of the current WP region (%d)" % (FirstLBA,hash_w[NumWPregions]["end_sector"])
  599.                 pass
  600.  
  601.         if (j+1) == len(PhyPartition[k]):
  602.             print "\nTHIS IS THE *LAST* PARTITION"
  603.  
  604.             if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==True:
  605.  
  606.                 print "\nMeans patching instructions go here"
  607.    
  608.                 PhyPartition[k][j]['size_in_kb']  = 0 # infinite huge
  609.                 print "PhyPartition[k][j]['size_in_kb'] set to 0"
  610.                 SectorsRemaining = BackupGPTNumLBAs
  611.  
  612.                 print "LastLBA=",LastLBA
  613.                 print "FirstLBA=",FirstLBA
  614.  
  615.                 # gpt patch - size of last partition ################################################
  616.                 #StartSector         = 2*512+40+j*128        ## i.e. skip sector 0 and 1, then it's offset
  617.                 #ByteOffset          = str(StartSector%512)
  618.                 #StartSector         = str(int(StartSector / 512))
  619.    
  620.                 StartSector         = 40+j*128        ## i.e. skip sector 0 and 1, then it's offset
  621.                 ByteOffset          = str(StartSector%SECTOR_SIZE_IN_BYTES)
  622.                 StartSector         = str(2+int(StartSector / SECTOR_SIZE_IN_BYTES))
  623.                    
  624.                 BackupStartSector   = 40+j*128
  625.                 ByteOffset          = str(BackupStartSector%SECTOR_SIZE_IN_BYTES)
  626.                 BackupStartSector   = int(BackupStartSector / SECTOR_SIZE_IN_BYTES)
  627.                    
  628.                 ## gpt patch - main gpt partition array
  629.                 UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % PrimaryGPTNumLBAs,os.path.basename(GPTMAIN),"Update last partition %d '%s' with actual size in Primary Header." % ((j+1),PhyPartition[k][j]['label']))
  630.                 UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % PrimaryGPTNumLBAs,"DISK",              "Update last partition %d '%s' with actual size in Primary Header." % ((j+1),PhyPartition[k][j]['label']))
  631.  
  632.                        
  633.                 ## gpt patch - backup gpt partition array
  634.                 UpdatePatch(str(BackupStartSector),    ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % PrimaryGPTNumLBAs,os.path.basename(GPTBACKUP),"Update last partition %d '%s' with actual size in Backup Header." % ((j+1),PhyPartition[k][j]['label']))
  635.                 UpdatePatch("NUM_DISK_SECTORS-%d." % (BackupGPTNumLBAs-BackupStartSector),ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % PrimaryGPTNumLBAs,"DISK",                "Update last partition %d '%s' with actual size in Backup Header." % ((j+1),PhyPartition[k][j]['label']))
  636.    
  637.         LastLBA = FirstLBA + ConvertKBtoSectors( PhyPartition[k][j]['size_in_kb'] ) ## increase by num sectors, LastLBA inclusive, so add 1 for size
  638.         if (j+1) != len(PhyPartition[k]):
  639.         LastLBA -= 1  # inclusive, meaning 0 to 3 is 4 sectors
  640.  
  641.         #import pdb; pdb.set_trace()
  642.  
  643.         print "\n\tAt sector location %d with size %.2f MB (%d sectors) and LastLBA=%d (0x%X)" % (FirstLBA,PhyPartition[k][j]['size_in_kb']/1024.0,ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb']),LastLBA,LastLBA)
  644.        
  645.         if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0:
  646.             AlignedRemainder = FirstLBA % HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'];
  647.             if AlignedRemainder==0:
  648.                 print "\tWPB: This partition is ** ALIGNED ** to a %i KB boundary at sector %i (boundary %i)" % (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'],FirstLBA,FirstLBA/(ConvertKBtoSectors(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'])))
  649.  
  650.         if PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']>0:
  651.             AlignedRemainder = FirstLBA % PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB'];
  652.             if AlignedRemainder==0:
  653.                 print "\t"+"-"*78
  654.                 print "\tPERF: This partition is ** ALIGNED ** to a %i KB boundary at sector %i (boundary %i)" % (PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB'],FirstLBA,FirstLBA/(ConvertKBtoSectors(PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB'])))
  655.                 print "\t"+"-"*78
  656.  
  657.         if PhyPartition[k][j]['readonly']=="true":
  658.             UpdateWPhash(FirstLBA, ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb']))
  659.  
  660.         #print Partition.keys()
  661.         #print Partition.has_key("label")
  662.         #print "\tsize %i kB (%.2f MB)" % (PhyPartition[k][j]['size_in_kb'], PhyPartition[k][j]['size_in_kb']/1024)
  663.  
  664.         PartitionTypeGUID = PhyPartition[k][j]['type']
  665.         print "\nPartitionTypeGUID\t0x%X" % PartitionTypeGUID
  666.  
  667.         # If the partition is a multiple of 4, it must start on an LBA boundary of size SECTOR_SIZE_IN_BYTES
  668. #        if j%4==0 :
  669. #            # To be here means the partition number is a multiple of 4, so it must start on
  670. #            # an LBA boundary, i.e. LBA2, LBA3 etc.
  671. #            if i%SECTOR_SIZE_IN_BYTES > 0:
  672. #                print "\tWARNING: Location is %i, need to add %i to offset" % (i, SECTOR_SIZE_IN_BYTES-(i%SECTOR_SIZE_IN_BYTES))
  673. #                i += (SECTOR_SIZE_IN_BYTES-(i%SECTOR_SIZE_IN_BYTES))
  674. #            
  675. #            print "\n==============================================================================="
  676. #       print "This partition array entry (%i) is a multiple of 4 and must begin on a boundary of size %i bytes" % (j,SECTOR_SIZE_IN_BYTES)
  677. #            print "This partition array entry is at LBA%i, absolute byte address %i (0x%X)" % (i/SECTOR_SIZE_IN_BYTES,i,i)
  678. #       print "NOTE: LBA0 is protective MBR, LBA1 is Primary GPT Header, LBA2 beginning of Partition Array"
  679. #            print "===============================================================================\n"
  680.        
  681.         for b in range(16):
  682.             PrimaryGPT[i] = ((PartitionTypeGUID>>(b*8)) & 0xFF) ; i+=1
  683.  
  684.         # Unique Partition GUID
  685.         if sequentialguid == 1:
  686.             UniquePartitionGUID = j+1
  687.         else:
  688.             if PhyPartition[k][j]['uguid'] != "false":
  689.                 UniquePartitionGUID = PhyPartition[k][j]['uguid']
  690.             else:
  691.                 UniquePartitionGUID = random.randint(0,2**(128))
  692.  
  693.         print "UniquePartitionGUID\t0x%X" % UniquePartitionGUID
  694.        
  695.        
  696.         # This HACK section is for verifying with GPARTED, allowing me to put in
  697.         # whatever uniqueGUID that program came up with
  698.        
  699.         #if j==0:
  700.         #    UniquePartitionGUID = 0x373C17CF53BC7FB149B85A927ED24483
  701.         #elif j==1:
  702.         #    UniquePartitionGUID = 0x1D3C4663FC172F904EC7E0C7A8CF84EC
  703.         #elif j==2:
  704.         #    UniquePartitionGUID = 0x04A9B2AAEF96DAAE465F429D0EF5C6E2
  705.         #else:
  706.         #    UniquePartitionGUID = 0x4D82D027725FD3AE46AF1C5A28944977
  707.            
  708.         for b in range(16):
  709.             PrimaryGPT[i] = ((UniquePartitionGUID>>(b*8)) & 0xFF) ; i+=1
  710.  
  711.         # First LBA
  712.         for b in range(8):
  713.             PrimaryGPT[i] = ((FirstLBA>>(b*8)) & 0xFF) ; i+=1
  714.  
  715.         # Last LBA
  716.         for b in range(8):
  717.             PrimaryGPT[i] = ((LastLBA>>(b*8)) & 0xFF) ; i+=1
  718.        
  719.         print "**** FirstLBA=%d and LastLBA=%d and size is %i sectors" % (FirstLBA,LastLBA,LastLBA-FirstLBA+1)
  720.  
  721.         # Attributes
  722.         Attributes = 0x0
  723.         #import pdb; pdb.set_trace()
  724.  
  725.         if PhyPartition[k][j]['readonly']=="true":
  726.             Attributes |= 1<<60 ## Bit 60 is read only
  727.         if PhyPartition[k][j]['hidden']=="true":
  728.             Attributes |= 1<<62
  729.         if PhyPartition[k][j]['dontautomount']=="true":
  730.             Attributes |= 1<<63
  731.         if PhyPartition[k][j]['system']=="true":
  732.             Attributes |= 1<<0
  733.         if PhyPartition[k][j]['tries_remaining']>0:
  734.             Attributes |= PhyPartition[k][j]['tries_remaining']<<52
  735.         if PhyPartition[k][j]['priority']>0:
  736.             Attributes |= PhyPartition[k][j]['priority']<<48
  737.  
  738.         print "Attributes\t\t0x%X" % Attributes
  739.  
  740.         ##import pdb; pdb.set_trace()
  741.            
  742.         for b in range(8):
  743.             PrimaryGPT[i] = ((Attributes>>(b*8)) & 0xFF) ; i+=1
  744.  
  745.         if len(PhyPartition[k][j]['label'])>36:
  746.             print "Label %s is more than 36 characters, therefore it's truncated" % PhyPartition[k][j]['label']
  747.             PhyPartition[k][j]['label'] = PhyPartition[k][j]['label'][0:36]
  748.            
  749.         #print "LABEL %s and i=%i" % (PhyPartition[k][j]['label'],i)
  750.         # Partition Name
  751.         for b in PhyPartition[k][j]['label']:
  752.             PrimaryGPT[i] = ord(b) ; i+=1
  753.             PrimaryGPT[i] = 0x00   ; i+=1
  754.  
  755.         for b in range(36-len(PhyPartition[k][j]['label'])):
  756.             PrimaryGPT[i] = 0x00 ; i+=1
  757.             PrimaryGPT[i] = 0x00 ; i+=1
  758.        
  759.         #for b in range(2):
  760.         #    PrimaryGPT[i] = 0x00 ; i+=1
  761.         #for b in range(70):
  762.         #    PrimaryGPT[i] = 0x00 ; i+=1
  763.  
  764.         ##FileToProgram   = ""
  765.         ##FileOffset      = 0
  766.         PartitionLabel  = ""
  767.        
  768.         ## Default for each partition is no file
  769.         FileToProgram           = [""]
  770.         FileOffset              = [0]
  771.         FilePartitionOffset     = [0]
  772.         FileAppsbin             = ["false"]
  773.         FileSparse              = ["false"]
  774.  
  775.         if 'filename' in PhyPartition[k][j]:
  776.             ##print "filename exists"
  777.             #print PhyPartition[k][j]['filename']
  778.             #print FileToProgram[0]
  779.            
  780.         # These are all the default values that should be there, including an empty string possibly for filename
  781.             FileToProgram[0]            = PhyPartition[k][j]['filename'][0]
  782.             FileOffset[0]               = PhyPartition[k][j]['fileoffset'][0]
  783.             FilePartitionOffset[0]      = PhyPartition[k][j]['filepartitionoffset'][0]
  784.             FileAppsbin[0]              = PhyPartition[k][j]['appsbin'][0]
  785.             FileSparse[0]               = PhyPartition[k][j]['sparse'][0]
  786.            
  787.             for z in range(1,len(PhyPartition[k][j]['filename'])):
  788.                 FileToProgram.append( PhyPartition[k][j]['filename'][z] )
  789.                 FileOffset.append( PhyPartition[k][j]['fileoffset'][z] )
  790.                 FilePartitionOffset.append( PhyPartition[k][j]['filepartitionoffset'][z] )
  791.                 FileAppsbin.append( PhyPartition[k][j]['appsbin'][z] )
  792.                 FileSparse.append( PhyPartition[k][j]['sparse'][z] )
  793.  
  794.             #print PhyPartition[k][j]['fileoffset']
  795.            
  796.  
  797.         #for z in range(len(FileToProgram)):
  798.         #    print "FileToProgram[",z,"]=",FileToProgram[z]
  799.         #    print "FileOffset[",z,"]=",FileOffset[z]
  800.         #    print " "
  801.        
  802.  
  803.         if 'label' in PhyPartition[k][j]:
  804.             PartitionLabel = PhyPartition[k][j]['label']
  805.  
  806.         for z in range(len(FileToProgram)):
  807.         #print "===============================%i of %i===========================================" % (z,len(FileToProgram))
  808.             #print "File: ",FileToProgram[z]
  809.             #print "Label: ",FileToProgram[z]
  810.             #print "FilePartitionOffset[z]=",FilePartitionOffset[z]
  811.             #print "UpdateRawProgram(RawProgramXML,",(FirstLBA+FilePartitionOffset[z]),",",((LastLBA-FirstLBA)*SECTOR_SIZE_IN_BYTES/1024.0),",",PhysicalPartitionNumber,",",FileOffset[z],",",(LastLBA-FirstLBA-FilePartitionOffset[z]),",",(FileToProgram[z]),",", PartitionLabel,")"
  812.             #print "LastLBA=",LastLBA
  813.             #print "FirstLBA=",FirstLBA
  814.             #print "FilePartitionOffset[z]=",FilePartitionOffset[z]
  815.             UpdateRawProgram(RawProgramXML,
  816.                              FirstLBA+FilePartitionOffset[z], # Start sector
  817.                              ((LastLBA-FirstLBA+1))*SECTOR_SIZE_IN_BYTES/1024.0, # Size in KB
  818.                              PhysicalPartitionNumber,
  819.                              FileOffset[z],
  820.                              LastLBA-FirstLBA+1 - FilePartitionOffset[z], # num_partition_sectors
  821.                              FileToProgram[z],
  822.                              FileSparse[z],
  823.                              PartitionLabel,
  824.                              PhyPartition[k][j]['readbackverify'],
  825.                              PhyPartition[k][j]['partofsingleimage'])
  826.             if (j+1) == len(PhyPartition[k]):
  827.                 ## last partition, and if GROW was set to True, it will only have a size of 0
  828.                 UpdateRawProgram(RawProgramXML_Wipe,
  829.                                  FirstLBA+FilePartitionOffset[z], #Start Sector
  830.                                  (ConvertKBtoSectors(PhyPartition[k][j]['original_size_in_kb'])+(LastLBA-FirstLBA)+1)*SECTOR_SIZE_IN_BYTES/1024.0, # Size in KB
  831.                                  PhysicalPartitionNumber,
  832.                                  FileOffset[z],
  833.                                  ConvertKBtoSectors(PhyPartition[k][j]['original_size_in_kb'])+LastLBA-FirstLBA+1-FilePartitionOffset[z],
  834.                                  "zeros_33sectors.bin",
  835.                                  "false",
  836.                                  PartitionLabel,
  837.                                  PhyPartition[k][j]['readbackverify'],
  838.                                  PhyPartition[k][j]['partofsingleimage'])
  839.             else:
  840.                 UpdateRawProgram(RawProgramXML_Wipe,
  841.                                  FirstLBA+FilePartitionOffset[z], # Start Sector
  842.                                  ((LastLBA-FirstLBA)+1)*SECTOR_SIZE_IN_BYTES/1024.0,  # Size in KB
  843.                                  PhysicalPartitionNumber,
  844.                                  FileOffset[z],
  845.                                  LastLBA-FirstLBA+1-FilePartitionOffset[z], # num_partition_sectors
  846.                                  "zeros_33sectorS.bin",
  847.                                  "false",
  848.                                  PartitionLabel,
  849.                                  PhyPartition[k][j]['readbackverify'],
  850.                                  PhyPartition[k][j]['partofsingleimage'])
  851.  
  852.             if j==0:
  853.                 UpdateRawProgram(RawProgramXML_Blank,0, 33*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, FileOffset[z], 33, "gpt_empty%d.bin" % k, "false", "PrimaryGPT", "false", "false")
  854.        
  855.  
  856.         LastLBA += 1    ## move to the next free sector, also, 0 to 9 inclusive means it's 10
  857.                         ## so below (LastLBA-FirstLBA) must = 10
  858.  
  859.         FirstLBA = LastLBA      # getting ready for next partition, FirstLBA is now where we left off
  860.  
  861.  
  862.     ## Still working on *this* PHY partition
  863.  
  864.     ## making protective MBR, all zeros in buffer up until 0x1BE
  865.  
  866.     i = 0x1BE
  867.  
  868.     PrimaryGPT[i+0]         = 0x00                  # not bootable
  869.     PrimaryGPT[i+1]         = 0x00                  # head
  870.     PrimaryGPT[i+2]         = 0x01                  # sector
  871.     PrimaryGPT[i+3]         = 0x00                  # cylinder
  872.     PrimaryGPT[i+4]         = 0xEE                  # type
  873.     PrimaryGPT[i+5]         = 0xFF                  # head
  874.     PrimaryGPT[i+6]         = 0xFF                  # sector
  875.     PrimaryGPT[i+7]         = 0xFF                  # cylinder
  876.     PrimaryGPT[i+8:i+8+4]   = [0x01,0x00,0x00,0x00] # starting sector
  877.     PrimaryGPT[i+12:i+12+4] = [0xFF,0xFF,0xFF,0xFF] # starting sector
  878.  
  879.     PrimaryGPT[440]         = (HashInstructions['DISK_SIGNATURE']>>24)&0xFF
  880.     PrimaryGPT[441]         = (HashInstructions['DISK_SIGNATURE']>>16)&0xFF
  881.     PrimaryGPT[442]         = (HashInstructions['DISK_SIGNATURE']>>8)&0xFF
  882.     PrimaryGPT[443]         = (HashInstructions['DISK_SIGNATURE'])&0xFF
  883.  
  884.     PrimaryGPT[510:512]     = [0x55,0xAA]           # magic byte for MBR partitioning - always at this location regardless of SECTOR_SIZE_IN_BYTES
  885.  
  886.     i = SECTOR_SIZE_IN_BYTES
  887.     ## Signature and Revision and HeaderSize i.e. "EFI PART" and 00 00 01 00 and 5C 00 00 00
  888.     PrimaryGPT[i:i+16] = [0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54, 0x00, 0x00, 0x01, 0x00, 0x5C, 0x00, 0x00, 0x00] ; i+=16
  889.  
  890.     PrimaryGPT[i:i+4] = [0x00, 0x00, 0x00, 0x00]    ; i+=4  ## CRC is zeroed out till calculated later
  891.     PrimaryGPT[i:i+4] = [0x00, 0x00, 0x00, 0x00]    ; i+=4  ## Reserved, set to 0
  892.  
  893.     CurrentLBA= 1                                       ;   i = UpdatePrimaryGPT(CurrentLBA,8,i)
  894.     BackupLBA = 0                                       ;   i = UpdatePrimaryGPT(BackupLBA,8,i)
  895.     FirstLBA  = len(PrimaryGPT)/SECTOR_SIZE_IN_BYTES    ;   i = UpdatePrimaryGPT(FirstLBA,8,i)
  896.     LastLBA   = 0                                       ;   i = UpdatePrimaryGPT(LastLBA,8,i)
  897.  
  898.     ##print "\n\nBackup GPT is at sector %i" % BackupLBA
  899.     ##print "Last Usable LBA is at sector %i" % (LastLBA)
  900.  
  901.     DiskGUID = random.randint(0,2**(128))
  902.     i = UpdatePrimaryGPT(DiskGUID,16,i)
  903.  
  904.     PartitionsLBA = 2                       ;   i = UpdatePrimaryGPT(PartitionsLBA,8,i)
  905.     NumPartitions = (SECTOR_SIZE_IN_BYTES/128)*int(len(PhyPartition[k])/(SECTOR_SIZE_IN_BYTES/128))  # Want a multiple of (SECTOR_SIZE_IN_BYTES) to fill the sector (avoids gdisk warning)
  906.     if (len(PhyPartition[k])%(SECTOR_SIZE_IN_BYTES/128))>0:
  907.         NumPartitions+=(SECTOR_SIZE_IN_BYTES/128)
  908.  
  909.     if force128partitions == 1:
  910.         print "\n\nGPT table will list 128 partitions instead of ",NumPartitions
  911.         print "This makes the output compatible with some older test utilities"
  912.         NumPartitions = 128
  913.  
  914.     i = UpdatePrimaryGPT(NumPartitions,4,i) ## (offset 80) Number of partition entries
  915.     ##NumPartitions = 8    ;   i = UpdatePrimaryGPT(NumPartitions,4,i) ## (offset 80) Number of partition entries
  916.     SizeOfPartitionArray = 128              ;   i = UpdatePrimaryGPT(SizeOfPartitionArray,4,i) ## (offset 84) Size of partition entries
  917.  
  918.     ## Now I can calculate the partitions CRC
  919.     print "\n\nCalculating CRC with NumPartitions=%i, SizeOfPartitionArray=%i (bytes each) TOTAL LENGTH %d" % (NumPartitions,SizeOfPartitionArray,NumPartitions*SizeOfPartitionArray);
  920.     ##PartitionsCRC = CalcCRC32(PrimaryGPT[1024:],NumPartitions*SizeOfPartitionArray)  ## Each partition entry is 128 bytes
  921.  
  922.  
  923.     PartitionsPerSector = SECTOR_SIZE_IN_BYTES/128  ## 128 bytes per partition
  924.  
  925.     if NumPartitions>PartitionsPerSector:
  926.         SectorsToCalculateCRCOver = NumPartitions/PartitionsPerSector
  927.         if NumPartitions%PartitionsPerSector:
  928.             SectorsToCalculateCRCOver+=1
  929.     else:
  930.         SectorsToCalculateCRCOver = 1
  931.  
  932.     PartitionsCRC = CalcCRC32(PrimaryGPT[(2*SECTOR_SIZE_IN_BYTES):],SectorsToCalculateCRCOver * SECTOR_SIZE_IN_BYTES)  ## NAND HACK
  933.  
  934.    
  935.     i = UpdatePrimaryGPT(PartitionsCRC,4,i)
  936.     print "\n\nCalculated PARTITION CRC is 0x%.8X" % PartitionsCRC
  937.  
  938.     ## gpt patch - main gpt header - last useable lba                    
  939.     ByteOffset          = str(48)
  940.     StartSector         = str(1)
  941.     BackupStartSector   = str(BackupGPTNumLBAs-1)  ## Want last sector    ##str(32)
  942.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % PrimaryGPTNumLBAs,os.path.basename(GPTMAIN), "Update Primary Header with LastUseableLBA.")
  943.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % PrimaryGPTNumLBAs,"DISK",               "Update Primary Header with LastUseableLBA.")
  944.    
  945.     UpdatePatch(BackupStartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % PrimaryGPTNumLBAs,os.path.basename(GPTBACKUP), "Update Backup Header with LastUseableLBA.")
  946.     UpdatePatch("NUM_DISK_SECTORS-1.",ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % PrimaryGPTNumLBAs,"DISK",             "Update Backup Header with LastUseableLBA.")
  947.    
  948.     # gpt patch - location of backup gpt header ##########################################
  949.     ByteOffset          = str(32)
  950.     StartSector         = str(1)
  951.     ## gpt patch - main gpt header
  952.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-1.",os.path.basename(GPTMAIN), "Update Primary Header with BackupGPT Header Location.")
  953.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-1.","DISK",               "Update Primary Header with BackupGPT Header Location.")
  954.  
  955.     # gpt patch - currentLBA backup header ##########################################
  956.     ByteOffset          = str(24)
  957.     BackupStartSector   = str(BackupGPTNumLBAs-1)  ## Want last sector    ##str(32)
  958.     ## gpt patch - main gpt header
  959.     UpdatePatch(BackupStartSector,    ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-1.",os.path.basename(GPTBACKUP), "Update Backup Header with CurrentLBA.")
  960.     UpdatePatch("NUM_DISK_SECTORS-1.",ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-1.","DISK",                 "Update Backup Header with CurrentLBA.")
  961.  
  962.     # gpt patch - location of backup gpt header ##########################################
  963.     ByteOffset          = str(72)
  964.     BackupStartSector   = str(BackupGPTNumLBAs-1)  ## Want last sector    ##str(32)
  965.    
  966.     ## gpt patch - main gpt header
  967.     UpdatePatch(BackupStartSector,   ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % BackupGPTNumLBAs,os.path.basename(GPTBACKUP), "Update Backup Header with Partition Array Location.")
  968.     UpdatePatch("NUM_DISK_SECTORS-1",ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-%d." % BackupGPTNumLBAs,"DISK",                 "Update Backup Header with Partition Array Location.")
  969.  
  970.     # gpt patch - Partition Array CRC ################################################
  971.     ByteOffset          = str(88)
  972.     StartSector         = str(1)
  973.     BackupStartSector   = str(BackupGPTNumLBAs-1)  ## Want last sector    ##str(32)
  974.  
  975.     ## gpt patch - main gpt header
  976.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"CRC32(2,%d)" % (NumPartitions*SizeOfPartitionArray),os.path.basename(GPTMAIN), "Update Primary Header with CRC of Partition Array.") # CRC32(start_sector:num_bytes)
  977.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"CRC32(2,%d)" % (NumPartitions*SizeOfPartitionArray),"DISK",               "Update Primary Header with CRC of Partition Array.") # CRC32(start_sector:num_bytes)
  978.  
  979.     ## gpt patch - backup gpt header
  980.     UpdatePatch(BackupStartSector,    ByteOffset,PhysicalPartitionNumber,4,"CRC32(0,%d)" % (NumPartitions*SizeOfPartitionArray),os.path.basename(GPTBACKUP), "Update Backup Header with CRC of Partition Array.")   # CRC32(start_sector:num_bytes)
  981.     UpdatePatch("NUM_DISK_SECTORS-1.",ByteOffset,PhysicalPartitionNumber,4,"CRC32(NUM_DISK_SECTORS-%d.,%d)" % (BackupGPTNumLBAs,NumPartitions*SizeOfPartitionArray),"DISK",                 "Update Backup Header with CRC of Partition Array.")   # CRC32(start_sector:num_bytes)
  982.  
  983.     #print "\nNeed to patch PARTITION ARRAY, @ sector 1, byte offset 88, size=4 bytes, CRC32(2,33)"
  984.     #print "\nNeed to patch PARTITION ARRAY, @ sector -1, byte offset 88, size=4 bytes, CRC32(2,33)"
  985.  
  986.     ## Now I can calculate the Header CRC
  987.     ##print "\nCalculating CRC for Primary Header"
  988.     CalcHeaderCRC = CalcCRC32(PrimaryGPT[SECTOR_SIZE_IN_BYTES:],92)
  989.     UpdatePrimaryGPT(CalcHeaderCRC,4,SECTOR_SIZE_IN_BYTES+16)
  990.     #print "\n\nCalculated HEADER CRC is 0x%.8X" % CalcHeaderCRC
  991.  
  992.     #print "\nNeed to patch GPT HEADERS in 2 places"
  993.     #print "\nNeed to patch CRC HEADER, @ sector 1, byte offset 16, size=4 bytes, CRC32(1,1)"
  994.     #print "\nNeed to patch CRC HEADER, @ sector -1, byte offset 16, size=4 bytes, CRC32(1,1)"
  995.  
  996.     # gpt patch - Header CRC ################################################
  997.     ByteOffset          = str(16)
  998.     StartSector         = str(1)
  999.     BackupStartSector   = str(BackupGPTNumLBAs-1)  ## Want last sector    ##str(32)
  1000.  
  1001.     ## gpt patch - main gpt header
  1002.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"0",os.path.basename(GPTMAIN), "Zero Out Header CRC in Primary Header.")      # zero out old CRC first
  1003.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"CRC32(1,92)",os.path.basename(GPTMAIN), "Update Primary Header with CRC of Primary Header.") # CRC32(start_sector:num_bytes)
  1004.    
  1005.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"0",          "DISK", "Zero Out Header CRC in Primary Header.")      # zero out old CRC first
  1006.     UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"CRC32(1,92)","DISK", "Update Primary Header with CRC of Primary Header.") # CRC32(start_sector:num_bytes)
  1007.  
  1008.     ## gpt patch - backup gpt header
  1009.     #import pdb; pdb.set_trace()
  1010.     UpdatePatch(BackupStartSector,ByteOffset,PhysicalPartitionNumber,4,"0",os.path.basename(GPTBACKUP), "Zero Out Header CRC in Backup Header.")      # zero out old CRC first
  1011.     UpdatePatch(BackupStartSector,ByteOffset,PhysicalPartitionNumber,4,"CRC32(%s,92)" % BackupStartSector,os.path.basename(GPTBACKUP), "Update Backup Header with CRC of Backup Header.")  # CRC32(start_sector:num_bytes)
  1012.    
  1013.     UpdatePatch("NUM_DISK_SECTORS-1.",ByteOffset,PhysicalPartitionNumber,4,"0",           "DISK", "Zero Out Header CRC in Backup Header.")      # zero out old CRC first
  1014.     UpdatePatch("NUM_DISK_SECTORS-1.",ByteOffset,PhysicalPartitionNumber,4,"CRC32(NUM_DISK_SECTORS-1.,92)","DISK", "Update Backup Header with CRC of Backup Header.")  # CRC32(start_sector:num_bytes)
  1015.    
  1016.     ## now create the backup GPT partitions
  1017.     BackupGPT       = [0xFF]*(BackupGPTNumLBAs*SECTOR_SIZE_IN_BYTES)
  1018.     BackupGPT[0:]   = PrimaryGPT[2*SECTOR_SIZE_IN_BYTES:]
  1019.  
  1020.     ## now create the backup GPT header
  1021.  
  1022.     BackupGPT[(BackupGPTNumLBAs-1)*SECTOR_SIZE_IN_BYTES:BackupGPTNumLBAs*SECTOR_SIZE_IN_BYTES]= PrimaryGPT[1*SECTOR_SIZE_IN_BYTES:2*SECTOR_SIZE_IN_BYTES] ##BackupGPTNumLBAs=33
  1023.     #ShowBackupGPT(32)
  1024.  
  1025.     ## Need to update CurrentLBA, BackupLBA and then recalc CRC for this header
  1026.  
  1027.     i = (BackupGPTNumLBAs-1)*SECTOR_SIZE_IN_BYTES+8+4+4
  1028.     CalcHeaderCRC   = 0     ;   i = UpdateBackupGPT(CalcHeaderCRC,4,i)  ## zero out CRC
  1029.     CalcHeaderCRC   = 0     ;   i = UpdateBackupGPT(CalcHeaderCRC,4,i)  ## reserved 4 zeros
  1030.     CurrentLBA      = 0     ;   i = UpdateBackupGPT(CurrentLBA,8,i)
  1031.     BackupLBA       = 1     ;   i = UpdateBackupGPT(BackupLBA,8,i)
  1032.  
  1033.     #print "\n\nBackup GPT is at sector %i" % CurrentLBA
  1034.     #print "Last Usable LBA is at sector %i" % (CurrentLBA-33)
  1035.  
  1036.     i += 8+8+16
  1037.     PartitionsLBA   = 0     ;   i = UpdateBackupGPT(PartitionsLBA,8,i)
  1038.     #print "PartitionsLBA = %d (0x%X)" % (PartitionsLBA,PartitionsLBA)
  1039.  
  1040.     ##print "\nCalculating CRC for Backup Header"
  1041.     CalcHeaderCRC = CalcCRC32(BackupGPT[(BackupGPTNumLBAs-1)*SECTOR_SIZE_IN_BYTES:],92)
  1042.     #print "\nCalcHeaderCRC of BackupGPT is 0x%.8X" % CalcHeaderCRC
  1043.     i = (BackupGPTNumLBAs-1)*SECTOR_SIZE_IN_BYTES+8+4+4
  1044.     i = UpdateBackupGPT(CalcHeaderCRC,4,i)  ## zero out CRC
  1045.  
  1046.     #ShowBackupGPT(32)
  1047.  
  1048.     UpdateRawProgram(RawProgramXML,0,       PrimaryGPTNumLBAs*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0, PrimaryGPTNumLBAs, os.path.basename(GPTMAIN), 'false', 'PrimaryGPT','false','true')
  1049.     UpdateRawProgram(RawProgramXML_Wipe,0,  1*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0,  1, "zeros_33sectors.bin", 'false', 'PrimaryGPT','false','true')
  1050.     UpdateRawProgram(RawProgramXML_Wipe,1, BackupGPTNumLBAs*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0, BackupGPTNumLBAs, "zeros_%dsectors.bin" % BackupGPTNumLBAs, 'false', 'PrimaryGPT','false','true')
  1051.                              
  1052.     #print "szStartSector=%s" % szStartSector
  1053.  
  1054.     UpdateRawProgram(RawProgramXML,-BackupGPTNumLBAs,       BackupGPTNumLBAs*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0, BackupGPTNumLBAs, os.path.basename(GPTBACKUP), 'false', 'BackupGPT','false','true')
  1055.     UpdateRawProgram(RawProgramXML_Wipe,-BackupGPTNumLBAs, BackupGPTNumLBAs*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0, BackupGPTNumLBAs, "zeros_%dsectors.bin" % BackupGPTNumLBAs, 'false', 'BackupGPT','false','true')
  1056.    
  1057.  
  1058.     ##print "szStartSector=%s" % szStartSector
  1059.  
  1060.  
  1061.     WriteGPT(GPTMAIN, GPTBACKUP, GPTEMPTY)
  1062.  
  1063.     opfile = open(RAW_PROGRAM, "w")
  1064.     opfile.write( prettify(RawProgramXML) )
  1065.     opfile.close()
  1066.     print "\nCreated \"%s\"\t\t\t<-- YOUR partition information is HERE" % RAW_PROGRAM
  1067.  
  1068.     opfile = open(RAW_PROGRAM_WIPE_PARTITIONS, "w")
  1069.     opfile.write( prettify(RawProgramXML_Wipe) )
  1070.     opfile.close()
  1071.     print "Created \"%s\"\t<-- Wipe out your images with this file (if needed for testing)" % RAW_PROGRAM_WIPE_PARTITIONS
  1072.    
  1073.     opfile = open(RAW_PROGRAM_BLANK_GPT, "w")
  1074.     opfile.write( prettify(RawProgramXML_Blank) )
  1075.     opfile.close()
  1076.     print "Created \"%s\"\t\t<-- Valid empty GPT partition table (to force to EDL)" % RAW_PROGRAM_BLANK_GPT
  1077.  
  1078.     opfile = open(PATCHES, "w")             # gpt
  1079.     opfile.write( prettify(PatchesXML) )
  1080.     opfile.close()
  1081.     print "Created \"%s\"\t\t\t\t<-- Tailor your partition tables to YOUR device with this file\n" % PATCHES
  1082.  
  1083.  
  1084.  
  1085. def AlignVariablesToEqualSigns(sz):
  1086.     temp = re.sub(r"(\t| )+=","=",sz)
  1087.     temp = re.sub(r"=(\t| )+","=",temp)
  1088.     return temp
  1089.  
  1090. def ReturnArrayFromSpaceSeparatedList(sz):
  1091.     temp = re.sub(r"\s+|\n"," ",sz)
  1092.     temp = re.sub(r"^\s+","",temp)
  1093.     temp = re.sub(r"\s+$","",temp)
  1094.     return temp.split(' ')
  1095.  
  1096. def ParseXML(XMLFile):
  1097.     global OutputToCreate,NumPhyPartitions, PartitionCollection, PhyPartition,MinSectorsNeeded,SECTOR_SIZE_IN_BYTES
  1098.  
  1099.  
  1100.     root = ET.parse( XMLFile )
  1101.  
  1102.     #Create an iterator
  1103.     iter = root.getiterator()
  1104.  
  1105.     for element in iter:
  1106.         #print "\nElement:" , element.tag   # thins like image,primary,extended etc
  1107.  
  1108.         if element.tag=="parser_instructions":
  1109.             instructions = ReturnArrayFromSpaceSeparatedList(AlignVariablesToEqualSigns(element.text))
  1110.  
  1111.             for element in instructions:
  1112.                 temp = element.split('=')
  1113.                 if len(temp) > 1:
  1114.                     HashInstructions[temp[0].strip()] = temp[1].strip()
  1115.                     #print "HashInstructions['%s'] = %s" % (temp[0].strip(),temp[1].strip())
  1116.  
  1117.  
  1118.     if 'SECTOR_SIZE_IN_BYTES' in HashInstructions:
  1119.         if type(HashInstructions['SECTOR_SIZE_IN_BYTES']) is str:
  1120.             m = re.search("^(\d+)$", HashInstructions['SECTOR_SIZE_IN_BYTES'])
  1121.             if type(m) is NoneType:
  1122.                 ## we didn't match, so assign deafult
  1123.                 HashInstructions['SECTOR_SIZE_IN_BYTES'] = 512
  1124.                 SECTOR_SIZE_IN_BYTES = 512
  1125.             else:
  1126.                 HashInstructions['SECTOR_SIZE_IN_BYTES'] = int(HashInstructions['SECTOR_SIZE_IN_BYTES'])
  1127.                 SECTOR_SIZE_IN_BYTES = HashInstructions['SECTOR_SIZE_IN_BYTES']
  1128.  
  1129.                 PrintBigWarning("WARNING: SECTOR_SIZE_IN_BYTES CHANGED <-- This may impact your targets ability to read the partition tables!!")
  1130.                 print "\n\nWARNING: SECTOR_SIZE_IN_BYTES *changed* from 512bytes/sector to %ibytes/sector" % SECTOR_SIZE_IN_BYTES
  1131.                 print "WARNING: SECTOR_SIZE_IN_BYTES *changed* from 512bytes/sector to %ibytes/sector" % SECTOR_SIZE_IN_BYTES
  1132.                 print "WARNING: SECTOR_SIZE_IN_BYTES *changed* from 512bytes/sector to %ibytes/sector\n\n" % SECTOR_SIZE_IN_BYTES
  1133.                 sleep(2)
  1134.     else:
  1135.         #print "SECTOR_SIZE_IN_BYTES does not exist"
  1136.         HashInstructions['SECTOR_SIZE_IN_BYTES'] = 512
  1137.  
  1138.  
  1139.     if 'WRITE_PROTECT_BOUNDARY_IN_KB' in HashInstructions:
  1140.         if type(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']) is str:
  1141.             m = re.search("^(\d+)$", HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'])
  1142.             if type(m) is NoneType:
  1143.                 ## we didn't match, so assign deafult
  1144.                 HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] = 0
  1145.             else:
  1146.                 HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] = int(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'])
  1147.     else:
  1148.         #print "WRITE_PROTECT_BOUNDARY_IN_KB does not exist"
  1149.         HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] = 65536
  1150.  
  1151.     if 'PERFORMANCE_BOUNDARY_IN_KB' in HashInstructions:
  1152.         if type(HashInstructions['PERFORMANCE_BOUNDARY_IN_KB']) is str:
  1153.             m = re.search("^(\d+)$", HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'])
  1154.             if type(m) is NoneType:
  1155.                 ## we didn't match, so assign deafult
  1156.                 HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'] = 0
  1157.             else:
  1158.                 HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'] = int(HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'])
  1159.     else:
  1160.         #print "PERFORMANCE_BOUNDARY_IN_KB does not exist"
  1161.         HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'] = 0
  1162.  
  1163.     if 'GROW_LAST_PARTITION_TO_FILL_DISK' in HashInstructions:
  1164.         if type(HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']) is str:
  1165.             m = re.search("^(true)$", HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] ,re.IGNORECASE)
  1166.             #print type(m)
  1167.             if type(m) is NoneType:
  1168.                 HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = False    # no match
  1169.                 #print "assigned false"
  1170.             else:
  1171.                 HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = True     # matched string true
  1172.                 #print "assigned true"
  1173.     else:
  1174.         HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = False
  1175.  
  1176.     if 'WRITE_PROTECT_GPT_PARTITION_TABLE' in HashInstructions:
  1177.         if type(HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE']) is str:
  1178.             m = re.search("^(true)$", HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] ,re.IGNORECASE)
  1179.             #print type(m)
  1180.             if type(m) is NoneType:
  1181.                 HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] = False    # no match
  1182.                 #print "assigned false"
  1183.             else:
  1184.                 HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] = True     # matched string true
  1185.                 #print "assigned true"
  1186.     else:
  1187.         HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] = False
  1188.  
  1189.     if 'ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY' in HashInstructions:
  1190.         if type(HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY']) is str:
  1191.             m = re.search("^(true)$", HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] ,re.IGNORECASE)
  1192.             #print type(m)
  1193.             if type(m) is NoneType:
  1194.                 HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] = False    # no match
  1195.                 #print "assigned false"
  1196.             else:
  1197.                 HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] = True     # matched string true
  1198.                 #print "assigned true"
  1199.     else:
  1200.         HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] = False
  1201.  
  1202.     if 'USE_GPT_PARTITIONING' in HashInstructions:
  1203.         if type(HashInstructions['USE_GPT_PARTITIONING']) is str:
  1204.             m = re.search("^(true)$", HashInstructions['USE_GPT_PARTITIONING'] ,re.IGNORECASE)
  1205.             #print type(m)
  1206.             if type(m) is NoneType:
  1207.                 HashInstructions['USE_GPT_PARTITIONING'] = False    # no match
  1208.                 #print "assigned false"
  1209.             else:
  1210.                 HashInstructions['USE_GPT_PARTITIONING'] = True     # matched string true
  1211.                 #print "assigned true"
  1212.     else:
  1213.         HashInstructions['USE_GPT_PARTITIONING'] = False
  1214.  
  1215.  
  1216.     if 'DISK_SIGNATURE' in HashInstructions:
  1217.         if type(HashInstructions['DISK_SIGNATURE']) is str:
  1218.             m = re.search("^0x([\da-fA-F]+)$", HashInstructions['DISK_SIGNATURE'])
  1219.             if type(m) is NoneType:
  1220.                 print "WARNING: DISK_SIGNATURE is not formed correctly, expected format is 0x12345678\n"
  1221.                 HashInstructions['DISK_SIGNATURE'] = 0x00000000
  1222.             else:
  1223.                 HashInstructions['DISK_SIGNATURE'] = int(HashInstructions['DISK_SIGNATURE'],16)
  1224.     else:
  1225.         print "DISK_SIGNATURE does not exist"
  1226.         HashInstructions['DISK_SIGNATURE'] = 0x00000000
  1227.  
  1228.     if 'ALIGN_BOUNDARY_IN_KB' in HashInstructions:
  1229.         if type(HashInstructions['ALIGN_BOUNDARY_IN_KB']) is str:
  1230.             m = re.search("^(\d+)$", HashInstructions['ALIGN_BOUNDARY_IN_KB'])
  1231.             if type(m) is NoneType:
  1232.                 ## we didn't match, so assign deafult
  1233.                 HashInstructions['ALIGN_BOUNDARY_IN_KB'] = HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']
  1234.             else:
  1235.                 HashInstructions['ALIGN_BOUNDARY_IN_KB'] = int(HashInstructions['ALIGN_BOUNDARY_IN_KB'])
  1236.     else:
  1237.         #print "ALIGN_BOUNDARY_IN_KB does not exist"
  1238.         HashInstructions['ALIGN_BOUNDARY_IN_KB'] = HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248.  
  1249.     root = ET.parse( XMLFile )
  1250.  
  1251.     #Create an iterator
  1252.     iter = root.getiterator()
  1253.  
  1254.     ## Need to count how many partitions
  1255.     CheckPartitionCount = [0,0,0,0,0,0,0,0]
  1256.     CurrentPartition    = -1
  1257.  
  1258.     for element in iter:
  1259.         ##print "\nElement:" , element.tag   # thins like image,primary,extended etc
  1260.         if element.tag == "physical_partition":
  1261.             CurrentPartition+=1
  1262.             #print "Now on CurrentPartition=",CurrentPartition
  1263.         if element.tag == "partition":
  1264.             CheckPartitionCount[CurrentPartition] += 1
  1265.             #print "CheckPartitionCount[%d]=%d" % (CurrentPartition,CheckPartitionCount[CurrentPartition])
  1266.  
  1267.     for p in range(CurrentPartition+1):
  1268.         print "CheckPartitionCount[%d]=%d" % (p,CheckPartitionCount[p])
  1269.  
  1270.     CurrentPartition    = -1
  1271.     for element in iter:
  1272.         #print "\nElement:" , element.tag   # thins like image,primary,extended etc
  1273.  
  1274.         if element.tag=="physical_partition":
  1275.             # We can have this scenario meaning NumPhyPartitions++ but len(PhyPartition) doesn't increase
  1276.             # <physical_partition>
  1277.             # </physical_partition>
  1278.             # Thus if NumPhyPartitions > len(PhyPartition) by 2, then we need to increase it
  1279.  
  1280.             NumPhyPartitions            += 1
  1281.             CurrentPartition            = 0 ## Using this to count partitions
  1282.  
  1283.             PartitionCollection          = []    # Reset, we've found a new physical partition
  1284.  
  1285.             if NumPhyPartitions-len(PhyPartition)>=2:
  1286.                 print "\n\n"
  1287.                 print "*"*78
  1288.                 print "ERROR: Empty <physical_partition></physical_partition> tags detected\n"
  1289.                 print "Please replace with"
  1290.                 print "<physical_partition>"
  1291.                 print "<partition label='placeholder' size_in_kb='0' type='00000000-0000-0000-0000-000000000001' bootable='false' readonly='false' filename='' />"
  1292.                 print "</physical_partition>\n"
  1293.                 sys.exit()
  1294.  
  1295.             print "\nFound a physical_partition, NumPhyPartitions=%d" % NumPhyPartitions
  1296.             print "\nlen(PhyPartition)=%d" % len(PhyPartition)
  1297.  
  1298.  
  1299.         elif element.tag=="partition" or element.tag=="primary" or element.tag=="extended":
  1300.  
  1301.             CurrentPartition+=1
  1302.  
  1303.             if element.keys():
  1304.                 #print "\tAttributes:"
  1305.  
  1306.                 # Reset all variables to defaults
  1307.                 Partition = {}
  1308.  
  1309.                 # This partition could have more than 1 file, so these are arrays
  1310.                 # However, as I loop through the elements, *if* there is more than 1 file
  1311.                 # it will have it's own <file> tag
  1312.                 Partition['filename']            = [""]
  1313.                 Partition['fileoffset']          = [0]
  1314.                 Partition['appsbin']             = ["false"]
  1315.                 Partition['sparse']              = ["false"]
  1316.                 Partition['filepartitionoffset'] = [0]
  1317.  
  1318.                 Partition['size_in_kb']         = 0
  1319.                 Partition['original_size_in_kb']= 0
  1320.                 Partition["readonly"]           = "false"
  1321.                 Partition['label']              = "false"
  1322.                 Partition['type']               = "false"
  1323.                 Partition['uguid']              = "false"   ## unique guid
  1324.                 Partition['align']              = "false"
  1325.                 Partition['hidden']             = "false"
  1326.                 Partition['system']             = "false"
  1327.                 Partition['dontautomount']      = "false"
  1328.                 Partition['partofsingleimage']  = "false"
  1329.                 Partition['readbackverify']     = "false"
  1330.                 Partition['tries_remaining']    = 0
  1331.                 Partition['priority']           = 0
  1332.                 Partition['firstlba']   = -1
  1333.  
  1334.                 ##import pdb; pdb.set_trace()
  1335.                
  1336.                 if 'PERFORMANCE_BOUNDARY_IN_KB' in HashInstructions:
  1337.                     Partition['PERFORMANCE_BOUNDARY_IN_KB']  = int(HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'])
  1338.                 else:
  1339.                     Partition['PERFORMANCE_BOUNDARY_IN_KB']  = 0
  1340.  
  1341.                 FileFound = 0
  1342.  
  1343.                 print " "
  1344.  
  1345.                 for name, value in element.items():
  1346.                     #print "\t\tName: '%s'=>'%s' " % (name,value)
  1347.  
  1348.                     if name=='name' or name=='filename' :
  1349.                         Partition['filename'][-1] = value
  1350.                         FileFound = 1
  1351.                         print "Found a file tag '%s'" % value
  1352.                     elif name=='fileoffset':
  1353.                         Partition['fileoffset'][-1] = value
  1354.                     elif name=='label':
  1355.                         Partition['label'] = value
  1356.                         print "LABEL:",value
  1357.                     elif name=='offset' or name=='filepartitionoffset':
  1358.                         Partition['filepartitionoffset'][-1] = int(value)
  1359.                     elif name=='appsbin':
  1360.                         Partition['appsbin'][-1] = value
  1361.                     elif name=='sparse':
  1362.                         Partition['sparse'][-1] = value
  1363.                     elif name=='PERFORMANCE_BOUNDARY_IN_KB':
  1364.                         Partition['PERFORMANCE_BOUNDARY_IN_KB'] = int(value)
  1365.                     elif name=='type':
  1366.                         if ValidGUIDForm(value) is True:
  1367.                             if OutputToCreate is None:
  1368.                                 OutputToCreate = "gpt"
  1369.                             elif OutputToCreate is "mbr":
  1370.                                 PrintBigError("ERROR: Your partition.xml is possibly corrupt, please check the GUID TYPE field")
  1371.                             Partition['type'] = ValidateGUID(value)
  1372.  
  1373.                         else:
  1374.                             if OutputToCreate is None:
  1375.                                 OutputToCreate = "mbr"
  1376.                             elif OutputToCreate is "gpt":
  1377.                                 PrintBigError("ERROR: Your partition.xml is possibly corrupt, please check the TYPE field")
  1378.                             Partition['type'] = ValidateTYPE(value)
  1379.                     elif name=='uniqueguid':
  1380.                         if ValidGUIDForm(value) is True:
  1381.                             Partition['uguid'] = ValidateGUID(value)
  1382.                         else:
  1383.                             PrintBigError("ERROR: Your partition.xml is possibly corrupt, please check the TYPE field")
  1384.                     elif name=="triesremaining":
  1385.                         Partition['tries_remaining'] = int(value);
  1386.                     elif name=="priority":
  1387.                         Partition['priority']       = int(value);
  1388.                     elif name=="size":
  1389.                         if len(value)==0:
  1390.                             PrintBigError("\nERROR: Invalid partition size")
  1391.  
  1392.                         ## 'size' means in terms of sectors
  1393.                         TempSizeInBytes = int(value)/2        # force as even number
  1394.                         if TempSizeInBytes<2:
  1395.                             TempSizeInBytes = 2
  1396.                         TempSizeInBytes = TempSizeInBytes*SECTOR_SIZE_IN_BYTES  ## either 1K or 8K
  1397.  
  1398.                         Partition["size_in_kb"]=TempSizeInBytes/1024
  1399.                         Partition["original_size_in_kb"]=TempSizeInBytes/1024
  1400.                     elif name=="size_in_kb":
  1401.                         if len(value)==0:
  1402.                             PrintBigError("\nERROR: Invalid partition size")
  1403.  
  1404.  
  1405.                         if value=='0':
  1406.                             if CheckPartitionCount[NumPhyPartitions-1] == CurrentPartition:
  1407.                                 ## To be here means they have size_in_kb='0' BUT this is ok since it is the LAST partition
  1408.                                 pass
  1409.                             else:
  1410.                                 PrintBigError("\nERROR: Invalid size_in_kb='0' detected on partition %d of %d. This is usually a mistake. Did you mean this to be the *last* partition"%(CurrentPartition,CheckPartitionCount[NumPhyPartitions-1]))
  1411.  
  1412. ##timmy
  1413.  
  1414.                         TempSizeInBytes = int(value)*1024
  1415.                         if TempSizeInBytes < SECTOR_SIZE_IN_BYTES:
  1416.                             ## smaller than a sector, which is possible if sector size is 4KB
  1417.                             TempSizeInBytes = SECTOR_SIZE_IN_BYTES
  1418.                         Partition["size_in_kb"]=TempSizeInBytes/1024
  1419.                         Partition["original_size_in_kb"]=TempSizeInBytes/1024
  1420.                     elif name=="firstlba":
  1421.                         Partition["firstlba"]=int(value)
  1422.                     else:
  1423.                         print "Just assigned %s to %s" % (name,value)
  1424.                         Partition[name]=value
  1425.                
  1426.         # No longer appending blank filename data for Trace32. Programming based on Label now
  1427.                 #if FileFound == 1:
  1428.                 #    Partition['filename'].append("")
  1429.                 #    Partition['fileoffset'].append(0)
  1430.                 #    Partition['filepartitionoffset'].append(0)
  1431.                 #    Partition['appsbin'].append("false")
  1432.                 #    Partition['sparse'].append("false")
  1433.                
  1434.  
  1435.  
  1436.                 ## done with all the elements, now ensure that size matches with size_in_kb
  1437.                 Partition["size"] = ConvertKBtoSectors(Partition["size_in_kb"]) # Still 512 bytes/sector here since "size" is a legacy field
  1438.  
  1439.                 ## Now add this "Partition" object to the PartitionCollection
  1440.                 ## unless it's the label EXT, which is a left over legacy tag
  1441.  
  1442.                 if Partition['label'] != 'EXT':
  1443.                     #print "\nJust added %s" % Partition['label']
  1444.                     PartitionCollection.append( Partition )
  1445.  
  1446.                     print "="*40
  1447.                     print "storing at %d" % (NumPhyPartitions-1)
  1448.                     ##import pdb; pdb.set_trace()
  1449.  
  1450.                     print "Adding PartitionCollection to \"PhyPartition\" of size %i" % (NumPhyPartitions-1)
  1451.                     PhyPartition[(NumPhyPartitions-1)]          = PartitionCollection
  1452.  
  1453.                     #print "\nPartition stored (%i partitions total)" % len(PartitionCollection)
  1454.            
  1455.             else:
  1456.                 PrintBigError("ERROR: element.tag was partition, primary or extended, but it had no keys!")
  1457.  
  1458.         elif element.tag=="file":
  1459.             #print "element.tag=='file' Found a file, NumPhyPartitions=",NumPhyPartitions    ## i.e. just a file tag (usually in legacy)
  1460.             #print PhyPartition[(NumPhyPartitions-1)]
  1461.             #print "Current partition is \"%s\"\n" % Partition['label']
  1462.  
  1463.             if element.keys():
  1464.                 for name, value in element.items():
  1465.                     if name=='name' or name=='filename' :
  1466.                         Partition['filename'][-1] = value
  1467.                     if name=='fileoffset':
  1468.                         Partition['fileoffset'][-1] = value
  1469.                     if name=='offset' or name=='filepartitionoffset':
  1470.                         Partition['filepartitionoffset'][-1] = int(value)
  1471.                     if name=='appsbin':
  1472.                         Partition['appsbin'][-1] = value
  1473.                     if name=='sparse':
  1474.                         Partition['sparse'][-1] = value
  1475.  
  1476.                     #Partition[name]=value
  1477.            
  1478.             #print Partition['filename']
  1479.             Partition['filename'].append("")
  1480.             Partition['fileoffset'].append(0)
  1481.             Partition['filepartitionoffset'].append(0)
  1482.             Partition['appsbin'].append("false")
  1483.             Partition['sparse'].append("false")
  1484.            
  1485.         #try:
  1486.         #    if len(Partition['filename'])>1:
  1487.         #        print "="*78
  1488.         #        print "="*78
  1489.         #        for z in range(len(Partition['filename'])):
  1490.         #            print "Partition['filename'][",z,"]=",Partition['filename'][z]
  1491.         #            print "Partition['fileoffset'][",z,"]=",Partition['fileoffset'][z]
  1492.         #            print "Partition['filepartitionoffset'][",z,"]=",Partition['filepartitionoffset'][z]
  1493.         #            print "Partition['appsbin'][",z,"]=",Partition['appsbin'][z]
  1494.         #            print "Partition['sparse'][",z,"]=",Partition['sparse'][z]
  1495.         #            print "-"*78
  1496.         #        print "="*78
  1497.         #except:
  1498.         #    print " "
  1499.         #print "Showing the changes to PartitionCollection"
  1500.         #print PartitionCollection[-1]
  1501.  
  1502.            
  1503.     # Must update this if the user has updated WRITE_PROTECT_BOUNDARY_IN_KB in partition.xml
  1504.     hash_w[NumWPregions]['num_sectors'] = (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES)
  1505.     hash_w[NumWPregions]['end_sector']  = (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES)-1
  1506.  
  1507.     if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] == 0:
  1508.         hash_w[NumWPregions]['num_sectors']             = 0
  1509.         hash_w[NumWPregions]['end_sector']              = 0
  1510.         hash_w[NumWPregions]['num_boundaries_covered']  = 0
  1511.  
  1512.     if OutputToCreate is "gpt" and HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] is False:
  1513.         hash_w[NumWPregions]['num_sectors']             = 0
  1514.         hash_w[NumWPregions]['end_sector']              = 0
  1515.         hash_w[NumWPregions]['num_boundaries_covered']  = 0
  1516.  
  1517.     print "HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']    =%d" % HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']
  1518.     print "HashInstructions['ALIGN_BOUNDARY_IN_KB']            =%d" % HashInstructions['ALIGN_BOUNDARY_IN_KB']
  1519.     print "HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']=%s" % HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']
  1520.     print "HashInstructions['DISK_SIGNATURE']=0x%X" % HashInstructions['DISK_SIGNATURE']
  1521.  
  1522.     #for j in range(len(PhyPartition)):
  1523.     #for j in range(1):
  1524.     #    print "\n\nPhyPartition[%d] ========================================================= " % (j)
  1525.     #    PrintPartitionCollection( PhyPartition[j] )
  1526.  
  1527.  
  1528.     print "len(PhyPartition)=",len(PhyPartition)
  1529.  
  1530.     if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==False:
  1531.         ## to be here means we're *not* growing final partition, thereore, obey the sizes they've specified
  1532.         for j in range(len(PhyPartition)):
  1533.             TempNumPartitions = len(PhyPartition[j])
  1534.             if TempNumPartitions>4:
  1535.                 MinSectorsNeeded = 1 + (TempNumPartitions-3) # need MBR + TempNumPartitions-3 EBRs
  1536.             else:
  1537.                 MinSectorsNeeded = 1    # need MBR only
  1538.  
  1539.             for Partition in PhyPartition[j]:
  1540.                 print "LABEL: '%s' with %d sectors " % (Partition['label'],ConvertKBtoSectors(Partition["size_in_kb"]))
  1541.  
  1542.                 MinSectorsNeeded += ConvertKBtoSectors(Partition["size_in_kb"])
  1543.  
  1544.                 #print "LABEL '%s' with size %d sectors" % (Partition['label'],Partition['size_in_kb']/2)
  1545.  
  1546.            
  1547.     print "MinSectorsNeeded=%d" % MinSectorsNeeded
  1548.     #sys.exit()  #
  1549.                
  1550.                
  1551.     if OutputToCreate is 'gpt':
  1552.         PrintBanner("GPT GUID discovered in XML file, Output will be GPT")
  1553.     if OutputToCreate is 'mbr':
  1554.         PrintBanner("MBR type discovered in XML file, Output will be MBR")
  1555.    
  1556.  
  1557. #    PrintPartitionCollection( PhyPartition[0] )
  1558. def PrintPartitionCollection(PartitionCollection):
  1559.  
  1560.     #print PartitionCollection
  1561.  
  1562.     for Partition in PartitionCollection:
  1563.         print Partition
  1564.         print " "
  1565.         for key in Partition:
  1566.             print key,"\t=>\t",Partition[key]
  1567.  
  1568.     #for j in range(NumMBRPartitions):
  1569.  
  1570. def ParseCommandLine():
  1571.     global XMLFile,OutputToCreate,PhysicalPartitionNumber
  1572.  
  1573.     print "\nArgs"
  1574.     for i in range(len(sys.argv)):
  1575.         print "sys.argv[%d]=%s" % (i,sys.argv[i])
  1576.  
  1577.     print " "
  1578.  
  1579.     XMLFile = sys.argv[1];
  1580.  
  1581.     if len(sys.argv) >= 3:
  1582.         m = re.search("mbr|gpt", sys.argv[2] )
  1583.  
  1584.         if type(m) is not NoneType:
  1585.             OutputToCreate = sys.argv[2]
  1586.         else:
  1587.             print "Unrecognized option '%s', only 'mbr' or 'gpt' expected" % sys.argv[2]
  1588.     else:
  1589.         print "\nUser *did* not explicitly specify partition table format (i.e. mbr|gpt)"
  1590.         print "\nWill AUTO-DETECT from file"
  1591.  
  1592.     if len(sys.argv) >= 4:  # Should mean PHY partition was specified
  1593.         m = re.search("^\d+$", sys.argv[3] )
  1594.         if type(m) is not NoneType:
  1595.             PhysicalPartitionNumber = int(sys.argv[3])
  1596.             print "PhysicalPartitionNumber specified as %d" % PhysicalPartitionNumber
  1597.         else:
  1598.             PrintBigError("ERROR: PhysicalPartitionNumber of disk must only contain numbers, '%s' is not valid" % sys.argv[3])
  1599.  
  1600.     print " "
  1601.  
  1602. # Updates the WriteProtect hash that is used in creating emmc_lock_regions.xml
  1603. def UpdateWPhash(Start,Size):
  1604.     global hash_w,NumWPregions
  1605.  
  1606.     if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']==0:
  1607.         return
  1608.  
  1609.     #print "\nUpdateWPhash(%i,%i) and currently NumWPregions=%i" % (Start,Size,NumWPregions)
  1610.     #print "hash_w[%i]['start_sector']=%i" % (NumWPregions,hash_w[NumWPregions]["start_sector"])
  1611.     #print "hash_w[%i]['end_sector']=%i" % (NumWPregions,hash_w[NumWPregions]["end_sector"])
  1612.     #print "hash_w[%i]['num_sectors']=%i" % (NumWPregions,hash_w[NumWPregions]["num_sectors"])
  1613.  
  1614.     if Start-1 <= hash_w[NumWPregions]["end_sector"]:
  1615.         #print "\n\tCurrent Write Protect region already covers the start of this partition (start=%i)" % hash_w[NumWPregions]["start_sector"]
  1616.        
  1617.         if (Start + Size - 1) > hash_w[NumWPregions]["end_sector"]:
  1618.             print "\n\tCurrent Write Protect region is not big enough at %i sectors, needs to be at least %i sectors" % (hash_w[NumWPregions]["end_sector"]-hash_w[NumWPregions]["start_sector"]+1,Start + Size - 1,)
  1619.             while (Start + Size - 1) > hash_w[NumWPregions]["end_sector"]:
  1620.                 hash_w[NumWPregions]["num_sectors"] += (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES);
  1621.                 hash_w[NumWPregions]["end_sector"]  += (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES);
  1622.                 if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0:
  1623.                     hash_w[NumWPregions]["num_boundaries_covered"] = hash_w[NumWPregions]["num_sectors"] / (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES)
  1624.                 else:
  1625.                     hash_w[NumWPregions]["num_boundaries_covered"] = 0
  1626.            
  1627.             print "\t\tend_sector increased to %i sectors" % hash_w[NumWPregions]["end_sector"]
  1628.             print "\t\tnum_sectors increased to %i sectors" % hash_w[NumWPregions]["num_sectors"]
  1629.        
  1630.         #print "\n\tCurrent Write Protect region covers this partition (num_sectors=%i)\n" % hash_w[NumWPregions]["num_sectors"]
  1631.        
  1632.     else:
  1633.         print "\n\tNew write protect region needed"
  1634.         #print "\tStart-1\t\t\t\t=%i" % (Start-1)
  1635.         #print "\tLAST hash_w[NumWPregions][end_sector]=%i\n" % hash_w[NumWPregions]["end_sector"]
  1636.        
  1637.  
  1638.         NumWPregions+=1;
  1639.        
  1640.         hash_w.append( {'start_sector':Start,'num_sectors':(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES),'end_sector':Start+(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES)-1,'physical_partition_number':0,'boundary_num':0,'num_boundaries_covered':1} )
  1641.        
  1642.         hash_w[NumWPregions]["boundary_num"] = Start / (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES)
  1643.  
  1644.         while (Start + Size - 1) > hash_w[NumWPregions]["end_sector"]:
  1645.             #print "\n\tThis region is not big enough though, needs to be %i sectors, but currently only %i" % (Start + Size - 1,hash_w[NumWPregions]["end_sector"])
  1646.             hash_w[NumWPregions]["num_sectors"] += (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES);
  1647.             hash_w[NumWPregions]["end_sector"]  += (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES);
  1648.             #print "\t\tend_sector increased to %i sectors" % hash_w[NumWPregions]["end_sector"]
  1649.             #print "\t\tnum_sectors increased to %i sectors" % hash_w[NumWPregions]["num_sectors"]
  1650.            
  1651.         hash_w[NumWPregions]["num_boundaries_covered"] = hash_w[NumWPregions]["num_sectors"] / (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES)
  1652.  
  1653.         print "\t\tstart_sector = %i sectors" % hash_w[NumWPregions]["start_sector"]
  1654.         print "\t\tend_sector = %i sectors" % hash_w[NumWPregions]["end_sector"]
  1655.         print "\t\tnum_sectors = %i sectors\n" % hash_w[NumWPregions]["num_sectors"]
  1656.  
  1657. # A8h reflected is 15h, i.e. 10101000 <--> 00010101
  1658. def reflect(data,nBits):
  1659.  
  1660.     reflection = 0x00000000
  1661.     bit = 0
  1662.  
  1663.     for bit in range(nBits):
  1664.         if(data & 0x01):
  1665.             reflection |= (1 << ((nBits - 1) - bit))
  1666.         data = (data >> 1);
  1667.  
  1668.     return reflection
  1669.  
  1670.  
  1671. def CalcCRC32(array,Len):
  1672.    k        = 8;            # length of unit (i.e. byte)
  1673.    MSB      = 0;
  1674.    gx       = 0x04C11DB7;   # IEEE 32bit polynomial
  1675.    regs     = 0xFFFFFFFF;   # init to all ones
  1676.    regsMask = 0xFFFFFFFF;   # ensure only 32 bit answer
  1677.  
  1678.    print "Calculating CRC over byte length of %i" % Len
  1679.    print "%s" % HexPrettyPrint(array,Len)
  1680.  
  1681.    for i in range(Len):
  1682.       DataByte = array[i]
  1683.       DataByte = reflect( DataByte, 8 );
  1684.    
  1685.       for j in range(k):
  1686.         MSB  = DataByte>>(k-1)  ## get MSB
  1687.         MSB &= 1                ## ensure just 1 bit
  1688.    
  1689.         regsMSB = (regs>>31) & 1
  1690.  
  1691.         regs = regs<<1          ## shift regs for CRC-CCITT
  1692.    
  1693.         if regsMSB ^ MSB:       ## MSB is a 1
  1694.             regs = regs ^ gx    ## XOR with generator poly
  1695.    
  1696.         regs = regs & regsMask; ## Mask off excess upper bits
  1697.  
  1698.         DataByte <<= 1          ## get to next bit
  1699.  
  1700.    
  1701.    regs          = regs & regsMask ## Mask off excess upper bits
  1702.    ReflectedRegs = reflect(regs,32) ^ 0xFFFFFFFF;
  1703.  
  1704.    #print "CRC is 0x%.8X\n" % ReflectedRegs
  1705.    
  1706.    return ReflectedRegs
  1707.  
  1708.  
  1709. def HexPrettyPrint(data,Length):
  1710.    szNum = ""
  1711.    szAsc = ""
  1712.    digest= ""
  1713.    P = 16
  1714.  
  1715.    ## Called during DLOAD and STREAM
  1716.    #log_info("In HexPrettyPrint() len(data)=%d" % len(data))
  1717.  
  1718.    ##return  " "## hack
  1719.  
  1720.    try:
  1721.        if len(data)==0:
  1722.            return " "
  1723.    except:
  1724.        log_debug("Hit Exception in HexPrettyPrint, data is %s" % type(data))
  1725.        return " "
  1726.  
  1727.    digest = ""
  1728.  
  1729.    TempAddress = 0
  1730.    szHexDump = "\n\tShowing %d bytes\n\t" % (Length)
  1731.    for i in range(Length):
  1732.        v = data[i]
  1733.  
  1734.        if v == 0x7 and i==0 and Length>5:
  1735.            ## Get next 4 bytes
  1736.            ##print "Length=",Length
  1737.            TempAddress = data[i+4]<<24 | data[i+3]<<16 | data[i+2]<<8 | data[i+1]
  1738.            szHexDump += "Suspected Write, Address would be 0x%.8X\n\t" % (TempAddress)
  1739.  
  1740.        if i>0 and i % 16==0:
  1741.            szHexDump += "%-48s\t%s\n\t" % (szNum,szAsc)
  1742.            szNum = ""
  1743.            szAsc = ""
  1744.  
  1745.        ##print "v=",v," type",type(v)  
  1746.        ##import pdb; pdb.set_trace()    
  1747.        #if type(v) is not int:    ## HACK
  1748.        #    v = ord(v)  ## convert to unsigned char (integers in python)
  1749.        szNum += "%.2X " % v
  1750.        if v>=0x20 and v<=0x7E:
  1751.            szAsc += "%c"    % v
  1752.        else:
  1753.            szAsc += "."
  1754.  
  1755.    ##import pdb; pdb.set_trace()
  1756.  
  1757.    szHexDump += "%-48s\t%s\n%s\n\n" % (szNum,szAsc,digest)
  1758.  
  1759.    return szHexDump
  1760.  
  1761.  
  1762. def ReturnLow32bits(var):
  1763.     return var & 0xFFFFFFFF
  1764.  
  1765. def ReturnHigh32bits(var):
  1766.     return (var>>32) & 0xFFFFFFFF
  1767.  
  1768. def PrintBanner(sz):
  1769.     print "\n"+"="*78
  1770.     print sz
  1771.     print "="*78+"\n"
  1772.  
  1773. def ShowUsage():
  1774.     PrintBanner("Basic Usage")
  1775.     print "python ptool.py -x partition.xml"
  1776.     PrintBanner("Advanced Usage")
  1777.     print "%-44s\t\tpython ptool.py -x partition.xml" % ("Basic Usage")
  1778.     print "%-44s\t\tpython ptool.py -x partition.xml -s c:\windows" % ("Search path to find partition.xml")
  1779.     print "%-44s\tpython ptool.py -x partition.xml -p 0" % ("Specify PHY Partition 0, (creates rawprogram0.xml)")
  1780.     print "%-44s\tpython ptool.py -x partition.xml -p 1" % ("Specify PHY Partition 1, (creates rawprogram1.xml)")
  1781.     print "%-44s\tpython ptool.py -x partition.xml -p 2" % ("Specify PHY Partition 2, (creates rawprogram2.xml)")
  1782.     print "%-44s\t\tpython ptool.py -x partition.xml -v" % ("Verbose output")
  1783.     print "%-44s\t\tpython ptool.py -x partition.xml -t c:\\temp" % ("Specify place to put output")
  1784.    
  1785. def CreateFinalPartitionBin():
  1786.     global OutputFolder
  1787.  
  1788.     opfile = open("%spartition.bin" % OutputFolder, "wb")
  1789.  
  1790.     for i in range(3):
  1791.         FileName = "%spartition%i.bin" % (OutputFolder,i);
  1792.         size     = 0
  1793.  
  1794.         if os.path.isfile(FileName):
  1795.             size = os.path.getsize(FileName)
  1796.  
  1797.             ipfile = open(FileName, "rb")
  1798.             temp = ipfile.read()
  1799.             opfile.write(temp)
  1800.             ipfile.close()
  1801.  
  1802.         if size < 8192:
  1803.             MyArray = [0]*(8192-size)
  1804.             for b in MyArray:
  1805.                 opfile.write(struct.pack("B", b))
  1806.  
  1807.     opfile.close()
  1808.  
  1809.  
  1810.  
  1811. def prettify(elem):
  1812.     """Return a pretty-printed XML string for the Element.
  1813.    """
  1814.     rough_string = ET.tostring(elem, 'utf-8')
  1815.     reparsed = minidom.parseString(rough_string)
  1816.     return reparsed.toprettyxml(indent="  ")
  1817.  
  1818.  
  1819. def UpdatePartitionTable(Bootable,Type,StartSector,Size,Offset,Record):
  1820.  
  1821.     #print "Size = %i" % Size
  1822.  
  1823.     if Bootable=="true":
  1824.         Bootable = 0x80
  1825.     else:
  1826.         Bootable = 0x00
  1827.  
  1828.     Type = ValidateTYPE(Type)
  1829.  
  1830.     #print "\tAt Offset=0x%.4X (%d) (%d bytes left)" % (Offset,Offset,len(Record)-Offset)
  1831.  
  1832.     Record[Offset]         = Bootable  ; Offset+=1
  1833.  
  1834.     Record[Offset:Offset+3]= [0,0,0]   ; Offset+=3
  1835.  
  1836.     Record[Offset]         = Type      ; Offset+=1
  1837.  
  1838.     Record[Offset:Offset+3]= [0,0,0]   ; Offset+=3
  1839.  
  1840.     # First StartSector
  1841.     for b in range(4):
  1842.         Record[Offset] = ((StartSector>>(b*8)) & 0xFF) ; Offset+=1
  1843.  
  1844.     # First StartSector
  1845.     for b in range(4):
  1846.         Record[Offset] = ((Size>>(b*8)) & 0xFF) ; Offset+=1
  1847.  
  1848.     #print "\t\tBoot:0x%.2X, ID:0x%.2X, 0x%.8X, 0x%.8X (%.2fMB)" % (Bootable,Type,StartSector,Size,Size/2048.0)
  1849.  
  1850.     return Record
  1851.  
  1852. # This function called first, then calls CreateMasterBootRecord and CreateExtendedBootRecords
  1853. def CreateMBRPartitionTable(PhysicalPartitionNumber):
  1854.     global PhyPartition,opfile,RawProgramXML,HashInstructions,ExtendedPartitionBegins,MBR,PARTITIONBIN, MBRBIN, EBRBIN, PATCHES, RAW_PROGRAM
  1855.  
  1856.     k = PhysicalPartitionNumber
  1857.  
  1858.     if(k>=len(PhyPartition)):
  1859.         print "PHY Partition %i of %i not found" % (k,len(PhyPartition))
  1860.         sys.exit()
  1861.    
  1862.     NumPartitions = len(PhyPartition[k])
  1863.  
  1864.     print "\n\nOn PHY Partition %d that has %d partitions" % (k,NumPartitions)
  1865.  
  1866.     print "\n------------\n"
  1867.  
  1868.     print "\nFor PHY Partition %i" % k
  1869.     if(NumPartitions<=4):
  1870.         print "\tWe can get away with only an MBR";
  1871.         CreateMasterBootRecord(k, NumPartitions )
  1872.     else:
  1873.         print "\tWe will need an MBR and %d EBRs" % (NumPartitions-3)
  1874.         CreateMasterBootRecord(k, 3 )
  1875.  
  1876.         ## Now the EXTENDED PARTITION
  1877.         print "\nAbout to make EBR, FirstLBA=%i, LastLBA=%i" % (FirstLBA,LastLBA)
  1878.         CreateExtendedBootRecords(k,NumPartitions-3)
  1879.  
  1880.  
  1881.     PARTITIONBIN    = '%spartition%i.bin'   % (OutputFolder,k)
  1882.     MBRBIN          = '%sMBR%i.bin'         % (OutputFolder,k)
  1883.     EBRBIN          = '%sEBR%i.bin'         % (OutputFolder,k)
  1884.     PATCHES         = '%spatch%i.xml'       % (OutputFolder,k)
  1885.     RAW_PROGRAM     = '%srawprogram%i.xml'  % (OutputFolder,k)
  1886.  
  1887.     UpdateRawProgram(RawProgramXML,0, 1*SECTOR_SIZE_IN_BYTES/1024.0, k, 0, 1, MBRBIN, 'false', 'MBR')
  1888.  
  1889.     if(NumPartitions>4):
  1890.         ## There was more than 4 partitions, so EXT partition had to be used
  1891.         UpdateRawProgram(RawProgramXML,ExtendedPartitionBegins, (NumPartitions-3)*SECTOR_SIZE_IN_BYTES/1024.0, k, 0, NumPartitions-3, EBRBIN, 'false', 'EXT')          # note file offset is 0
  1892.  
  1893.     print "\nptool.py is running from CWD: ", os.getcwd(), "\n"
  1894.  
  1895.     opfile = open(PARTITIONBIN, "wb")
  1896.     WriteMBR()
  1897.     WriteEBR()
  1898.     opfile.close()
  1899.     print "Created \"%s\"" % PARTITIONBIN
  1900.  
  1901.     opfile = open(MBRBIN, "wb")
  1902.     WriteMBR()
  1903.     opfile.close()
  1904.     print "Created \"%s\"" % MBRBIN
  1905.  
  1906.     opfile = open(EBRBIN, "wb")
  1907.     WriteEBR()
  1908.     opfile.close()
  1909.     print "Created \"%s\"" % EBRBIN
  1910.  
  1911.     opfile = open(RAW_PROGRAM, "w")
  1912.     opfile.write( prettify(RawProgramXML) )
  1913.     opfile.close()
  1914.     print "Created \"%s\"" % RAW_PROGRAM
  1915.  
  1916.     opfile = open(PATCHES, "w")
  1917.     opfile.write( prettify(PatchesXML) )
  1918.     opfile.close()
  1919.     print "Created \"%s\"" % PATCHES
  1920.  
  1921.     for mydict in hash_w:
  1922.         #print mydict
  1923.         SubElement(EmmcLockRegionsXML, 'program', {'start_sector':"%X" % mydict['start_sector'],'start_sector_dec':str(mydict['start_sector']),
  1924.                                        'num_sectors':"%X" % mydict['num_sectors'],'num_sectors_dec':str(mydict['num_sectors']),
  1925.                                        'boundary_num':str(mydict['boundary_num']),
  1926.                                        'num_boundaries_covered':str(mydict['num_boundaries_covered']),
  1927.                                        'physical_partition_number':str(mydict['physical_partition_number']) })
  1928.  
  1929.  
  1930.     SubElement(EmmcLockRegionsXML, 'information', {'WRITE_PROTECT_BOUNDARY_IN_KB':str(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']) })
  1931.  
  1932.     opfile = open("%semmc_lock_regions.xml" % OutputFolder, "w")
  1933.  
  1934.     opfile.write( prettify(EmmcLockRegionsXML) )
  1935.     opfile.close()
  1936.     print "Created \"%semmc_lock_regions.xml\"" % OutputFolder
  1937.  
  1938.     print "\nUse msp tool to write this information to SD/eMMC card"
  1939.     print "\ti.e."
  1940.  
  1941.     if sys.platform.startswith("linux"):
  1942.         print "\tsudo python msp.py rawprogram0.xml /dev/sdb    <---- where /dev/sdb is assumed to be your SD/eMMC card"
  1943.         print "\tsudo python msp.py patch0.xml /dev/sdb    <---- where /dev/sdb is assumed to be your SD/eMMC card\n\n"
  1944.     else:
  1945.         print "\tpython msp.py rawprogram0.xml \\\\.\\PHYSICALDRIVE2    <---- where \\\\.\\PHYSICALDRIVE2 is"
  1946.         print "\tpython msp.py patch0.xml \\\\.\\PHYSICALDRIVE2    <---- assumed to be your SD/eMMC card\n\n"
  1947.  
  1948.  
  1949.   # CreateMasterBootRecord(k,len(PhyPartition[k]) )
  1950. def CreateMasterBootRecord(k,NumMBRPartitions):
  1951.     global PhyPartition,HashInstructions,MBR,FirstLBA,LastLBA
  1952.     print "\nInside CreateMasterBootRecord(%d) -------------------------------------" % NumMBRPartitions    
  1953.  
  1954.     MBR             = [0]*SECTOR_SIZE_IN_BYTES
  1955.     MBR[440]        = (HashInstructions['DISK_SIGNATURE']>>24)&0xFF
  1956.     MBR[441]        = (HashInstructions['DISK_SIGNATURE']>>16)&0xFF
  1957.     MBR[442]        = (HashInstructions['DISK_SIGNATURE']>>8)&0xFF
  1958.     MBR[443]        = (HashInstructions['DISK_SIGNATURE'])&0xFF
  1959.  
  1960.     MBR[510:512]    = [0x55,0xAA]           # magic byte for MBR partitioning - always at this location regardless of SECTOR_SIZE_IN_BYTES
  1961.  
  1962.     ## These two values used like so 'num_sectors':str(LastLBA-FirstLBA)
  1963.     FirstLBA    = 1    ## the MBR is at 0, Partition 1 is at 1
  1964.     LastLBA     = 1
  1965.  
  1966.     PartitionSectorSize = 0
  1967.  
  1968.     #print "\nOn PHY Partition %d that has %d partitions" % (k,len(PhyPartition[k]))
  1969.     for j in range(NumMBRPartitions):   # typically this is 0,1,2
  1970.  
  1971.         ## ALL MBR partitions are marked as read-only
  1972.         PhyPartition[k][j]['readonly'] = "true"
  1973.  
  1974.         PartitionSectorSize = ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb'])    # in sector form, i.e. 1KB = 2 sectors
  1975.  
  1976.         print "\n\n%d of %d \"%s\" (readonly=%s) and size=%dKB (%.2fMB or %i sectors)" % (j+1,len(PhyPartition[k]),PhyPartition[k][j]['label'],
  1977.                                         PhyPartition[k][j]['readonly'],PhyPartition[k][j]['size_in_kb'],
  1978.                                         PhyPartition[k][j]['size_in_kb']/1024.0,ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb']))
  1979.  
  1980.  
  1981.         # Is this sector aligned?
  1982.         if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0:
  1983.             AlignedRemainder = FirstLBA % HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'];
  1984.            
  1985.             if AlignedRemainder==0:
  1986.                 print "\tThis partition is ** ALIGNED ** to a %i KB boundary at sector %i (boundary %i)" % (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'],FirstLBA,FirstLBA/(ConvertKBtoSectors(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'])))
  1987.  
  1988.  
  1989.         # are we on the very last partition, i.e. did user only specify 3 or less partitions?
  1990.         if (j+1) == len(PhyPartition[k]):
  1991.             print "\nTHIS IS THE LAST PARTITION"
  1992.             print "HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = %s" % HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']
  1993.             if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==True:
  1994.                 SectorOffsetPatchBefore = 0
  1995.                 SectorOffsetPatchAfter  = 0
  1996.                 ByteOffset              = 0x1CA+j*16
  1997.                 UpdatePatch(str(SectorOffsetPatchBefore),str(ByteOffset),k,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA),"partition%d.bin" % k, "Update last partition with actual size.")
  1998.                 UpdatePatch(str(SectorOffsetPatchBefore),str(ByteOffset),k,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA),"MBR%d.bin" % k, "Update last partition with actual size.")
  1999.                 UpdatePatch(str(SectorOffsetPatchAfter), str(ByteOffset),k,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA),"DISK", "Update 'Update last partition with actual size.")
  2000.                    
  2001.         # Update the Write-Protect hash
  2002.         if PhyPartition[k][j]['readonly']=="true":
  2003.             UpdateWPhash(FirstLBA, PartitionSectorSize)
  2004.  
  2005.         LastLBA += PartitionSectorSize ## increase by num sectors, LastLBA inclusive, so add 1 for size
  2006.        
  2007.         ## Default for each partition is no file
  2008.         FileToProgram           = [""]
  2009.         FileOffset              = [0]
  2010.         FilePartitionOffset     = [0]
  2011.         FileAppsbin             = ["false"]
  2012.         FileSparse              = ["false"]
  2013.  
  2014.         if 'filename' in PhyPartition[k][j]:
  2015.             ##print "filename exists"
  2016.             #print PhyPartition[k][j]['filename']
  2017.             #print FileToProgram[0]
  2018.            
  2019.  
  2020.             FileToProgram[0]            = PhyPartition[k][j]['filename'][0]
  2021.             FileOffset[0]               = PhyPartition[k][j]['fileoffset'][0]
  2022.             FilePartitionOffset[0]      = PhyPartition[k][j]['filepartitionoffset'][0]
  2023.             FileAppsbin[0]              = PhyPartition[k][j]['appsbin'][0]
  2024.             FileSparse[0]               = PhyPartition[k][j]['sparse'][0]
  2025.  
  2026.             for z in range(1,len(PhyPartition[k][j]['filename'])):
  2027.                 FileToProgram.append( PhyPartition[k][j]['filename'][z] )
  2028.                 FileOffset.append( PhyPartition[k][j]['fileoffset'][z] )
  2029.                 FilePartitionOffset.append( PhyPartition[k][j]['filepartitionoffset'][z] )
  2030.                 FileAppsbin.append( PhyPartition[k][j]['appsbin'][z] )
  2031.                 FileSparse.append( PhyPartition[k][j]['sparse'][z] )
  2032.  
  2033.             #print PhyPartition[k][j]['fileoffset']
  2034.            
  2035.  
  2036.         #for z in range(len(FileToProgram)):
  2037.         #    print "FileToProgram[",z,"]=",FileToProgram[z]
  2038.         #    print "FileOffset[",z,"]=",FileOffset[z]
  2039.         #    print " "
  2040.        
  2041.         PartitionLabel  = ""
  2042.         Type            = ""
  2043.         Bootable        = "false"
  2044.  
  2045.         ## Now update with the real values
  2046.         if 'label' in PhyPartition[k][j]:
  2047.             PartitionLabel = PhyPartition[k][j]['label']
  2048.         if 'type' in PhyPartition[k][j]:
  2049.             Type = PhyPartition[k][j]['type']
  2050.         if 'bootable' in PhyPartition[k][j]:
  2051.             Bootable = PhyPartition[k][j]['bootable']
  2052.  
  2053.         ## Now it is time to update the partition table
  2054.         offset = 0x1BE + (j*16)
  2055.  
  2056.         MBR = UpdatePartitionTable(Bootable,Type,FirstLBA,PartitionSectorSize,offset,MBR)
  2057.  
  2058.  
  2059.         for z in range(len(FileToProgram)):
  2060.             #print "File: ",FileToProgram[z]
  2061.             #print "FilePartitionOffset[z]=",FilePartitionOffset[z]
  2062.             UpdateRawProgram(RawProgramXML, FirstLBA+FilePartitionOffset[z], PartitionSectorSize*SECTOR_SIZE_IN_BYTES/1024.0, k, FileOffset[z], PartitionSectorSize-FilePartitionOffset[z], FileToProgram[z], FileSparse[z], PartitionLabel)
  2063.  
  2064.         FirstLBA = LastLBA      # getting ready for next partition, FirstLBA is now where we left off
  2065.  
  2066. # CreateExtendedBootRecords(k,len(PhyPartition[k])-3)
  2067. def CreateExtendedBootRecords(k,NumEBRPartitions):
  2068.     global PhyPartition,HashInstructions,MBR,EBR,FirstLBA,LastLBA,ExtendedPartitionBegins
  2069.     print "\nInside CreateExtendedBootRecords(%d) -----------------------------------------" % NumEBRPartitions
  2070.  
  2071.     ## Step 1 is to update the MBR with the size of the EXT partition
  2072.     ## in which logical partitions will be created
  2073.  
  2074.     EBROffset = 0
  2075.  
  2076.     print "EBROffset=",EBROffset
  2077.  
  2078.     ExtendedPartitionBegins = FirstLBA
  2079.  
  2080.     if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==True:
  2081.         print "Extended Partition begins at FirstLBA=%i\n" % (ExtendedPartitionBegins)
  2082.         MBR=UpdatePartitionTable("false","05",FirstLBA,0x0,0x1EE,MBR)  ## offset at 0x1EE is the last entry in MBR
  2083.     else:
  2084.         print "Extended Partition begins at FirstLBA=%i, size is %i\n" % (ExtendedPartitionBegins,MinSectorsNeeded-FirstLBA)
  2085.         MBR=UpdatePartitionTable("false","05",FirstLBA,MinSectorsNeeded-FirstLBA,0x1EE,MBR)  ## offset at 0x1EE is the last entry in MBR
  2086.  
  2087.     ## Still patch no matter what, since this can still go on any size card
  2088.     UpdatePatch('0',str(0x1FA),PhysicalPartitionNumber,4,"NUM_DISK_SECTORS-%s." % str(ExtendedPartitionBegins),"partition%d.bin" % k, "Update MBR with the length of the EXT Partition.")
  2089.     UpdatePatch('0',str(0x1FA),PhysicalPartitionNumber,4,"NUM_DISK_SECTORS-%s." % str(ExtendedPartitionBegins),"MBR%d.bin" % k, "Update MBR with the length of the EXT Partition.")
  2090.     UpdatePatch('0',str(0x1FA),PhysicalPartitionNumber,4,"NUM_DISK_SECTORS-%s." % str(ExtendedPartitionBegins),"DISK", "Update MBR with the length of the EXT Partition.")
  2091.  
  2092.     UpdateWPhash(FirstLBA, NumEBRPartitions)
  2093.  
  2094.     ## Need to make room for the EBR tables
  2095.     FirstLBA        += NumEBRPartitions
  2096.     LastLBA         += NumEBRPartitions
  2097.  
  2098.     print "FirstLBA now equals %d since NumEBRPartitions=%d" % (FirstLBA,NumEBRPartitions)
  2099.  
  2100.     offset                  = 0     # offset to EBR array which gets EBR.extend( [0]*SECTOR_SIZE_IN_BYTES ) for each EBR
  2101.     SectorsTillNextBoundary = 0     # reset
  2102.  
  2103.  
  2104.     # EBROffset is the num sectors from the location of the EBR to the actual logical partition
  2105.     # and because we group all the EBRs together,
  2106.     #   EBR0 is NumEBRPartitions away from EXT0
  2107.     #   EBR1 is NumEBRPartitions-1+SizeOfEXT0 away from EXT1 and so on
  2108.     #   EBR2 is NumEBRPartitions-2+SizeOfEXT0+SizeOfEXT1 away from EXT2 and so on
  2109.     # Thus EBROffset is constantly growing
  2110.  
  2111.     # Also since the EBRs must be write protected, we must ensure that it ends
  2112.     # on a WP boundary, i.e. HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']
  2113.  
  2114.     ## NOTE: We only have extended partitions when there are more than 4 partitions
  2115.     ## meaning 3 primary and then 2 extended. Thus everything here is offset from 3
  2116.     ## since the first 3 primary partitions were 0,1,2
  2117.     EBR = []
  2118.     for j in range(3,(NumEBRPartitions+3)):
  2119.         SectorsTillNextBoundary = 0
  2120.         EBR.extend( [0]*SECTOR_SIZE_IN_BYTES )
  2121.  
  2122.         #print "hash_w[%i]['start_sector']=%i" % (NumWPregions,hash_w[NumWPregions]["start_sector"])
  2123.         #print "hash_w[%i]['end_sector']=%i" % (NumWPregions,hash_w[NumWPregions]["end_sector"])
  2124.         #print "hash_w[%i]['num_sectors']=%i" % (NumWPregions,hash_w[NumWPregions]["num_sectors"])
  2125.  
  2126.         PartitionSectorSize = ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb'])
  2127.  
  2128.         ##print "\nPartition name='%s' (readonly=%s)" % (PhyPartition[k][j]['label'], PhyPartition[k][j]['readonly'])
  2129.         print "\n\n%d of %d \"%s\" (readonly=%s) and size=%dKB (%.2fMB or %i sectors)" %(j+1,len(PhyPartition[k]),PhyPartition[k][j]['label'],PhyPartition[k][j]['readonly'],PhyPartition[k][j]['size_in_kb'],PhyPartition[k][j]['size_in_kb']/1024.0,ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb']))
  2130.         print "\tFirstLBA=%d (with size %d sectors) and LastLBA=%d" % (FirstLBA,ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb']),LastLBA)
  2131.  
  2132.         if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0:
  2133.             SectorsTillNextBoundary = ReturnNumSectorsTillBoundary(FirstLBA,HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'])
  2134.  
  2135.         # Only the last partition can be re-sized. Are we on the very last partition?
  2136.         if (j+1) == len(PhyPartition[k]):
  2137.             print "\n\tTHIS IS THE LAST PARTITION"
  2138.  
  2139.             if PhyPartition[k][j]['readonly']=="true":
  2140.                 PhyPartition[k][j]['readonly']="false"
  2141.                 print "\tIt cannot be marked as read-only, it is now set to writeable"
  2142.  
  2143.             if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==True:
  2144.                 ## Here I'd want a patch for this
  2145.                 print "\tHashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = %s" % HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']
  2146.  
  2147.                 print "\njust set LAST PartitionSectorSize = 0 (it was %d)" % PartitionSectorSize
  2148.                 PartitionSectorSize = 0
  2149.                 print "This means the partition table will have a zero in it"
  2150.                 LastPartitionBeginsAt = FirstLBA
  2151.  
  2152.             NumEBRs = (len(PhyPartition[k])-3)
  2153.             SectorOffsetPatchBefore = NumEBRs
  2154.             SectorOffsetPatchAfter  = ExtendedPartitionBegins+NumEBRs-1
  2155.             ByteOffset              = 0x1CA
  2156.            
  2157.             ## Patch no matter what
  2158.             UpdatePatch(str(SectorOffsetPatchBefore),str(ByteOffset),PhysicalPartitionNumber,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA+1),"partition%d.bin" % k, "Update last partition with actual size.")
  2159.             UpdatePatch(str(SectorOffsetPatchBefore-1),str(ByteOffset),PhysicalPartitionNumber,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA+1),"EBR%d.bin" % k, "Update last partition with actual size.")
  2160.             UpdatePatch(str(SectorOffsetPatchAfter), str(ByteOffset),PhysicalPartitionNumber,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA+1),"DISK", "Update last partition with actual size.")
  2161.  
  2162.  
  2163.         print "\tPhyPartition[k][j]['align']=",PhyPartition[k][j]['align']
  2164.         print "\tSectorsTillNextBoundary=",SectorsTillNextBoundary
  2165.  
  2166.         if PhyPartition[k][j]['readonly']=="true":
  2167.             ## to be here means this partition is read-only, so see if we need to move the start
  2168.             if FirstLBA <= hash_w[NumWPregions]["end_sector"]:
  2169.                 print "Great, We *don't* need to move FirstLBA (%d) since it's covered by the end of the current WP region (%d)" % (FirstLBA,hash_w[NumWPregions]["end_sector"])
  2170.                 pass
  2171.             else:
  2172.                 print "\tFirstLBA (%d) is *not* covered by the end of the WP region (%d),\n\tit needs to be moved to be aligned to %d" % (FirstLBA,hash_w[NumWPregions]["end_sector"],FirstLBA + SectorsTillNextBoundary)
  2173.                 FirstLBA += SectorsTillNextBoundary
  2174.         elif PhyPartition[k][j]['align']=="true":
  2175.             ## to be here means this partition *must* be on an ALIGN boundary
  2176.             SectorsTillNextBoundary = ReturnNumSectorsTillBoundary(FirstLBA,HashInstructions['ALIGN_BOUNDARY_IN_KB'])
  2177.             if SectorsTillNextBoundary>0:
  2178.                 print "\tSectorsTillNextBoundary=%d, FirstLBA=%d it needs to be moved to be aligned to %d" % (SectorsTillNextBoundary,FirstLBA,FirstLBA + SectorsTillNextBoundary)
  2179.                 print "\tHashInstructions['ALIGN_BOUNDARY_IN_KB']=",HashInstructions['ALIGN_BOUNDARY_IN_KB']
  2180.                 FirstLBA += SectorsTillNextBoundary
  2181.                
  2182.                 AlignedRemainder = FirstLBA % HashInstructions['ALIGN_BOUNDARY_IN_KB'];
  2183.                
  2184.                 if AlignedRemainder==0:
  2185.                     print "\tThis partition is ** ALIGNED ** to a %i KB boundary at sector %i (boundary %i)" % (HashInstructions['ALIGN_BOUNDARY_IN_KB'],FirstLBA,FirstLBA/(ConvertKBtoSectors(HashInstructions['ALIGN_BOUNDARY_IN_KB'])))
  2186.  
  2187.         else:
  2188.             print "\n\tThis partition is *NOT* readonly (or does not have align='true')"
  2189.             ## to be here means this partition is writeable, so see if we need to move the start
  2190.             if FirstLBA <= hash_w[NumWPregions]["end_sector"]:
  2191.                 print "\tWe *need* to move FirstLBA (%d) since it's covered by the end of the current WP region (%d)" % (FirstLBA,hash_w[NumWPregions]["end_sector"])
  2192.                 print "\nhash_w[NumWPregions]['end_sector']=%i" % hash_w[NumWPregions]["end_sector"];
  2193.                 print "FirstLBA=%i\n" %FirstLBA;
  2194.                 FirstLBA += SectorsTillNextBoundary
  2195.  
  2196.                 print "\tFirstLBA is now %d" % (FirstLBA)
  2197.             else:
  2198.                 #print "Great, We *don't* need to move FirstLBA (%d) since it's *not* covered by the end of the current WP region (%d)" % (FirstLBA,hash_w[NumWPregions]["end_sector"])
  2199.                 pass
  2200.  
  2201.         if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0:
  2202.             AlignedRemainder = FirstLBA % HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'];
  2203.        
  2204.             if AlignedRemainder==0:
  2205.                 print "\tThis partition is ** ALIGNED ** to a %i KB boundary at sector %i (boundary %i)" % (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'],FirstLBA,FirstLBA/(ConvertKBtoSectors(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'])))
  2206.  
  2207.         if PhyPartition[k][j]['readonly']=="true":
  2208.             UpdateWPhash(FirstLBA, PartitionSectorSize)
  2209.  
  2210.         LastLBA = FirstLBA + PartitionSectorSize
  2211.  
  2212.         print "\n\tFirstLBA=%u, LastLBA=%u, PartitionSectorSize=%u" % (FirstLBA,LastLBA,PartitionSectorSize)
  2213.  
  2214.         print "\tLastLBA is currently %i sectors" % LastLBA
  2215.         print "\tCard size of at least %.1fMB needed (%u sectors)" % (LastLBA/2048.0,LastLBA)
  2216.         PhyPartition[k][j]['size_in_kb'] = PartitionSectorSize/2
  2217.  
  2218.         ## Default for each partition is no file
  2219.         FileToProgram           = [""]
  2220.         FileOffset              = [0]
  2221.         FilePartitionOffset     = [0]
  2222.         FileAppsbin             = ["false"]
  2223.         FileSparse              = ["false"]
  2224.  
  2225.         if 'filename' in PhyPartition[k][j]:
  2226.             ##print "filename exists"
  2227.             #print PhyPartition[k][j]['filename']
  2228.             #print FileToProgram[0]
  2229.            
  2230.             FileToProgram[0]            = PhyPartition[k][j]['filename'][0]
  2231.             FileOffset[0]               = PhyPartition[k][j]['fileoffset'][0]
  2232.             FilePartitionOffset[0]      = PhyPartition[k][j]['filepartitionoffset'][0]
  2233.             FileAppsbin[0]              = PhyPartition[k][j]['appsbin'][0]
  2234.             FileSparse[0]               = PhyPartition[k][j]['sparse'][0]
  2235.            
  2236.             for z in range(1,len(PhyPartition[k][j]['filename'])):
  2237.                 FileToProgram.append( PhyPartition[k][j]['filename'][z] )
  2238.                 FileOffset.append( PhyPartition[k][j]['fileoffset'][z] )
  2239.                 FilePartitionOffset.append( PhyPartition[k][j]['filepartitionoffset'][z] )
  2240.                 FileAppsbin.append( PhyPartition[k][j]['appsbin'][z] )
  2241.                 FileSparse.append( PhyPartition[k][j]['sparse'][z] )
  2242.  
  2243.             #print PhyPartition[k][j]['fileoffset']
  2244.            
  2245.  
  2246.         #for z in range(len(FileToProgram)):
  2247.         #    print "FileToProgram[",z,"]=",FileToProgram[z]
  2248.         #    print "FileOffset[",z,"]=",FileOffset[z]
  2249.         #    print " "
  2250.  
  2251.         PartitionLabel  = ""
  2252.         Type            = ""
  2253.         Bootable        = "false"
  2254.  
  2255.  
  2256.         if 'label' in PhyPartition[k][j]:
  2257.             PartitionLabel = PhyPartition[k][j]['label']
  2258.         if 'type' in PhyPartition[k][j]:
  2259.             Type = PhyPartition[k][j]['type']
  2260.         if 'bootable' in PhyPartition[k][j]:
  2261.             Bootable = PhyPartition[k][j]['bootable']
  2262.  
  2263.  
  2264.         ## Update main logical partition
  2265.         offset += 0x1BE     ## this naturally increments to 0x200, then 0x400 etc
  2266.  
  2267.         ##UpdatePartitionTable(Bootable,Type,EBROffset,PartitionSectorSize,offset) ; offset +=16
  2268.         EBR = UpdatePartitionTable(Bootable,Type,FirstLBA-ExtendedPartitionBegins-EBROffset,PartitionSectorSize,offset,EBR) ; offset +=16
  2269.  
  2270.         ## Update EXT, i.e. are there more partitions to come?
  2271.         if (j+1) == (NumEBRPartitions+3):
  2272.             ## No, this is the very last so indicate no more logical partitions
  2273.             EBR = UpdatePartitionTable("false","00",0,0,offset,EBR)    ; offset +=16  ## on last partition, so no more
  2274.         else:
  2275.             ## Yes, at least one more, so indicate EXT type of 05
  2276.             EBR = UpdatePartitionTable("false","05",j-2,1,offset,EBR)  ; offset +=16
  2277.  
  2278.         ## Update last 2 which are always blank
  2279.         EBR = UpdatePartitionTable("false","00",0,0,offset,EBR)        ; offset +=16
  2280.         EBR = UpdatePartitionTable("false","00",0,0,offset,EBR)        ; offset +=16
  2281.  
  2282.         EBR[offset]     = 0x55      ; offset +=1
  2283.         EBR[offset]     = 0xAA      ; offset +=1
  2284.  
  2285.  
  2286.         ## Now update EBROffset
  2287.         EBROffset += 1                      # Each EBR gets us one closer
  2288.  
  2289.         for z in range(len(FileToProgram)):
  2290.             #print "File: ",FileToProgram[z]
  2291.             #print "FilePartitionOffset[z]=",FilePartitionOffset[z]
  2292.             UpdateRawProgram(RawProgramXML,FirstLBA+FilePartitionOffset[z], PartitionSectorSize*SECTOR_SIZE_IN_BYTES/1024.0, k, FileOffset[z], PartitionSectorSize-FilePartitionOffset[z], FileToProgram[z], FileSparse[z], PartitionLabel)
  2293.  
  2294.         FirstLBA = LastLBA      # getting ready for next partition, FirstLBA is now where we left off
  2295.  
  2296.  
  2297.     print "\n------------------------------------------------------------------------------"
  2298.     print "             LastLBA is currently %i sectors" % (LastLBA)
  2299.     print "       Card size of at least %.1fMB needed (%u sectors)" % (LastLBA/2048.0,LastLBA)
  2300.     print "------------------------------------------------------------------------------"
  2301.  
  2302. def ReturnNumSectorsTillBoundary(CurrentLBA, BoundaryInKB):
  2303.     #Say BoundaryInKB is 65536 (64MB)
  2304.     #    if SECTOR_SIZE_IN_BYTES=512,  BoundaryLBA=131072
  2305.     #    if SECTOR_SIZE_IN_BYTES=4096, BoundaryLBA=16384
  2306.    
  2307.     #Say were at the 63MB boundary, then
  2308.     #    if SECTOR_SIZE_IN_BYTES=512,  CurrentLBA=129024
  2309.     #    if SECTOR_SIZE_IN_BYTES=4096, CurrentLBA=16128
  2310.    
  2311.     # Distance is then 1MB
  2312.     #    if SECTOR_SIZE_IN_BYTES=512,  DistanceLBA=2048   (2048*512=1MB)
  2313.     #    if SECTOR_SIZE_IN_BYTES=4096, DistanceLBA=256    (256*4096=1MB)
  2314.  
  2315.     ##import pdb; pdb.set_trace()
  2316.    
  2317.     x = 0
  2318.     if BoundaryInKB>0:
  2319.         if (CurrentLBA%ConvertKBtoSectors(BoundaryInKB)) > 0:
  2320.             x = ConvertKBtoSectors(BoundaryInKB) - (CurrentLBA%ConvertKBtoSectors(BoundaryInKB))
  2321.    
  2322.     ##print "\tFYI: Increase by %dKB (%d sectors) if you want to align to %i KB boundary at sector %d" % (x/2,x,BoundaryInKB,CurrentLBA+x)
  2323.     return x
  2324.  
  2325.  
  2326. def WriteMBR():
  2327.     global opfile,MBR
  2328.     for b in MBR:
  2329.         opfile.write(struct.pack("B", b))
  2330.  
  2331. def WriteEBR():
  2332.     global opfile,EBR
  2333.     for b in EBR:
  2334.         opfile.write(struct.pack("B", b))
  2335.  
  2336. def PrintBigError(sz):
  2337.     print "\t _________________ ___________ "
  2338.     print "\t|  ___| ___ \\ ___ \\  _  | ___ \\"
  2339.     print "\t| |__ | |_/ / |_/ / | | | |_/ /"
  2340.     print "\t|  __||    /|    /| | | |    / "
  2341.     print "\t| |___| |\\ \\| |\\ \\\\ \\_/ / |\\ \\ "
  2342.     print "\t\\____/\\_| \\_\\_| \\_|\\___/\\_| \\_|\n"
  2343.  
  2344.     if len(sz)>0:
  2345.         print sz
  2346.         sys.exit(1)
  2347.                                    
  2348.  
  2349. def find_file(filename, search_paths):
  2350.     print "\n\n\tLooking for ",filename
  2351.     print "\t"+"-"*40
  2352.     for x in search_paths:
  2353.         print "\tSearching ",x
  2354.         temp = os.path.join(x, filename)
  2355.         if os.path.exists(temp):
  2356.             print "\n\t**Found %s (%i bytes)" % (temp,os.path.getsize(temp))
  2357.             return temp
  2358.  
  2359.     ## search cwd last
  2360.     print "\tSearching ",os.getcwd()
  2361.     if os.path.exists(filename):
  2362.         print "\n\t**Found %s (%i bytes)" % (filename,os.path.getsize(filename))
  2363.         return filename
  2364.  
  2365.     print "\tCound't find file\n"
  2366.     return None
  2367.  
  2368. ## ==============================================================================================
  2369. ## ==============================================================================================
  2370. ## ==============================================================================================
  2371. ## =====main()===================================================================================
  2372. ## ==============================================================================================
  2373. ## ==============================================================================================
  2374. ## ==============================================================================================
  2375.  
  2376. if len(sys.argv) < 2:
  2377.     CreateErasingRawProgramFiles()
  2378.     ShowUsage()
  2379.     sys.exit(); # error
  2380.  
  2381. print "\nCWD: ", os.getcwd(), "\n"
  2382.  
  2383. try:
  2384.     opts, args = getopt.getopt(sys.argv[1:], "x:f:p:s:t:g:k:v:e", ["xml=", "format=", "partition=", "search_path=", "location=", "sequentialguid=", "use128partitions=", "verbose=","erasefirst"])
  2385. except getopt.GetoptError, err:
  2386.     # print help information and exit:
  2387.     print str(err) # will print something like "option -a not recognized"
  2388.     ShowUsage()
  2389.     sys.exit(1)
  2390.  
  2391. XMLFile= "aaron"
  2392. OutputToCreate          = None ## sys.argv[2]
  2393. PhysicalPartitionNumber = 0     ## sys.argv[3]
  2394. search_paths            = []
  2395.  
  2396. verbose                 = False
  2397. UsingGetOpts            = False
  2398. sequentialguid          = 0
  2399. force128partitions      = 0
  2400. PhysicalPartitionNumber = -1
  2401. erasefirst              = 0
  2402.  
  2403. for o, a in opts:
  2404.     if o in ("-x", "--xml"):
  2405.         UsingGetOpts = True
  2406.         XMLFile = a
  2407.     elif o in ("-t", "--location"):
  2408.         OutputFolder = a
  2409.         OutputFolder = re.sub(r"\\$","",OutputFolder)    # remove final slash if it exists
  2410.         OutputFolder = re.sub(r"/$","",OutputFolder)     # remove final slash if it exists
  2411.  
  2412.         OutputFolder += "/"     # slashes will all be corrected below
  2413.  
  2414.         if sys.platform.startswith("linux"):
  2415.             OutputFolder = re.sub(r"\\","/",OutputFolder)   # correct slashes
  2416.         else:
  2417.             OutputFolder = re.sub(r"/","\\\\",OutputFolder) # correct slashes
  2418.  
  2419.         print "OutputFolder=",OutputFolder
  2420.         EnsureDirectoryExists(OutputFolder) # only need to call once
  2421.  
  2422.     elif o in ("-f", "--format"):
  2423.         UsingGetOpts = True
  2424.         OutputToCreate = a
  2425.         m = re.search("^(mbr|gpt)$", a)     #mbr|gpt
  2426.         if type(m) is NoneType:
  2427.             PrintBigError("ERROR: Only MBR or GPT is supported")
  2428.         else:
  2429.             OutputToCreate = m.group(1)
  2430.  
  2431.     elif o in ("-s", "--search_path"):
  2432.         ## also allow seperating commas
  2433.         for x in a.strip("\n").split(","):
  2434.             search_paths.append(x)
  2435.  
  2436.     elif o in ("-k", "--use128partitions"):
  2437.         ## Force there to be 128 partitions in the partition table
  2438.         m = re.search("\d", a)     #mbr|gpt
  2439.         if type(m) is NoneType:
  2440.             force128partitions = 0
  2441.         else:
  2442.             force128partitions = 1
  2443.  
  2444.     elif o in ("-e", "--erasefirst"):
  2445.         erasefirst = 1;
  2446.  
  2447.     elif o in ("-g", "--sequentialguid"):
  2448.         ## also allow seperating commas
  2449.         m = re.search("\d", a)     #mbr|gpt
  2450.         if type(m) is NoneType:
  2451.             sequentialguid = 0
  2452.         else:
  2453.             sequentialguid = 1
  2454.  
  2455.     elif o in ("-p", "--partition"):
  2456.         UsingGetOpts = True
  2457.         PhysicalPartitionNumber = a
  2458.         m = re.search("^(\d)$", a)     #0|1|2
  2459.         if type(m) is NoneType:
  2460.             PrintBigError("ERROR: PhysicalPartitionNumber (-p) must be a number, you supplied *",a,"*")
  2461.         else:
  2462.             PhysicalPartitionNumber = int(m.group(1))
  2463.     elif o in ("-v", "--verbose"):
  2464.         UsingGetOpts = True
  2465.         verbose = True
  2466.     else:
  2467.         print "o=",o
  2468.         assert False, "unhandled option"
  2469.  
  2470. if UsingGetOpts is False:
  2471.     #ParseCommandLine()
  2472.     PrintBanner("NEW USAGE - Note this program will auto-detect if it's GPT or MBR")
  2473.     ShowUsage()
  2474.     sys.exit(1)
  2475.  
  2476. print "XMLFile=",XMLFile
  2477. if len(OutputFolder)>0:
  2478.     print "OutputFolder=",OutputFolder
  2479. print "OutputToCreate",OutputToCreate
  2480. print "PhysicalPartitionNumber",PhysicalPartitionNumber
  2481. print "verbose",verbose
  2482.  
  2483.  
  2484. XMLFile = find_file(XMLFile, search_paths)
  2485. if XMLFile is None:
  2486.     PrintBigError("ERROR: Could not find file")
  2487.  
  2488. ParseXML(XMLFile)  # parses XMLFile, discovers if GPT or MBR
  2489.  
  2490. PrintBanner("OutputToCreate ===> '%s'" % OutputToCreate)
  2491.  
  2492. def InitializeXMLFileVars():
  2493.     global EmmcLockRegionsXML,RawProgramXML,RawProgramXML_Wipe,PatchesXML,RawProgramXML_Blank,PatchesXML_Blank
  2494.  
  2495.     EmmcLockRegionsXML = Element('protect')
  2496.     EmmcLockRegionsXML.append(Comment("NOTE: This is an ** Autogenerated file **"))
  2497.     EmmcLockRegionsXML.append(Comment('NOTE: Sector size is %ibytes, WRITE_PROTECT_BOUNDARY_IN_KB=%i, WRITE_PROTECT_BOUNDARY_IN_SECTORS=%i' % (SECTOR_SIZE_IN_BYTES,HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'],ConvertKBtoSectors(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']))))
  2498.     EmmcLockRegionsXML.append(Comment("NOTE: \"num_sectors\" in HEX \"start_sector\" in HEX, i.e. 10 really equals 16 !!"))
  2499.  
  2500.     RawProgramXML = Element('data')
  2501.     RawProgramXML.append(Comment('NOTE: This is an ** Autogenerated file **'))
  2502.     RawProgramXML.append(Comment('NOTE: Sector size is %ibytes'%SECTOR_SIZE_IN_BYTES))
  2503.  
  2504.     RawProgramXML_Wipe = Element('data')
  2505.     RawProgramXML_Wipe.append(Comment('NOTE: This is an ** Autogenerated file **'))
  2506.     RawProgramXML_Wipe.append(Comment('NOTE: Sector size is %ibytes'%SECTOR_SIZE_IN_BYTES))
  2507.  
  2508.     PatchesXML = Element('patches')
  2509.     PatchesXML.append(Comment('NOTE: This is an ** Autogenerated file **'))
  2510.     PatchesXML.append(Comment('NOTE: Patching is in little endian format, i.e. 0xAABBCCDD will look like DD CC BB AA in the file or on disk'))
  2511.     PatchesXML.append(Comment('NOTE: This file is used by Trace32 - So make sure to add decimals, i.e. 0x10-10=0, *but* 0x10-10.=6.'))
  2512.  
  2513.     RawProgramXML_Blank = Element('data')
  2514.     RawProgramXML_Blank.append(Comment('NOTE: This is an ** Autogenerated file **'))
  2515.     RawProgramXML_Blank.append(Comment('NOTE: This file writes a VALID but EMPTY partition table to sector 0 **'))
  2516.     RawProgramXML_Blank.append(Comment('NOTE: Sector size is %ibytes'%SECTOR_SIZE_IN_BYTES))
  2517.  
  2518.     PatchesXML_Blank = Element('patches')
  2519.     PatchesXML_Blank.append(Comment('NOTE: This is an ** Autogenerated file **'))
  2520.     PatchesXML_Blank.append(Comment('NOTE: Patching is in little endian format, i.e. 0xAABBCCDD will look like DD CC BB AA in the file or on disk'))
  2521.     PatchesXML_Blank.append(Comment('NOTE: This file is used by Trace32 - So make sure to add decimals, i.e. 0x10-10=0, *but* 0x10-10.=6.'))
  2522.  
  2523. if OutputToCreate == "gpt":
  2524.     if PhysicalPartitionNumber == -1:
  2525.         for PhysicalPartitionNumber in range(0,len(PhyPartition)):  ## where len(PhyPartition) is typically a maximum of 8
  2526.             InitializeXMLFileVars()
  2527.             CreateGPTPartitionTable( PhysicalPartitionNumber ) ## wants it in LBA format, i.e. 1KB = 2 sectors of size SECTOR_SIZE_IN_BYTES
  2528.         CreateErasingRawProgramFiles()
  2529.         print "\n\nNOTE: All Physical Partitions / LUNs were created since user did not use -p 0 option\n\n"
  2530.     else:
  2531.         InitializeXMLFileVars()
  2532.         CreateGPTPartitionTable( PhysicalPartitionNumber, True ) ## wants it in LBA format, i.e. 1KB = 2 sectors of size SECTOR_SIZE_IN_BYTES
  2533.         CreateErasingRawProgramFiles()
  2534. else:
  2535.     InitializeXMLFileVars()
  2536.     CreateMBRPartitionTable( PhysicalPartitionNumber )
  2537.     CreateFinalPartitionBin()
  2538.  
  2539.  
  2540.  
  2541.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement