#!/usr/bin/python #=========================================================================== # This script parses "partition.xml" and creates numerous output files # specifically, partition.bin, rawprogram.xml # REFERENCES # $Header: //components/rel/boot.bf/3.1.1/boot_images/core/storage/tools/ptool/ptool.py#1 $ # $DateTime: 2014/09/09 14:47:07 $ # $Author: pwbldsvc $ # when who what, where, why # -------- --- ------------------------------------------------------- # 2012-08-20 ah Allow "uniqueguid" in partition.xml # 2012-08-16 ah Fixed bug if PERFORMANCE_BOUNDARY_IN_KB wasn't specified # 2012-08-14 ah PERFORMANCE_BOUNDARY_IN_KB can now be an individual partition tag # 2012-07-06 ah More user friendly with ShowPartitionExample() # 2012-04-30 ah GPT Attributes bits corrected # 2012-02-24 ah Much cleaner code - fixes for configurable sector sizes # 2012-02-15 ah Minor fix when 'SECTOR_SIZE_IN_BYTES' is not defined # 2012-01-13 ah Fixed bug where rawprogram.xml was reporting numsectors off by 1 # 2011-11-22 ah Added SECTOR_SIZE_IN_BYTES option (defaults to 512) # 2011-11-17 ah Added force128 partitions, option -k # 2011-11-14 ah Enabled zeroout tag for GPT # 2011-10-19 ah Not allowing empty tags in partition.xml - makes multiple PHY partitions work # 2011-09-23 ah GPT num partitions in table not fixed to 128, respecting partition table attributes now # 2011-08-12 ah Added ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY, WRITE_PROTECT_GPT_PARTITION_TABLE # 2011-08-11 ah Added Unique GUID option or Sequential -g (default is unique) # 2011-08-09 ah Fix alignment issue for WPG<64MB - Fixed GPT off by 1 sector issue # 2011-08-04 ah Now allowing -t option to specify output directory for files # 2011-07-26 ah Much better error message if GUID invalid, fixed 'grow' partition size (patch) # 2011-07-21 ah Major revision, using getopt(), auto-discovering GPT or MBR # 2011-07-13 ah Corrected sparse support # 2011-06-01 ah Added sparse support for GPT - corrected size of last partition # 2011-05-26 ah Adds "zeroout" tag (wiping GPT) and "sparse" file support # 2011-05-21 ab Undoing hack for boot to wipe out sector 1 # 2011-05-17 ah removing GPT sectors is simpler now, compatible with 8960 tz.mbn issue # 2011-05-06 ah MBR partition tables now nuke any trace of GPT (request from boot team) # 2011-04-26 ah temporarily removed 'start_byte_hex':szStartByte for QPST compatibility # 2011-03-23 ah ensured last partition is size 0 for rawprogram.xml # 2011-03-22 ah rawprogram for GPT for 'grow' partition, since mjsdload.cmm couldn't handle big number # 2011-03-22 ah Corrected final disk size patch (off by 1 sector), corrected GPT labels (uni-code) # 2011-03-18 ah Fixed default bug for DISK_SIGNATURE, align_wpb -> align # 2011-03-16 ah New DISK_SIGNATURE tag added for MBR partitions, Split partition0.bin into # MBR0.bin and EBR0.bin, Corrected bug in backup GPT DISK patching # 2011-03-10 ah Removes loadpt.cmm, splits partition0.bin to MBR0.bin, EBR0.bin # 2011-03-09 ah Much more error checking, cleaner, adds "align_wpb" tag # 2011-02-14 ah Added patching of DISK for GPT # 2011-02-02 ah Allow MBR Type to be specified as "4C" or "0x4C" # 2011-25-01 ah Outputs "patch.xml" as well, allows more optimal partition alignment # 2010-12-01 ah Matching QPST, all EXT partitions 64MB aligned (configurable actually) # More error checking, Removed CHS option, GPT output is 2 files (primary and backup) # 2010-10-26 ah better error checking, corrected typo on physical_partition for > 0 # 2010-10-25 ah adds GPT, CFILE output, various other features # 2010-10-08 ah released to remove compile errors of missing PERL script modules # Copyright (c) 2007-2010 Qualcomm Technologies, Inc. # All Rights Reserved. # Confidential and Proprietary - Qualcomm Technologies, Inc. # ===========================================================================*/ import sys,os,getopt import random,math import re import struct from types import * from time import sleep if sys.version_info < (2,5): sys.stdout.write("\n\nERROR: This script needs Python version 2.5 or greater, detected as ") print sys.version_info sys.exit() # error from xml.etree import ElementTree as ET #from elementtree.ElementTree import ElementTree from xml.etree.ElementTree import Element, SubElement, Comment, tostring from xml.dom import minidom OutputFolder = "" LastPartitionBeginsAt = 0 HashInstructions = {} tempVar = 5 NumPhyPartitions = 0 PartitionCollection = [] # An array of Partition objects. Partition is a hash of information about partition PhyPartition = {} # An array of PartitionCollection objects MinSectorsNeeded = 0 # Ex. PhyPartition[0] holds the PartitionCollection that holds all the info for partitions in PHY partition 0 AvailablePartitions = {} XMLFile = "module_common.py" ExtendedPartitionBegins= 0 instructions = [] HashStruct = {} StructPartitions = [] StructAdditionalFields = [] AllPartitions = {} PARTITION_SYSTEM_GUID = 0x3BC93EC9A0004BBA11D2F81FC12A7328 PARTITION_MSFT_RESERVED_GUID= 0xAE1502F02DF97D814DB80B5CE3C9E316 PARTITION_BASIC_DATA_GUID = 0xC79926B7B668C0874433B9E5EBD0A0A2 SECTOR_SIZE_IN_BYTES = 512 # This can be over ridden in the partition.xml file 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) 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) ## Note that these HashInstructions are updated by the XML file HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] = 64*1024 HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = True HashInstructions['DISK_SIGNATURE'] = 0x0 MBR = [0]*SECTOR_SIZE_IN_BYTES EBR = [0]*SECTOR_SIZE_IN_BYTES hash_w = [{'start_sector':0,'num_sectors':(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES), '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}] NumWPregions = 0 def ShowPartitionExample(): print "Your \"partition.xml\" file needs to look like something like this below" print "\t(i.e. notice the *multiple* physical_partition tags)\n" print "" print "" print " " print "" print " " print "" print "" print " " print "" def ConvertKBtoSectors(x): ## 1KB / SECTOR_SIZE_IN_BYTES normally means return 2 (i.e. with SECTOR_SIZE_IN_BYTES=512) ## 2KB / SECTOR_SIZE_IN_BYTES normally means return 4 (i.e. with SECTOR_SIZE_IN_BYTES=512) return int((x*1024)/SECTOR_SIZE_IN_BYTES) def UpdatePatch(StartSector,ByteOffset,PHYPartition,size_in_bytes,szvalue,szfilename,szwhat): global PatchesXML SubElement(PatchesXML, 'patch', {'start_sector':StartSector, 'byte_offset':ByteOffset, 'physical_partition_number':str(PHYPartition), 'size_in_bytes':str(size_in_bytes), 'value':szvalue, 'filename':szfilename, 'SECTOR_SIZE_IN_BYTES':str(SECTOR_SIZE_IN_BYTES), 'what':szwhat }) def UpdateRawProgram(RawProgramXML, StartSector, size_in_KB, PHYPartition, file_sector_offset, num_partition_sectors, filename, sparse, label): if StartSector<0: szStartSector = "NUM_DISK_SECTORS%d." % StartSector ## as in NUM_DISK_SECTORS-33 since %d=-33 szStartByte = "(%d*NUM_DISK_SECTORS)%d." % (SECTOR_SIZE_IN_BYTES,StartSector*SECTOR_SIZE_IN_BYTES) else: #print "\nTo be here means StartSector>0" #print "UpdateRawProgram StartSector=",StartSector #print "StartSector=",type(StartSector) #print "-----------------------------------------" szStartByte = str(hex(StartSector*SECTOR_SIZE_IN_BYTES)) szStartSector = str(StartSector) #import pdb; pdb.set_trace() if num_partition_sectors<=0: #print "*"*78 #print "WARNING: num_partition_sectors is %d for '%s' PHYPartition=%d, setting it to 0" % (num_partition_sectors,label,PHYPartition) #print "\tThis can happen if you only have 1 partition and thus it is the grow partition" num_partition_sectors = 0 size_in_KB = 0 SubElement(RawProgramXML, 'program', {'start_sector':szStartSector, 'size_in_KB':str(size_in_KB), 'physical_partition_number':str(PHYPartition), 'file_sector_offset':str(file_sector_offset), 'num_partition_sectors':str(num_partition_sectors), 'filename':filename, 'sparse':sparse, 'start_byte_hex':szStartByte, 'SECTOR_SIZE_IN_BYTES':str(SECTOR_SIZE_IN_BYTES), 'label':label }) #iter = RawProgramXML.getiterator() #for element in iter: # print "\nElement:" , element.tag, " : ", element.text # thins like image,primary,extended etc # if element.keys(): # print "\tAttributes:" # for name, value in element.items(): # print "\t\tName: '%s'=>'%s' " % (name,value) #import pdb; pdb.set_trace() def PrintBigWarning(sz): print "\t _ " print "\t (_) " print "\t__ ____ _ _ __ _ __ _ _ __ __ _ " print "\t\\ \\ /\\ / / _` | '__| '_ \\| | '_ \\ / _` |" print "\t \\ V V / (_| | | | | | | | | | | (_| |" print "\t \\_/\\_/ \\__,_|_| |_| |_|_|_| |_|\\__, |" print "\t __/ |" print "\t |___/ \n" if len(sz)>0: print sz def ValidGUIDForm(GUID): if type(GUID) is not str: GUID = str(GUID) print "Testing if GUID=",GUID m = re.search("0x([a-fA-F\d]{32})$", GUID) #0xC79926B7B668C0874433B9E5EBD0A0A2 if type(m) is not NoneType: return True 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) if type(m) is not NoneType: return True print "GUID does not match regular expression" return False def ValidateTYPE(Type): # for type I must support the original "4C" and if they put "0x4C" if type(Type) is int: if Type>=0 and Type<=255: return Type if type(Type) is not str: Type = str(Type) m = re.search("^(0x)?([a-fA-F\d][a-fA-F\d]?)$", Type) if type(m) is NoneType: print "\tWARNING: Type \"%s\" is not in the form 0x4C" % Type sys.exit(1) else: #print m.group(2) #print "---------" #print "\tType is \"0x%X\"" % Type return int(m.group(2),16) def ValidateGUID(GUID): if type(GUID) is not str: GUID = str(GUID) print "Looking to validate GUID=",GUID m = re.search("0x([a-fA-F\d]{32})$", GUID) #0xC79926B7B668C0874433B9E5EBD0A0A2 if type(m) is not NoneType: tempGUID = int(m.group(1),16) print "\tGUID \"%s\"" % GUID if tempGUID == PARTITION_SYSTEM_GUID: print "\tPARTITION_SYSTEM_GUID detected\n" elif tempGUID == PARTITION_MSFT_RESERVED_GUID: print "\tPARTITION_MSFT_RESERVED_GUID detected\n" elif tempGUID == PARTITION_BASIC_DATA_GUID: print "\tPARTITION_BASIC_DATA_GUID detected\n" else: print "\tUNKNOWN PARTITION_GUID detected\n" return tempGUID else: #ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 --> #0x C7 99 26 B7 B6 68 C087 4433 B9E5 EBD0A0A2 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) if type(m) is not NoneType: print "Found more advanced type" tempGUID = (int(m.group(4),16)<<64) | (int(m.group(3),16)<<48) | (int(m.group(2),16)<<32) | int(m.group(1),16) 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) tempGUID|= (int(m.group(11),16)<<120)| (int(m.group(10),16)<<112)| (int(m.group(9),16)<<104) print "** CONVERTED GUID \"%s\" is FOUND --> 0x%X" % (GUID,tempGUID) return tempGUID else: print "\nWARNING: "+"-"*78 print "*"*78 print "WARNING: GUID \"%s\" is not in the form ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" % GUID print "*"*78 print "WARNING"+"-"*78+"\n" print "Converted to PARTITION_BASIC_DATA_GUID (0xC79926B7B668C0874433B9E5EBD0A0A2)\n" return PARTITION_BASIC_DATA_GUID def EnsureDirectoryExists(filename): dir = os.path.dirname(filename) try: os.stat(dir) except: os.makedirs(dir) def WriteGPT(GPTMAIN, GPTBACKUP): global opfile,PrimaryGPT,BackupGPT,GPTBOTH #for b in PrimaryGPT: # opfile.write(struct.pack("B", b)) #for b in BackupGPT: # opfile.write(struct.pack("B", b)) ofile = open(GPTMAIN, "wb") for b in PrimaryGPT: ofile.write(struct.pack("B", b)) ofile.close() print "\nCreated \"%s\"\t\t\t<-- Primary GPT partition tables + protective MBR" % GPTMAIN ofile = open(GPTBACKUP, "wb") for b in BackupGPT: ofile.write(struct.pack("B", b)) ofile.close() print "Created \"%s\"\t\t<-- Backup GPT partition tables" % GPTBACKUP ofile = open(GPTBOTH, "wb") for b in PrimaryGPT: ofile.write(struct.pack("B", b)) for b in BackupGPT: ofile.write(struct.pack("B", b)) ofile.close() print "Created \"%s\" \t\t<-- you can run 'perl parseGPT.pl %s'" % (GPTBOTH,GPTBOTH) def UpdatePrimaryGPT(value,length,i): global PrimaryGPT for b in range(length): PrimaryGPT[i] = ((value>>(b*8)) & 0xFF) ; i+=1 return i def UpdateBackupGPT(value,length,i): global BackupGPT for b in range(length): BackupGPT[i] = ((value>>(b*8)) & 0xFF) ; i+=1 return i def ShowBackupGPT(sector): global BackupGPT print "Sector: %d" % sector for j in range(32): for i in range(16): sys.stdout.write("%.2X " % BackupGPT[i+j*16+sector*SECTOR_SIZE_IN_BYTES]) print " " print " " def CreateFileOfZeros(filename,num_sectors): try: opfile = open(filename, "w+b") except Exception, x: print "ERROR: Could not create '%s', cwd=%s" % (filename,os.getcwd() ) print "REASON: %s" % (x) sys.exit(1) temp = [0]*(SECTOR_SIZE_IN_BYTES*num_sectors) zeros = struct.pack("%iB"%(SECTOR_SIZE_IN_BYTES*num_sectors),*temp) try: opfile.write(zeros) except Exception, x: print "ERROR: Could not write zeros to '%s'\nREASON: %s" % (filename,x) sys.exit(1) try: opfile.close() except Exception, x: print "\tWARNING: Could not close %s" % filename print "REASON: %s" % (x) print "Created \"%s\"\t\t<-- full of binary zeros - used by \"wipe\" rawprogram files" % filename def CreateErasingRawProgramFiles(): CreateFileOfZeros("zeros_1sector.bin",1) CreateFileOfZeros("zeros_33sectors.bin",33) ##import pdb; pdb.set_trace() for i in range(8): # PHY partitions 0 to 7 exist (with 4,5,6,7 as GPPs) if i==3: continue # no such PHY partition as of Feb 23, 2012 temp = Element('data') temp.append(Comment('NOTE: This is an ** Autogenerated file **')) temp.append(Comment('NOTE: Sector size is %ibytes'%SECTOR_SIZE_IN_BYTES)) UpdateRawProgram(temp,0, 0.5, i, 0, 1, "zeros_1sector.bin", "false", "Overwrite MBR sector") UpdateRawProgram(temp,1, 33*SECTOR_SIZE_IN_BYTES/1024.0, i, 0, 33, "zeros_33sectors.bin", "false", "Overwrite Primary GPT Sectors") UpdateRawProgram(temp,-33, 33*SECTOR_SIZE_IN_BYTES/1024.0, i, 0, 33, "zeros_33sectors.bin", "false", "Overwrite Backup GPT Sectors") RAW_PROGRAM = '%swipe_rawprogram_PHY%d.xml' % (OutputFolder,i) opfile = open(RAW_PROGRAM, "w") opfile.write( prettify(temp) ) opfile.close() print "Created \"%s\"\t<-- Used to *wipe/erase* partition information" % RAW_PROGRAM NumPartitions = 0 SizeOfPartitionArray= 0 def CreateGPTPartitionTable(PhysicalPartitionNumber): global opfile,PhyPartition,PrimaryGPT,BackupGPT,RawProgramXML, GPTMAIN, GPTBACKUP, GPTBOTH, RAW_PROGRAM, PATCHES print "\n\nMaking GUID Partitioning Table (GPT)" #PrintBanner("instructions") #print "\nGoing through partitions listed in XML file" ## Step 2. Move through partitions resizing as needed based on WRITE_PROTECT_BOUNDARY_IN_KB #print "\n\n--------------------------------------------------------" #print "This is the order of the partitions" # I most likely need to resize at least one partition below to the WRITE_PROTECT_BOUNDARY_IN_KB boundary #for k in range(len(PhyPartition)): k = PhysicalPartitionNumber GPTMAIN = '%sgpt_main%d.bin' % (OutputFolder,k) GPTBACKUP = '%sgpt_backup%d.bin' % (OutputFolder,k) GPTBOTH = '%sgpt_both%d.bin' % (OutputFolder,k) RAW_PROGRAM = '%srawprogram%d.xml' % (OutputFolder,k) RAW_PROGRAM_BLANK = '%srawprogram%d_BLANK.xml'% (OutputFolder,k) PATCHES = '%spatch%i.xml' % (OutputFolder,k) #for k in range(1): PrimaryGPT = [0]*(34*SECTOR_SIZE_IN_BYTES) # This is LBA 0 to 33 (34 sectors total) (start of disk) BackupGPT = [0]*(33*SECTOR_SIZE_IN_BYTES) # This is LBA-33 to -1 (33 sectors total) (end of disk) ## --------------------------------------------------------------------------------- ## Step 2. Move through xml definition and figure out partitions sizes ## --------------------------------------------------------------------------------- i = 2*SECTOR_SIZE_IN_BYTES ## partition arrays begin here FirstLBA = 34 LastLBA = 34 ## Make these equal at first if HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] is True: UpdateWPhash(FirstLBA, 0) # make sure 1st write protect boundary is setup correctly #print "len(PhyPartition)=%d and k=%d" % (len(PhyPartition),k) if(k>=len(PhyPartition)): print "\nERROR: PHY Partition %i of %i not found" % (k,len(PhyPartition)) print "\nERROR: PHY Partition %i of %i not found\n\n" % (k,len(PhyPartition)) ShowPartitionExample() sys.exit() SectorsTillNextBoundary = 0 print "\n\nOn PHY Partition %d that has %d partitions" % (k,len(PhyPartition[k])) for j in range(len(PhyPartition[k])): #print "\nPartition name='%s' (readonly=%s)" % (PhyPartition[k][j]['label'], PhyPartition[k][j]['readonly']) #print "\tat sector location %d (%d KB or %.2f MB) and LastLBA=%d" % (FirstLBA,FirstLBA/2,FirstLBA/2048,LastLBA) #print "%d of %d with label %s" %(j,len(PhyPartition[k]),PhyPartition[k][j]['label']) print "\n"+"="*78 print " _ (\"-._ (\"-._ (\"-._ (\"-._ (\"-._ (\"-._ (\"-._ (\"-._ (\"-." print " ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )" print " (_,-\" (_,-\" (_,-\" (_,-\" (_,-\" (_,-\" (_,-\" (_,-\" (_,-\"" print "="*78 PhyPartition[k][j]['size_in_kb'] = int(PhyPartition[k][j]['size_in_kb']) 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) ##import pdb; pdb.set_trace() # timmy if HashInstructions['PERFORMANCE_BOUNDARY_IN_KB']>0 and HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] is False: 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']) 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']) print "To correct this, partition.xml should look like this\n" print "\t" print "\t\tPERFORMANCE_BOUNDARY_IN_KB = %i" % Partition['PERFORMANCE_BOUNDARY_IN_KB'] print "\t\tALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY=true" print "\t\n\n" if HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] is True: ## to be here means this partition *must* be on an ALIGN boundary print "\tAlignment is to %iKB" % PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB'] SectorsTillNextBoundary = ReturnNumSectorsTillBoundary(FirstLBA,PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']) ## hi if SectorsTillNextBoundary>0: print "\tSectorsTillNextBoundary=%d, FirstLBA=%d it needs to be moved to be aligned to %d" % (SectorsTillNextBoundary,FirstLBA,FirstLBA + SectorsTillNextBoundary) ##print "\tPhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']=",PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB'] FirstLBA += SectorsTillNextBoundary else: if PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']>0: print "\tThis partition is *NOT* aligned to a performance boundary\n" if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0: SectorsTillNextBoundary = ReturnNumSectorsTillBoundary(FirstLBA,HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']) if PhyPartition[k][j]['readonly']=="true": ## to be here means this partition is read-only, so see if we need to move the start if FirstLBA <= hash_w[NumWPregions]["end_sector"]: 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"]) pass else: 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) FirstLBA += SectorsTillNextBoundary else: print "\n\tThis partition is *NOT* readonly" ## to be here means this partition is writeable, so see if we need to move the start if FirstLBA <= hash_w[NumWPregions]["end_sector"]: 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"]) print "\nhash_w[NumWPregions]['end_sector']=%i" % hash_w[NumWPregions]["end_sector"]; print "FirstLBA=%i\n" %FirstLBA; FirstLBA += SectorsTillNextBoundary print "\tFirstLBA is now %d" % (FirstLBA) else: #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"]) pass if (j+1) == len(PhyPartition[k]): print "\nTHIS IS THE *LAST* PARTITION" if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==True: print "\nMeans patching instructions go here" PhyPartition[k][j]['size_in_kb'] = 0 # infinite huge print "PhyPartition[k][j]['size_in_kb'] set to 0" SectorsRemaining = 33 print "LastLBA=",LastLBA print "FirstLBA=",FirstLBA # gpt patch - size of last partition ################################################ #StartSector = 2*512+40+j*128 ## i.e. skip sector 0 and 1, then it's offset #ByteOffset = str(StartSector%512) #StartSector = str(int(StartSector / 512)) StartSector = 40+j*128 ## i.e. skip sector 0 and 1, then it's offset ByteOffset = str(StartSector%SECTOR_SIZE_IN_BYTES) StartSector = str(2+int(StartSector / SECTOR_SIZE_IN_BYTES)) BackupStartSector = 40+j*128 ByteOffset = str(BackupStartSector%SECTOR_SIZE_IN_BYTES) BackupStartSector = int(BackupStartSector / SECTOR_SIZE_IN_BYTES) ## gpt patch - main gpt partition array UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-34.",os.path.basename(GPTMAIN),"Update last partition %d '%s' with actual size in Primary Header." % ((j+1),PhyPartition[k][j]['label'])) UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-34.","DISK", "Update last partition %d '%s' with actual size in Primary Header." % ((j+1),PhyPartition[k][j]['label'])) ## gpt patch - backup gpt partition array UpdatePatch(str(BackupStartSector), ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-34.",os.path.basename(GPTBACKUP),"Update last partition %d '%s' with actual size in Backup Header." % ((j+1),PhyPartition[k][j]['label'])) UpdatePatch("NUM_DISK_SECTORS-%d." % (33-BackupStartSector),ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-34.","DISK", "Update last partition %d '%s' with actual size in Backup Header." % ((j+1),PhyPartition[k][j]['label'])) LastLBA = FirstLBA + ConvertKBtoSectors( PhyPartition[k][j]['size_in_kb'] ) ## increase by num sectors, LastLBA inclusive, so add 1 for size LastLBA -= 1 # inclusive, meaning 0 to 3 is 4 sectors, OR another way, LastLBA must be odd 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) if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0: AlignedRemainder = FirstLBA % HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']; if AlignedRemainder==0: 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']))) if PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']>0: AlignedRemainder = FirstLBA % PhyPartition[k][j]['PERFORMANCE_BOUNDARY_IN_KB']; if AlignedRemainder==0: print "\t"+"-"*78 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']))) print "\t"+"-"*78 if PhyPartition[k][j]['readonly']=="true": UpdateWPhash(FirstLBA, ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb'])) #print Partition.keys() #print Partition.has_key("label") #print "\tsize %i kB (%.2f MB)" % (PhyPartition[k][j]['size_in_kb'], PhyPartition[k][j]['size_in_kb']/1024) PartitionTypeGUID = PhyPartition[k][j]['type'] print "\nPartitionTypeGUID\t0x%X" % PartitionTypeGUID # If the partition is a multiple of 4, it must start on an LBA boundary of size SECTOR_SIZE_IN_BYTES if j%4==0 : # To be here means the partition number is a multiple of 4, so it must start on # an LBA boundary, i.e. LBA2, LBA3 etc. if i%SECTOR_SIZE_IN_BYTES > 0: print "\tWARNING: Location is %i, need to add %i to offset" % (i, SECTOR_SIZE_IN_BYTES-(i%SECTOR_SIZE_IN_BYTES)) i += (SECTOR_SIZE_IN_BYTES-(i%SECTOR_SIZE_IN_BYTES)) print "\n===============================================================================" 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) print "This partition array entry is at LBA%i, absolute byte address %i (0x%X)" % (i/SECTOR_SIZE_IN_BYTES,i,i) print "NOTE: LBA0 is protective MBR, LBA1 is Primary GPT Header, LBA2 beginning of Partition Array" print "===============================================================================\n" for b in range(16): PrimaryGPT[i] = ((PartitionTypeGUID>>(b*8)) & 0xFF) ; i+=1 # Unique Partition GUID if sequentialguid == 1: UniquePartitionGUID = j+1 else: if PhyPartition[k][j]['uguid'] != "false": UniquePartitionGUID = PhyPartition[k][j]['uguid'] else: UniquePartitionGUID = random.randint(0,2**(128)) print "UniquePartitionGUID\t0x%X" % UniquePartitionGUID # This HACK section is for verifying with GPARTED, allowing me to put in # whatever uniqueGUID that program came up with #if j==0: # UniquePartitionGUID = 0x373C17CF53BC7FB149B85A927ED24483 #elif j==1: # UniquePartitionGUID = 0x1D3C4663FC172F904EC7E0C7A8CF84EC #elif j==2: # UniquePartitionGUID = 0x04A9B2AAEF96DAAE465F429D0EF5C6E2 #else: # UniquePartitionGUID = 0x4D82D027725FD3AE46AF1C5A28944977 for b in range(16): PrimaryGPT[i] = ((UniquePartitionGUID>>(b*8)) & 0xFF) ; i+=1 # First LBA for b in range(8): PrimaryGPT[i] = ((FirstLBA>>(b*8)) & 0xFF) ; i+=1 # Last LBA for b in range(8): PrimaryGPT[i] = ((LastLBA>>(b*8)) & 0xFF) ; i+=1 print "**** FirstLBA=%d and LastLBA=%d and size is %i sectors" % (FirstLBA,LastLBA,LastLBA-FirstLBA+1) # Attributes Attributes = 0x0 if PhyPartition[k][j]['readonly']=="true": Attributes |= 1<<60 ## Bit 60 is read only if PhyPartition[k][j]['hidden']=="true": Attributes |= 1<<62 if PhyPartition[k][j]['dontautomount']=="true": Attributes |= 1<<63 if PhyPartition[k][j]['system']=="true": Attributes |= 1<<0 ##import pdb; pdb.set_trace() for b in range(8): PrimaryGPT[i] = ((Attributes>>(b*8)) & 0xFF) ; i+=1 if len(PhyPartition[k][j]['label'])>36: print "Label %s is more than 36 characters, therefore it's truncated" % PhyPartition[k][j]['label'] PhyPartition[k][j]['label'] = PhyPartition[k][j]['label'][0:36] #print "LABEL %s and i=%i" % (PhyPartition[k][j]['label'],i) # Partition Name for b in PhyPartition[k][j]['label']: PrimaryGPT[i] = ord(b) ; i+=1 PrimaryGPT[i] = 0x00 ; i+=1 for b in range(36-len(PhyPartition[k][j]['label'])): PrimaryGPT[i] = 0x00 ; i+=1 PrimaryGPT[i] = 0x00 ; i+=1 #for b in range(2): # PrimaryGPT[i] = 0x00 ; i+=1 #for b in range(70): # PrimaryGPT[i] = 0x00 ; i+=1 ##FileToProgram = "" ##FileOffset = 0 PartitionLabel = "" ## Default for each partition is no file FileToProgram = [""] FileOffset = [0] FilePartitionOffset = [0] FileAppsbin = ["false"] FileSparse = ["false"] if 'filename' in PhyPartition[k][j]: ##print "filename exists" #print PhyPartition[k][j]['filename'] #print FileToProgram[0] # These are all the default values that should be there, including an empty string possibly for filename FileToProgram[0] = PhyPartition[k][j]['filename'][0] FileOffset[0] = PhyPartition[k][j]['fileoffset'][0] FilePartitionOffset[0] = PhyPartition[k][j]['filepartitionoffset'][0] FileAppsbin[0] = PhyPartition[k][j]['appsbin'][0] FileSparse[0] = PhyPartition[k][j]['sparse'][0] for z in range(1,len(PhyPartition[k][j]['filename'])): FileToProgram.append( PhyPartition[k][j]['filename'][z] ) FileOffset.append( PhyPartition[k][j]['fileoffset'][z] ) FilePartitionOffset.append( PhyPartition[k][j]['filepartitionoffset'][z] ) FileAppsbin.append( PhyPartition[k][j]['appsbin'][z] ) FileSparse.append( PhyPartition[k][j]['sparse'][z] ) #print PhyPartition[k][j]['fileoffset'] #for z in range(len(FileToProgram)): # print "FileToProgram[",z,"]=",FileToProgram[z] # print "FileOffset[",z,"]=",FileOffset[z] # print " " if 'label' in PhyPartition[k][j]: PartitionLabel = PhyPartition[k][j]['label'] for z in range(len(FileToProgram)): #print "===============================%i of %i===========================================" % (z,len(FileToProgram)) #print "File: ",FileToProgram[z] #print "Label: ",FileToProgram[z] #print "FilePartitionOffset[z]=",FilePartitionOffset[z] #print "UpdateRawProgram(RawProgramXML,",(FirstLBA+FilePartitionOffset[z]),",",((LastLBA-FirstLBA)*SECTOR_SIZE_IN_BYTES/1024.0),",",PhysicalPartitionNumber,",",FileOffset[z],",",(LastLBA-FirstLBA-FilePartitionOffset[z]),",",(FileToProgram[z]),",", PartitionLabel,")" #print "LastLBA=",LastLBA #print "FirstLBA=",FirstLBA #print "FilePartitionOffset[z]=",FilePartitionOffset[z] UpdateRawProgram(RawProgramXML,FirstLBA+FilePartitionOffset[z], ((LastLBA-FirstLBA)+1)*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, FileOffset[z], LastLBA-FirstLBA-FilePartitionOffset[z]+1, FileToProgram[z], FileSparse[z], PartitionLabel) UpdateRawProgram(RawProgramXML_Blank,FirstLBA+FilePartitionOffset[z], ((LastLBA-FirstLBA)+1)*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, FileOffset[z], LastLBA-FirstLBA-FilePartitionOffset[z]+1, "zeros_1sector.bin", "false", PartitionLabel) LastLBA += 1 ## move to the next free sector, also, 0 to 9 inclusive means it's 10 ## so below (LastLBA-FirstLBA) must = 10 FirstLBA = LastLBA # getting ready for next partition, FirstLBA is now where we left off ## Still working on *this* PHY partition ## making protective MBR, all zeros in buffer up until 0x1BE i = 0x1BE PrimaryGPT[i+0] = 0x00 # not bootable PrimaryGPT[i+1] = 0x00 # head PrimaryGPT[i+2] = 0x01 # sector PrimaryGPT[i+3] = 0x00 # cylinder PrimaryGPT[i+4] = 0xEE # type PrimaryGPT[i+5] = 0xFF # head PrimaryGPT[i+6] = 0xFF # sector PrimaryGPT[i+7] = 0xFF # cylinder PrimaryGPT[i+8:i+8+4] = [0x01,0x00,0x00,0x00] # starting sector PrimaryGPT[i+12:i+12+4] = [0xFF,0xFF,0xFF,0xFF] # starting sector PrimaryGPT[440] = (HashInstructions['DISK_SIGNATURE']>>24)&0xFF PrimaryGPT[441] = (HashInstructions['DISK_SIGNATURE']>>16)&0xFF PrimaryGPT[442] = (HashInstructions['DISK_SIGNATURE']>>8)&0xFF PrimaryGPT[443] = (HashInstructions['DISK_SIGNATURE'])&0xFF PrimaryGPT[510:512] = [0x55,0xAA] # magic byte for MBR partitioning - always at this location regardless of SECTOR_SIZE_IN_BYTES i = SECTOR_SIZE_IN_BYTES ## Signature and Revision and HeaderSize i.e. "EFI PART" and 00 00 01 00 and 5C 00 00 00 PrimaryGPT[i:i+16] = [0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54, 0x00, 0x00, 0x01, 0x00, 0x5C, 0x00, 0x00, 0x00] ; i+=16 PrimaryGPT[i:i+4] = [0x00, 0x00, 0x00, 0x00] ; i+=4 ## CRC is zeroed out till calculated later PrimaryGPT[i:i+4] = [0x00, 0x00, 0x00, 0x00] ; i+=4 ## Reserved, set to 0 CurrentLBA= 1 ; i = UpdatePrimaryGPT(CurrentLBA,8,i) BackupLBA = 0 ; i = UpdatePrimaryGPT(BackupLBA,8,i) FirstLBA = 34 ; i = UpdatePrimaryGPT(FirstLBA,8,i) LastLBA = 0 ; i = UpdatePrimaryGPT(LastLBA,8,i) ##print "\n\nBackup GPT is at sector %i" % BackupLBA ##print "Last Usable LBA is at sector %i" % (LastLBA) DiskGUID = 0x4BFA5EA0886429854DAC4B1C1ED28A1F DiskGUID = 0x200C003DB32B6EA04BF2BBE298101B32 i = UpdatePrimaryGPT(DiskGUID,16,i) PartitionsLBA = 2 ; i = UpdatePrimaryGPT(PartitionsLBA,8,i) NumPartitions = 4*int(len(PhyPartition[k])/4) # Want a multiple of 4 to fill the sector (avoids gdisk warning) if (len(PhyPartition[k])%4)>0: NumPartitions+=4 if force128partitions == 1: print "\n\nGPT table will list 128 partitions instead of ",NumPartitions print "This makes the output compatible with some older test utilities" NumPartitions = 128 i = UpdatePrimaryGPT(NumPartitions,4,i) ## (offset 80) Number of partition entries ##NumPartitions = 8 ; i = UpdatePrimaryGPT(NumPartitions,4,i) ## (offset 80) Number of partition entries SizeOfPartitionArray = 128 ; i = UpdatePrimaryGPT(SizeOfPartitionArray,4,i) ## (offset 84) Size of partition entries ## Now I can calculate the partitions CRC ##PartitionsCRC = CalcCRC32(PrimaryGPT[1024:],32*512) ##print "\n\nCalculating CRC with NumPartitions=%i, SizeOfPartitionArray=%i TOTAL LENGTH %d" % (NumPartitions,SizeOfPartitionArray,NumPartitions*SizeOfPartitionArray); PartitionsCRC = CalcCRC32(PrimaryGPT[1024:],NumPartitions*SizeOfPartitionArray) ## Each partition entry is 128 bytes i = UpdatePrimaryGPT(PartitionsCRC,4,i) #print "\n\nCalculated PARTITION CRC is 0x%.8X" % PartitionsCRC ## gpt patch - main gpt header - last useable lba ByteOffset = str(48) StartSector = str(1) BackupStartSector = str(32) UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-34.",os.path.basename(GPTMAIN), "Update Primary Header with LastUseableLBA.") UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-34.","DISK", "Update Primary Header with LastUseableLBA.") UpdatePatch(BackupStartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-34.",os.path.basename(GPTBACKUP), "Update Backup Header with LastUseableLBA.") UpdatePatch("NUM_DISK_SECTORS-1.",ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-34.","DISK", "Update Backup Header with LastUseableLBA.") # gpt patch - location of backup gpt header ########################################## ByteOffset = str(32) StartSector = str(1) ## gpt patch - main gpt header UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-1.",os.path.basename(GPTMAIN), "Update Primary Header with BackupGPT Header Location.") UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-1.","DISK", "Update Primary Header with BackupGPT Header Location.") # gpt patch - currentLBA backup header ########################################## ByteOffset = str(24) BackupStartSector = str(32) ## gpt patch - main gpt header UpdatePatch(BackupStartSector, ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-1.",os.path.basename(GPTBACKUP), "Update Backup Header with CurrentLBA.") UpdatePatch("NUM_DISK_SECTORS-1.",ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-1.","DISK", "Update Backup Header with CurrentLBA.") # gpt patch - location of backup gpt header ########################################## ByteOffset = str(72) BackupStartSector = str(32) ## gpt patch - main gpt header UpdatePatch(BackupStartSector, ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-33.",os.path.basename(GPTBACKUP), "Update Backup Header with Partition Array Location.") UpdatePatch("NUM_DISK_SECTORS-1",ByteOffset,PhysicalPartitionNumber,8,"NUM_DISK_SECTORS-33.","DISK", "Update Backup Header with Partition Array Location.") # gpt patch - Partition Array CRC ################################################ ByteOffset = str(88) StartSector = str(1) BackupStartSector = str(32) ## gpt patch - main gpt header 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) UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"CRC32(2,%d)" % (NumPartitions*SizeOfPartitionArray),"DISK", "Update Primary Header with CRC of Partition Array.") # CRC32(start_sector:num_bytes) ## gpt patch - backup gpt header 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) UpdatePatch("NUM_DISK_SECTORS-1.",ByteOffset,PhysicalPartitionNumber,4,"CRC32(NUM_DISK_SECTORS-33.,%d)" % (NumPartitions*SizeOfPartitionArray),"DISK", "Update Backup Header with CRC of Partition Array.") # CRC32(start_sector:num_bytes) #print "\nNeed to patch PARTITION ARRAY, @ sector 1, byte offset 88, size=4 bytes, CRC32(2,33)" #print "\nNeed to patch PARTITION ARRAY, @ sector -1, byte offset 88, size=4 bytes, CRC32(2,33)" ## Now I can calculate the Header CRC ##print "\nCalculating CRC for Primary Header" CalcHeaderCRC = CalcCRC32(PrimaryGPT[SECTOR_SIZE_IN_BYTES:],92) UpdatePrimaryGPT(CalcHeaderCRC,4,SECTOR_SIZE_IN_BYTES+16) #print "\n\nCalculated HEADER CRC is 0x%.8X" % CalcHeaderCRC #print "\nNeed to patch GPT HEADERS in 2 places" #print "\nNeed to patch CRC HEADER, @ sector 1, byte offset 16, size=4 bytes, CRC32(1,1)" #print "\nNeed to patch CRC HEADER, @ sector -1, byte offset 16, size=4 bytes, CRC32(1,1)" # gpt patch - Header CRC ################################################ ByteOffset = str(16) StartSector = str(1) BackupStartSector = str(32) ## gpt patch - main gpt header UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"0",os.path.basename(GPTMAIN), "Zero Out Header CRC in Primary Header.") # zero out old CRC first 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) UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"0", "DISK", "Zero Out Header CRC in Primary Header.") # zero out old CRC first UpdatePatch(StartSector,ByteOffset,PhysicalPartitionNumber,4,"CRC32(1,92)","DISK", "Update Primary Header with CRC of Primary Header.") # CRC32(start_sector:num_bytes) ## gpt patch - backup gpt header UpdatePatch(BackupStartSector,ByteOffset,PhysicalPartitionNumber,4,"0",os.path.basename(GPTBACKUP), "Zero Out Header CRC in Backup Header.") # zero out old CRC first UpdatePatch(BackupStartSector,ByteOffset,PhysicalPartitionNumber,4,"CRC32(32,92)",os.path.basename(GPTBACKUP), "Update Backup Header with CRC of Backup Header.") # CRC32(start_sector:num_bytes) UpdatePatch("NUM_DISK_SECTORS-1.",ByteOffset,PhysicalPartitionNumber,4,"0", "DISK", "Zero Out Header CRC in Backup Header.") # zero out old CRC first 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) ## now create the backup GPT partitions BackupGPT = [0xFF]*(33*SECTOR_SIZE_IN_BYTES) BackupGPT[0:] = PrimaryGPT[2*SECTOR_SIZE_IN_BYTES:] ## now create the backup GPT header BackupGPT[32*SECTOR_SIZE_IN_BYTES:33*SECTOR_SIZE_IN_BYTES]= PrimaryGPT[1*SECTOR_SIZE_IN_BYTES:2*SECTOR_SIZE_IN_BYTES] #ShowBackupGPT(32) ## Need to update CurrentLBA, BackupLBA and then recalc CRC for this header i = 32*SECTOR_SIZE_IN_BYTES+8+4+4 CalcHeaderCRC = 0 ; i = UpdateBackupGPT(CalcHeaderCRC,4,i) ## zero out CRC CalcHeaderCRC = 0 ; i = UpdateBackupGPT(CalcHeaderCRC,4,i) ## reserved 4 zeros CurrentLBA = 0 ; i = UpdateBackupGPT(CurrentLBA,8,i) BackupLBA = 1 ; i = UpdateBackupGPT(BackupLBA,8,i) #print "\n\nBackup GPT is at sector %i" % CurrentLBA #print "Last Usable LBA is at sector %i" % (CurrentLBA-33) i += 8+8+16 PartitionsLBA = 0 ; i = UpdateBackupGPT(PartitionsLBA,8,i) #print "PartitionsLBA = %d (0x%X)" % (PartitionsLBA,PartitionsLBA) ##print "\nCalculating CRC for Backup Header" CalcHeaderCRC = CalcCRC32(BackupGPT[32*SECTOR_SIZE_IN_BYTES:],92) #print "\nCalcHeaderCRC of BackupGPT is 0x%.8X" % CalcHeaderCRC i = 32*SECTOR_SIZE_IN_BYTES+8+4+4 i = UpdateBackupGPT(CalcHeaderCRC,4,i) ## zero out CRC #ShowBackupGPT(32) UpdateRawProgram(RawProgramXML,0, 34*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0, 34, os.path.basename(GPTMAIN), 'false', 'PrimaryGPT') UpdateRawProgram(RawProgramXML_Blank,0, 1*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0, 1, "zeros_1sector.bin", 'false', 'PrimaryGPT') UpdateRawProgram(RawProgramXML_Blank,1, 33*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0, 33, "zeros_33sectors.bin", 'false', 'PrimaryGPT') #print "szStartSector=%s" % szStartSector UpdateRawProgram(RawProgramXML,-33, 33*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0, 33, os.path.basename(GPTBACKUP), 'false', 'BackupGPT') UpdateRawProgram(RawProgramXML_Blank,-33, 33*SECTOR_SIZE_IN_BYTES/1024.0, PhysicalPartitionNumber, 0, 33, "zeros_33sectors.bin", 'false', 'BackupGPT') ##print "szStartSector=%s" % szStartSector WriteGPT(GPTMAIN, GPTBACKUP) opfile = open(RAW_PROGRAM, "w") opfile.write( prettify(RawProgramXML) ) opfile.close() print "\nCreated \"%s\"\t<-- YOUR partition information is HERE" % RAW_PROGRAM opfile = open(RAW_PROGRAM_BLANK, "w") opfile.write( prettify(RawProgramXML_Blank) ) opfile.close() print "Created \"%s\"\t<-- Wipe out your images with this file (if needed for testing)" % RAW_PROGRAM_BLANK opfile = open(PATCHES, "w") # gpt opfile.write( prettify(PatchesXML) ) opfile.close() print "Created \"%s\"\t\t<-- Tailor your partition tables to YOUR device with this file\n" % PATCHES def AlignVariablesToEqualSigns(sz): temp = re.sub(r"(\t| )+=","=",sz) temp = re.sub(r"=(\t| )+","=",temp) return temp def ReturnArrayFromSpaceSeparatedList(sz): temp = re.sub(r"\s+|\n"," ",sz) temp = re.sub(r"^\s+","",temp) temp = re.sub(r"\s+$","",temp) return temp.split(' ') def ParseXML(XMLFile): global OutputToCreate,NumPhyPartitions, PartitionCollection, PhyPartition,MinSectorsNeeded,SECTOR_SIZE_IN_BYTES root = ET.parse( XMLFile ) #Create an iterator iter = root.getiterator() for element in iter: #print "\nElement:" , element.tag # thins like image,primary,extended etc if element.tag=="parser_instructions": instructions = ReturnArrayFromSpaceSeparatedList(AlignVariablesToEqualSigns(element.text)) for element in instructions: temp = element.split('=') if len(temp) > 1: HashInstructions[temp[0].strip()] = temp[1].strip() #print "HashInstructions['%s'] = %s" % (temp[0].strip(),temp[1].strip()) elif element.tag=="physical_partition": # We can have this scenario meaning NumPhyPartitions++ but len(PhyPartition) doesn't increase # # # Thus if NumPhyPartitions > len(PhyPartition) by 2, then we need to increase it NumPhyPartitions += 1 PartitionCollection = [] # Reset, we've found a new physical partition if NumPhyPartitions-len(PhyPartition)>=2: print "\n\n" print "*"*78 print "ERROR: Empty tags detected\n" print "Please replace with" print "" print "" print "\n" sys.exit() print "\nFound a physical_partition, NumPhyPartitions=%d" % NumPhyPartitions print "\nlen(PhyPartition)=%d" % len(PhyPartition) elif element.tag=="partition" or element.tag=="primary" or element.tag=="extended": if element.keys(): #print "\tAttributes:" # Reset all variables to defaults Partition = {} # This partition could have more than 1 file, so these are arrays # However, as I loop through the elements, *if* there is more than 1 file # it will have it's own tag Partition['filename'] = [""] Partition['fileoffset'] = [0] Partition['appsbin'] = ["false"] Partition['sparse'] = ["false"] Partition['filepartitionoffset'] = [0] Partition['size_in_kb'] = 0 Partition["readonly"] = "false" Partition['label'] = "false" Partition['type'] = "false" Partition['uguid'] = "false" ## unique guid Partition['align'] = "false" Partition['hidden'] = "false" Partition['system'] = "false" Partition['dontautomount'] = "false" if 'PERFORMANCE_BOUNDARY_IN_KB' in HashInstructions: Partition['PERFORMANCE_BOUNDARY_IN_KB'] = int(HashInstructions['PERFORMANCE_BOUNDARY_IN_KB']) else: Partition['PERFORMANCE_BOUNDARY_IN_KB'] = 0 FileFound = 0 print " " for name, value in element.items(): #print "\t\tName: '%s'=>'%s' " % (name,value) if name=='name' or name=='filename' : Partition['filename'][-1] = value FileFound = 1 print "Found a file tag '%s'" % value elif name=='fileoffset': Partition['fileoffset'][-1] = value elif name=='label': Partition['label'] = value print "LABEL:",value elif name=='offset' or name=='filepartitionoffset': Partition['filepartitionoffset'][-1] = int(value) elif name=='appsbin': Partition['appsbin'][-1] = value elif name=='sparse': Partition['sparse'][-1] = value elif name=='PERFORMANCE_BOUNDARY_IN_KB': Partition['PERFORMANCE_BOUNDARY_IN_KB'] = int(value) elif name=='type': if ValidGUIDForm(value) is True: if OutputToCreate is None: OutputToCreate = "gpt" elif OutputToCreate is "mbr": PrintBigError("ERROR: Your partition.xml is possibly corrupt, please check the GUID TYPE field") Partition['type'] = ValidateGUID(value) else: if OutputToCreate is None: OutputToCreate = "mbr" elif OutputToCreate is "gpt": PrintBigError("ERROR: Your partition.xml is possibly corrupt, please check the TYPE field") Partition['type'] = ValidateTYPE(value) elif name=='uniqueguid': if ValidGUIDForm(value) is True: Partition['uguid'] = ValidateGUID(value) else: PrintBigError("ERROR: Your partition.xml is possibly corrupt, please check the TYPE field") elif name=="size": if len(value)==0: PrintBigError("\nERROR: Invalid partition size") Partition["size_in_kb"]=int(value)/2 # force as even number elif name=="size_in_kb": if len(value)==0: PrintBigError("\nERROR: Invalid partition size") Partition["size_in_kb"]=int(value) else: Partition[name]=value # No longer appending blank filename data for Trace32. Programming based on Label now #if FileFound == 1: # Partition['filename'].append("") # Partition['fileoffset'].append(0) # Partition['filepartitionoffset'].append(0) # Partition['appsbin'].append("false") # Partition['sparse'].append("false") ## done with all the elements, now ensure that size matches with size_in_kb Partition["size"] = ConvertKBtoSectors(Partition["size_in_kb"]) # Still 512 bytes/sector here since "size" is a legacy field ## Now add this "Partition" object to the PartitionCollection ## unless it's the label EXT, which is a left over legacy tag if Partition['label'] != 'EXT': #print "\nJust added %s" % Partition['label'] PartitionCollection.append( Partition ) print "="*40 print "storing at %d" % (NumPhyPartitions-1) ##import pdb; pdb.set_trace() print "Adding PartitionCollection to \"PhyPartition\" of size %i" % (NumPhyPartitions-1) PhyPartition[(NumPhyPartitions-1)] = PartitionCollection #print "\nPartition stored (%i partitions total)" % len(PartitionCollection) else: PrintBigError("ERROR: element.tag was partition, primary or extended, but it had no keys!") elif element.tag=="file": #print "element.tag=='file' Found a file, NumPhyPartitions=",NumPhyPartitions ## i.e. just a file tag (usually in legacy) #print PhyPartition[(NumPhyPartitions-1)] #print "Current partition is \"%s\"\n" % Partition['label'] if element.keys(): for name, value in element.items(): if name=='name' or name=='filename' : Partition['filename'][-1] = value if name=='fileoffset': Partition['fileoffset'][-1] = value if name=='offset' or name=='filepartitionoffset': Partition['filepartitionoffset'][-1] = int(value) if name=='appsbin': Partition['appsbin'][-1] = value if name=='sparse': Partition['sparse'][-1] = value #Partition[name]=value #print Partition['filename'] Partition['filename'].append("") Partition['fileoffset'].append(0) Partition['filepartitionoffset'].append(0) Partition['appsbin'].append("false") Partition['sparse'].append("false") #try: # if len(Partition['filename'])>1: # print "="*78 # print "="*78 # for z in range(len(Partition['filename'])): # print "Partition['filename'][",z,"]=",Partition['filename'][z] # print "Partition['fileoffset'][",z,"]=",Partition['fileoffset'][z] # print "Partition['filepartitionoffset'][",z,"]=",Partition['filepartitionoffset'][z] # print "Partition['appsbin'][",z,"]=",Partition['appsbin'][z] # print "Partition['sparse'][",z,"]=",Partition['sparse'][z] # print "-"*78 # print "="*78 #except: # print " " #print "Showing the changes to PartitionCollection" #print PartitionCollection[-1] if 'WRITE_PROTECT_BOUNDARY_IN_KB' in HashInstructions: if type(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']) is str: m = re.search("^(\d+)$", HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']) if type(m) is NoneType: ## we didn't match, so assign deafult HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] = 0 else: HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] = int(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']) else: #print "WRITE_PROTECT_BOUNDARY_IN_KB does not exist" HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] = 65536 if 'SECTOR_SIZE_IN_BYTES' in HashInstructions: if type(HashInstructions['SECTOR_SIZE_IN_BYTES']) is str: m = re.search("^(\d+)$", HashInstructions['SECTOR_SIZE_IN_BYTES']) if type(m) is NoneType: ## we didn't match, so assign deafult HashInstructions['SECTOR_SIZE_IN_BYTES'] = 512 SECTOR_SIZE_IN_BYTES = 512 else: HashInstructions['SECTOR_SIZE_IN_BYTES'] = int(HashInstructions['SECTOR_SIZE_IN_BYTES']) SECTOR_SIZE_IN_BYTES = HashInstructions['SECTOR_SIZE_IN_BYTES'] PrintBigWarning("WARNING: SECTOR_SIZE_IN_BYTES CHANGED <-- This may impact your targets ability to read the partition tables!!") print "\n\nWARNING: SECTOR_SIZE_IN_BYTES *changed* from 512bytes/sector to %ibytes/sector" % SECTOR_SIZE_IN_BYTES print "WARNING: SECTOR_SIZE_IN_BYTES *changed* from 512bytes/sector to %ibytes/sector" % SECTOR_SIZE_IN_BYTES print "WARNING: SECTOR_SIZE_IN_BYTES *changed* from 512bytes/sector to %ibytes/sector\n\n" % SECTOR_SIZE_IN_BYTES sleep(2) else: #print "SECTOR_SIZE_IN_BYTES does not exist" HashInstructions['SECTOR_SIZE_IN_BYTES'] = 512 if 'PERFORMANCE_BOUNDARY_IN_KB' in HashInstructions: if type(HashInstructions['PERFORMANCE_BOUNDARY_IN_KB']) is str: m = re.search("^(\d+)$", HashInstructions['PERFORMANCE_BOUNDARY_IN_KB']) if type(m) is NoneType: ## we didn't match, so assign deafult HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'] = 0 else: HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'] = int(HashInstructions['PERFORMANCE_BOUNDARY_IN_KB']) else: #print "PERFORMANCE_BOUNDARY_IN_KB does not exist" HashInstructions['PERFORMANCE_BOUNDARY_IN_KB'] = 0 if 'GROW_LAST_PARTITION_TO_FILL_DISK' in HashInstructions: if type(HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']) is str: m = re.search("^(true)$", HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] ,re.IGNORECASE) #print type(m) if type(m) is NoneType: HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = False # no match #print "assigned false" else: HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = True # matched string true #print "assigned true" else: HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = False if 'WRITE_PROTECT_GPT_PARTITION_TABLE' in HashInstructions: if type(HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE']) is str: m = re.search("^(true)$", HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] ,re.IGNORECASE) #print type(m) if type(m) is NoneType: HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] = False # no match #print "assigned false" else: HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] = True # matched string true #print "assigned true" else: HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] = False if 'ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY' in HashInstructions: if type(HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY']) is str: m = re.search("^(true)$", HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] ,re.IGNORECASE) #print type(m) if type(m) is NoneType: HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] = False # no match #print "assigned false" else: HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] = True # matched string true #print "assigned true" else: HashInstructions['ALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY'] = False if 'USE_GPT_PARTITIONING' in HashInstructions: if type(HashInstructions['USE_GPT_PARTITIONING']) is str: m = re.search("^(true)$", HashInstructions['USE_GPT_PARTITIONING'] ,re.IGNORECASE) #print type(m) if type(m) is NoneType: HashInstructions['USE_GPT_PARTITIONING'] = False # no match #print "assigned false" else: HashInstructions['USE_GPT_PARTITIONING'] = True # matched string true #print "assigned true" else: HashInstructions['USE_GPT_PARTITIONING'] = False if 'DISK_SIGNATURE' in HashInstructions: if type(HashInstructions['DISK_SIGNATURE']) is str: m = re.search("^0x([\da-fA-F]+)$", HashInstructions['DISK_SIGNATURE']) if type(m) is NoneType: print "WARNING: DISK_SIGNATURE is not formed correctly, expected format is 0x12345678\n" HashInstructions['DISK_SIGNATURE'] = 0x00000000 else: HashInstructions['DISK_SIGNATURE'] = int(HashInstructions['DISK_SIGNATURE'],16) else: print "DISK_SIGNATURE does not exist" HashInstructions['DISK_SIGNATURE'] = 0x00000000 if 'ALIGN_BOUNDARY_IN_KB' in HashInstructions: if type(HashInstructions['ALIGN_BOUNDARY_IN_KB']) is str: m = re.search("^(\d+)$", HashInstructions['ALIGN_BOUNDARY_IN_KB']) if type(m) is NoneType: ## we didn't match, so assign deafult HashInstructions['ALIGN_BOUNDARY_IN_KB'] = HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] else: HashInstructions['ALIGN_BOUNDARY_IN_KB'] = int(HashInstructions['ALIGN_BOUNDARY_IN_KB']) else: #print "ALIGN_BOUNDARY_IN_KB does not exist" HashInstructions['ALIGN_BOUNDARY_IN_KB'] = HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] # Must update this if the user has updated WRITE_PROTECT_BOUNDARY_IN_KB in partition.xml hash_w[NumWPregions]['num_sectors'] = (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES) hash_w[NumWPregions]['end_sector'] = (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES)-1 if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] == 0: hash_w[NumWPregions]['num_sectors'] = 0 hash_w[NumWPregions]['end_sector'] = 0 hash_w[NumWPregions]['num_boundaries_covered'] = 0 if OutputToCreate is "gpt" and HashInstructions['WRITE_PROTECT_GPT_PARTITION_TABLE'] is False: hash_w[NumWPregions]['num_sectors'] = 0 hash_w[NumWPregions]['end_sector'] = 0 hash_w[NumWPregions]['num_boundaries_covered'] = 0 print "HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] =%d" % HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] print "HashInstructions['ALIGN_BOUNDARY_IN_KB'] =%d" % HashInstructions['ALIGN_BOUNDARY_IN_KB'] print "HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']=%s" % HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] print "HashInstructions['DISK_SIGNATURE']=0x%X" % HashInstructions['DISK_SIGNATURE'] #for j in range(len(PhyPartition)): #for j in range(1): # print "\n\nPhyPartition[%d] ========================================================= " % (j) # PrintPartitionCollection( PhyPartition[j] ) print "len(PhyPartition)=",len(PhyPartition) if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==False: ## to be here means we're *not* growing final partition, thereore, obey the sizes they've specified for j in range(len(PhyPartition)): TempNumPartitions = len(PhyPartition[j]) if TempNumPartitions>4: MinSectorsNeeded = 1 + (TempNumPartitions-3) # need MBR + TempNumPartitions-3 EBRs else: MinSectorsNeeded = 1 # need MBR only for Partition in PhyPartition[j]: print "LABEL: '%s' with %d sectors " % (Partition['label'],ConvertKBtoSectors(Partition["size_in_kb"])) MinSectorsNeeded += ConvertKBtoSectors(Partition["size_in_kb"]) #print "LABEL '%s' with size %d sectors" % (Partition['label'],Partition['size_in_kb']/2) print "MinSectorsNeeded=%d" % MinSectorsNeeded #sys.exit() # if OutputToCreate is 'gpt': PrintBanner("GPT GUID discovered in XML file, Output will be GPT") if OutputToCreate is 'mbr': PrintBanner("MBR type discovered in XML file, Output will be MBR") # PrintPartitionCollection( PhyPartition[0] ) def PrintPartitionCollection(PartitionCollection): #print PartitionCollection for Partition in PartitionCollection: print Partition print " " for key in Partition: print key,"\t=>\t",Partition[key] #for j in range(NumMBRPartitions): def ParseCommandLine(): global XMLFile,OutputToCreate,PhysicalPartitionNumber print "\nArgs" for i in range(len(sys.argv)): print "sys.argv[%d]=%s" % (i,sys.argv[i]) print " " XMLFile = sys.argv[1]; if len(sys.argv) >= 3: m = re.search("mbr|gpt", sys.argv[2] ) if type(m) is not NoneType: OutputToCreate = sys.argv[2] else: print "Unrecognized option '%s', only 'mbr' or 'gpt' expected" % sys.argv[2] else: print "\nUser *did* not explicitly specify partition table format (i.e. mbr|gpt)" print "\nWill AUTO-DETECT from file" if len(sys.argv) >= 4: # Should mean PHY partition was specified m = re.search("^\d+$", sys.argv[3] ) if type(m) is not NoneType: PhysicalPartitionNumber = int(sys.argv[3]) print "PhysicalPartitionNumber specified as %d" % PhysicalPartitionNumber else: PrintBigError("ERROR: PhysicalPartitionNumber of disk must only contain numbers, '%s' is not valid" % sys.argv[3]) print " " # Updates the WriteProtect hash that is used in creating emmc_lock_regions.xml def UpdateWPhash(Start,Size): global hash_w,NumWPregions if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']==0: return #print "\nUpdateWPhash(%i,%i) and currently NumWPregions=%i" % (Start,Size,NumWPregions) #print "hash_w[%i]['start_sector']=%i" % (NumWPregions,hash_w[NumWPregions]["start_sector"]) #print "hash_w[%i]['end_sector']=%i" % (NumWPregions,hash_w[NumWPregions]["end_sector"]) #print "hash_w[%i]['num_sectors']=%i" % (NumWPregions,hash_w[NumWPregions]["num_sectors"]) if Start-1 <= hash_w[NumWPregions]["end_sector"]: #print "\n\tCurrent Write Protect region already covers the start of this partition (start=%i)" % hash_w[NumWPregions]["start_sector"] if (Start + Size - 1) > hash_w[NumWPregions]["end_sector"]: 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,) while (Start + Size - 1) > hash_w[NumWPregions]["end_sector"]: hash_w[NumWPregions]["num_sectors"] += (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES); hash_w[NumWPregions]["end_sector"] += (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES); if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0: hash_w[NumWPregions]["num_boundaries_covered"] = hash_w[NumWPregions]["num_sectors"] / (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES) else: hash_w[NumWPregions]["num_boundaries_covered"] = 0 print "\t\tend_sector increased to %i sectors" % hash_w[NumWPregions]["end_sector"] print "\t\tnum_sectors increased to %i sectors" % hash_w[NumWPregions]["num_sectors"] #print "\n\tCurrent Write Protect region covers this partition (num_sectors=%i)\n" % hash_w[NumWPregions]["num_sectors"] else: print "\n\tNew write protect region needed" #print "\tStart-1\t\t\t\t=%i" % (Start-1) #print "\tLAST hash_w[NumWPregions][end_sector]=%i\n" % hash_w[NumWPregions]["end_sector"] NumWPregions+=1; 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} ) hash_w[NumWPregions]["boundary_num"] = Start / (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES) while (Start + Size - 1) > hash_w[NumWPregions]["end_sector"]: #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"]) hash_w[NumWPregions]["num_sectors"] += (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES); hash_w[NumWPregions]["end_sector"] += (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES); #print "\t\tend_sector increased to %i sectors" % hash_w[NumWPregions]["end_sector"] #print "\t\tnum_sectors increased to %i sectors" % hash_w[NumWPregions]["num_sectors"] hash_w[NumWPregions]["num_boundaries_covered"] = hash_w[NumWPregions]["num_sectors"] / (HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']*1024/SECTOR_SIZE_IN_BYTES) print "\t\tstart_sector = %i sectors" % hash_w[NumWPregions]["start_sector"] print "\t\tend_sector = %i sectors" % hash_w[NumWPregions]["end_sector"] print "\t\tnum_sectors = %i sectors\n" % hash_w[NumWPregions]["num_sectors"] # A8h reflected is 15h, i.e. 10101000 <--> 00010101 def reflect(data,nBits): reflection = 0x00000000 bit = 0 for bit in range(nBits): if(data & 0x01): reflection |= (1 << ((nBits - 1) - bit)) data = (data >> 1); return reflection def CalcCRC32(array,Len): k = 8; # length of unit (i.e. byte) MSB = 0; gx = 0x04C11DB7; # IEEE 32bit polynomial regs = 0xFFFFFFFF; # init to all ones regsMask = 0xFFFFFFFF; # ensure only 32 bit answer ##print "Calculating CRC over byte length of %i" % Len for i in range(Len): DataByte = array[i] DataByte = reflect( DataByte, 8 ); for j in range(k): MSB = DataByte>>(k-1) ## get MSB MSB &= 1 ## ensure just 1 bit regsMSB = (regs>>31) & 1 regs = regs<<1 ## shift regs for CRC-CCITT if regsMSB ^ MSB: ## MSB is a 1 regs = regs ^ gx ## XOR with generator poly regs = regs & regsMask; ## Mask off excess upper bits DataByte <<= 1 ## get to next bit regs = regs & regsMask ## Mask off excess upper bits ReflectedRegs = reflect(regs,32) ^ 0xFFFFFFFF; #print "CRC is 0x%.8X\n" % ReflectedRegs return ReflectedRegs def ReturnLow32bits(var): return var & 0xFFFFFFFF def ReturnHigh32bits(var): return (var>>32) & 0xFFFFFFFF def PrintBanner(sz): print "\n"+"="*78 print sz print "="*78+"\n" def ShowUsage(): PrintBanner("Basic Usage") print "python ptool.py -x partition.xml" PrintBanner("Advanced Usage") print "%-44s\t\tpython ptool.py -x partition.xml" % ("Basic Usage") print "%-44s\t\tpython ptool.py -x partition.xml -s c:\windows" % ("Search path to find partition.xml") print "%-44s\tpython ptool.py -x partition.xml -p 0" % ("Specify PHY Partition 0, (creates rawprogram0.xml)") print "%-44s\tpython ptool.py -x partition.xml -p 1" % ("Specify PHY Partition 1, (creates rawprogram1.xml)") print "%-44s\tpython ptool.py -x partition.xml -p 2" % ("Specify PHY Partition 2, (creates rawprogram2.xml)") print "%-44s\t\tpython ptool.py -x partition.xml -v" % ("Verbose output") print "%-44s\t\tpython ptool.py -x partition.xml -t c:\\temp" % ("Specify place to put output") def CreateFinalPartitionBin(): global OutputFolder opfile = open("%spartition.bin" % OutputFolder, "wb") for i in range(3): FileName = "%spartition%i.bin" % (OutputFolder,i); size = 0 if os.path.isfile(FileName): size = os.path.getsize(FileName) ipfile = open(FileName, "rb") temp = ipfile.read() opfile.write(temp) ipfile.close() if size < 8192: MyArray = [0]*(8192-size) for b in MyArray: opfile.write(struct.pack("B", b)) opfile.close() def prettify(elem): """Return a pretty-printed XML string for the Element. """ rough_string = ET.tostring(elem, 'utf-8') reparsed = minidom.parseString(rough_string) return reparsed.toprettyxml(indent=" ") def UpdatePartitionTable(Bootable,Type,StartSector,Size,Offset,Record): #print "Size = %i" % Size if Bootable=="true": Bootable = 0x80 else: Bootable = 0x00 Type = ValidateTYPE(Type) #print "\tAt Offset=0x%.4X (%d) (%d bytes left)" % (Offset,Offset,len(Record)-Offset) Record[Offset] = Bootable ; Offset+=1 Record[Offset:Offset+3]= [0,0,0] ; Offset+=3 Record[Offset] = Type ; Offset+=1 Record[Offset:Offset+3]= [0,0,0] ; Offset+=3 # First StartSector for b in range(4): Record[Offset] = ((StartSector>>(b*8)) & 0xFF) ; Offset+=1 # First StartSector for b in range(4): Record[Offset] = ((Size>>(b*8)) & 0xFF) ; Offset+=1 #print "\t\tBoot:0x%.2X, ID:0x%.2X, 0x%.8X, 0x%.8X (%.2fMB)" % (Bootable,Type,StartSector,Size,Size/2048.0) return Record # This function called first, then calls CreateMasterBootRecord and CreateExtendedBootRecords def CreateMBRPartitionTable(PhysicalPartitionNumber): global PhyPartition,opfile,RawProgramXML,HashInstructions,ExtendedPartitionBegins,MBR,PARTITIONBIN, MBRBIN, EBRBIN, PATCHES, RAW_PROGRAM k = PhysicalPartitionNumber if(k>=len(PhyPartition)): print "PHY Partition %i of %i not found" % (k,len(PhyPartition)) sys.exit() NumPartitions = len(PhyPartition[k]) print "\n\nOn PHY Partition %d that has %d partitions" % (k,NumPartitions) print "\n------------\n" print "\nFor PHY Partition %i" % k if(NumPartitions<=4): print "\tWe can get away with only an MBR"; CreateMasterBootRecord(k, NumPartitions ) else: print "\tWe will need an MBR and %d EBRs" % (NumPartitions-3) CreateMasterBootRecord(k, 3 ) ## Now the EXTENDED PARTITION print "\nAbout to make EBR, FirstLBA=%i, LastLBA=%i" % (FirstLBA,LastLBA) CreateExtendedBootRecords(k,NumPartitions-3) PARTITIONBIN = '%spartition%i.bin' % (OutputFolder,k) MBRBIN = '%sMBR%i.bin' % (OutputFolder,k) EBRBIN = '%sEBR%i.bin' % (OutputFolder,k) PATCHES = '%spatch%i.xml' % (OutputFolder,k) RAW_PROGRAM = '%srawprogram%i.xml' % (OutputFolder,k) UpdateRawProgram(RawProgramXML,0, 1*SECTOR_SIZE_IN_BYTES/1024.0, k, 0, 1, MBRBIN, 'false', 'MBR') if(NumPartitions>4): ## There was more than 4 partitions, so EXT partition had to be used UpdateRawProgram(RawProgramXML,ExtendedPartitionBegins, (NumPartitions-3)*SECTOR_SIZE_IN_BYTES/1024.0, k, 0, NumPartitions-3, EBRBIN, 'false', 'EXT') # note file offset is 0 print "\nptool.py is running from CWD: ", os.getcwd(), "\n" opfile = open(PARTITIONBIN, "wb") WriteMBR() WriteEBR() opfile.close() print "Created \"%s\"" % PARTITIONBIN opfile = open(MBRBIN, "wb") WriteMBR() opfile.close() print "Created \"%s\"" % MBRBIN opfile = open(EBRBIN, "wb") WriteEBR() opfile.close() print "Created \"%s\"" % EBRBIN opfile = open(RAW_PROGRAM, "w") opfile.write( prettify(RawProgramXML) ) opfile.close() print "Created \"%s\"" % RAW_PROGRAM opfile = open(PATCHES, "w") opfile.write( prettify(PatchesXML) ) opfile.close() print "Created \"%s\"" % PATCHES for mydict in hash_w: #print mydict SubElement(EmmcLockRegionsXML, 'program', {'start_sector':"%X" % mydict['start_sector'],'start_sector_dec':str(mydict['start_sector']), 'num_sectors':"%X" % mydict['num_sectors'],'num_sectors_dec':str(mydict['num_sectors']), 'boundary_num':str(mydict['boundary_num']), 'num_boundaries_covered':str(mydict['num_boundaries_covered']), 'physical_partition_number':str(mydict['physical_partition_number']) }) SubElement(EmmcLockRegionsXML, 'information', {'WRITE_PROTECT_BOUNDARY_IN_KB':str(HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']) }) opfile = open("%semmc_lock_regions.xml" % OutputFolder, "w") opfile.write( prettify(EmmcLockRegionsXML) ) opfile.close() print "Created \"%semmc_lock_regions.xml\"" % OutputFolder print "\nUse msp tool to write this information to SD/eMMC card" print "\ti.e." if sys.platform.startswith("linux"): print "\tsudo python msp.py rawprogram0.xml /dev/sdb <---- where /dev/sdb is assumed to be your SD/eMMC card" print "\tsudo python msp.py patch0.xml /dev/sdb <---- where /dev/sdb is assumed to be your SD/eMMC card\n\n" else: print "\tpython msp.py rawprogram0.xml \\\\.\\PHYSICALDRIVE2 <---- where \\\\.\\PHYSICALDRIVE2 is" print "\tpython msp.py patch0.xml \\\\.\\PHYSICALDRIVE2 <---- assumed to be your SD/eMMC card\n\n" # CreateMasterBootRecord(k,len(PhyPartition[k]) ) def CreateMasterBootRecord(k,NumMBRPartitions): global PhyPartition,HashInstructions,MBR,FirstLBA,LastLBA print "\nInside CreateMasterBootRecord(%d) -------------------------------------" % NumMBRPartitions MBR = [0]*SECTOR_SIZE_IN_BYTES MBR[440] = (HashInstructions['DISK_SIGNATURE']>>24)&0xFF MBR[441] = (HashInstructions['DISK_SIGNATURE']>>16)&0xFF MBR[442] = (HashInstructions['DISK_SIGNATURE']>>8)&0xFF MBR[443] = (HashInstructions['DISK_SIGNATURE'])&0xFF MBR[510:512] = [0x55,0xAA] # magic byte for MBR partitioning - always at this location regardless of SECTOR_SIZE_IN_BYTES ## These two values used like so 'num_sectors':str(LastLBA-FirstLBA) FirstLBA = 1 ## the MBR is at 0, Partition 1 is at 1 LastLBA = 1 PartitionSectorSize = 0 #print "\nOn PHY Partition %d that has %d partitions" % (k,len(PhyPartition[k])) for j in range(NumMBRPartitions): # typically this is 0,1,2 ## ALL MBR partitions are marked as read-only PhyPartition[k][j]['readonly'] = "true" PartitionSectorSize = ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb']) # in sector form, i.e. 1KB = 2 sectors 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'])) # Is this sector aligned? if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0: AlignedRemainder = FirstLBA % HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']; if AlignedRemainder==0: 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']))) # are we on the very last partition, i.e. did user only specify 3 or less partitions? if (j+1) == len(PhyPartition[k]): print "\nTHIS IS THE LAST PARTITION" print "HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = %s" % HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==True: SectorOffsetPatchBefore = 0 SectorOffsetPatchAfter = 0 ByteOffset = 0x1CA+j*16 UpdatePatch(str(SectorOffsetPatchBefore),str(ByteOffset),k,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA),"partition%d.bin" % k, "Update last partition with actual size.") UpdatePatch(str(SectorOffsetPatchBefore),str(ByteOffset),k,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA),"MBR%d.bin" % k, "Update last partition with actual size.") UpdatePatch(str(SectorOffsetPatchAfter), str(ByteOffset),k,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA),"DISK", "Update 'Update last partition with actual size.") # Update the Write-Protect hash if PhyPartition[k][j]['readonly']=="true": UpdateWPhash(FirstLBA, PartitionSectorSize) LastLBA += PartitionSectorSize ## increase by num sectors, LastLBA inclusive, so add 1 for size ## Default for each partition is no file FileToProgram = [""] FileOffset = [0] FilePartitionOffset = [0] FileAppsbin = ["false"] FileSparse = ["false"] if 'filename' in PhyPartition[k][j]: ##print "filename exists" #print PhyPartition[k][j]['filename'] #print FileToProgram[0] FileToProgram[0] = PhyPartition[k][j]['filename'][0] FileOffset[0] = PhyPartition[k][j]['fileoffset'][0] FilePartitionOffset[0] = PhyPartition[k][j]['filepartitionoffset'][0] FileAppsbin[0] = PhyPartition[k][j]['appsbin'][0] FileSparse[0] = PhyPartition[k][j]['sparse'][0] for z in range(1,len(PhyPartition[k][j]['filename'])): FileToProgram.append( PhyPartition[k][j]['filename'][z] ) FileOffset.append( PhyPartition[k][j]['fileoffset'][z] ) FilePartitionOffset.append( PhyPartition[k][j]['filepartitionoffset'][z] ) FileAppsbin.append( PhyPartition[k][j]['appsbin'][z] ) FileSparse.append( PhyPartition[k][j]['sparse'][z] ) #print PhyPartition[k][j]['fileoffset'] #for z in range(len(FileToProgram)): # print "FileToProgram[",z,"]=",FileToProgram[z] # print "FileOffset[",z,"]=",FileOffset[z] # print " " PartitionLabel = "" Type = "" Bootable = "false" ## Now update with the real values if 'label' in PhyPartition[k][j]: PartitionLabel = PhyPartition[k][j]['label'] if 'type' in PhyPartition[k][j]: Type = PhyPartition[k][j]['type'] if 'bootable' in PhyPartition[k][j]: Bootable = PhyPartition[k][j]['bootable'] ## Now it is time to update the partition table offset = 0x1BE + (j*16) MBR = UpdatePartitionTable(Bootable,Type,FirstLBA,PartitionSectorSize,offset,MBR) for z in range(len(FileToProgram)): #print "File: ",FileToProgram[z] #print "FilePartitionOffset[z]=",FilePartitionOffset[z] UpdateRawProgram(RawProgramXML, FirstLBA+FilePartitionOffset[z], PartitionSectorSize*SECTOR_SIZE_IN_BYTES/1024.0, k, FileOffset[z], PartitionSectorSize-FilePartitionOffset[z], FileToProgram[z], FileSparse[z], PartitionLabel) FirstLBA = LastLBA # getting ready for next partition, FirstLBA is now where we left off # CreateExtendedBootRecords(k,len(PhyPartition[k])-3) def CreateExtendedBootRecords(k,NumEBRPartitions): global PhyPartition,HashInstructions,MBR,EBR,FirstLBA,LastLBA,ExtendedPartitionBegins print "\nInside CreateExtendedBootRecords(%d) -----------------------------------------" % NumEBRPartitions ## Step 1 is to update the MBR with the size of the EXT partition ## in which logical partitions will be created EBROffset = 0 print "EBROffset=",EBROffset ExtendedPartitionBegins = FirstLBA if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==True: print "Extended Partition begins at FirstLBA=%i\n" % (ExtendedPartitionBegins) MBR=UpdatePartitionTable("false","05",FirstLBA,0x0,0x1EE,MBR) ## offset at 0x1EE is the last entry in MBR else: print "Extended Partition begins at FirstLBA=%i, size is %i\n" % (ExtendedPartitionBegins,MinSectorsNeeded-FirstLBA) MBR=UpdatePartitionTable("false","05",FirstLBA,MinSectorsNeeded-FirstLBA,0x1EE,MBR) ## offset at 0x1EE is the last entry in MBR ## Still patch no matter what, since this can still go on any size card 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.") 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.") UpdatePatch('0',str(0x1FA),PhysicalPartitionNumber,4,"NUM_DISK_SECTORS-%s." % str(ExtendedPartitionBegins),"DISK", "Update MBR with the length of the EXT Partition.") UpdateWPhash(FirstLBA, NumEBRPartitions) ## Need to make room for the EBR tables FirstLBA += NumEBRPartitions LastLBA += NumEBRPartitions print "FirstLBA now equals %d since NumEBRPartitions=%d" % (FirstLBA,NumEBRPartitions) offset = 0 # offset to EBR array which gets EBR.extend( [0]*SECTOR_SIZE_IN_BYTES ) for each EBR SectorsTillNextBoundary = 0 # reset # EBROffset is the num sectors from the location of the EBR to the actual logical partition # and because we group all the EBRs together, # EBR0 is NumEBRPartitions away from EXT0 # EBR1 is NumEBRPartitions-1+SizeOfEXT0 away from EXT1 and so on # EBR2 is NumEBRPartitions-2+SizeOfEXT0+SizeOfEXT1 away from EXT2 and so on # Thus EBROffset is constantly growing # Also since the EBRs must be write protected, we must ensure that it ends # on a WP boundary, i.e. HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB'] ## NOTE: We only have extended partitions when there are more than 4 partitions ## meaning 3 primary and then 2 extended. Thus everything here is offset from 3 ## since the first 3 primary partitions were 0,1,2 EBR = [] for j in range(3,(NumEBRPartitions+3)): SectorsTillNextBoundary = 0 EBR.extend( [0]*SECTOR_SIZE_IN_BYTES ) #print "hash_w[%i]['start_sector']=%i" % (NumWPregions,hash_w[NumWPregions]["start_sector"]) #print "hash_w[%i]['end_sector']=%i" % (NumWPregions,hash_w[NumWPregions]["end_sector"]) #print "hash_w[%i]['num_sectors']=%i" % (NumWPregions,hash_w[NumWPregions]["num_sectors"]) PartitionSectorSize = ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb']) ##print "\nPartition name='%s' (readonly=%s)" % (PhyPartition[k][j]['label'], PhyPartition[k][j]['readonly']) 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'])) print "\tFirstLBA=%d (with size %d sectors) and LastLBA=%d" % (FirstLBA,ConvertKBtoSectors(PhyPartition[k][j]['size_in_kb']),LastLBA) if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0: SectorsTillNextBoundary = ReturnNumSectorsTillBoundary(FirstLBA,HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']) # Only the last partition can be re-sized. Are we on the very last partition? if (j+1) == len(PhyPartition[k]): print "\n\tTHIS IS THE LAST PARTITION" if PhyPartition[k][j]['readonly']=="true": PhyPartition[k][j]['readonly']="false" print "\tIt cannot be marked as read-only, it is now set to writeable" if HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK']==True: ## Here I'd want a patch for this print "\tHashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] = %s" % HashInstructions['GROW_LAST_PARTITION_TO_FILL_DISK'] print "\njust set LAST PartitionSectorSize = 0 (it was %d)" % PartitionSectorSize PartitionSectorSize = 0 print "This means the partition table will have a zero in it" LastPartitionBeginsAt = FirstLBA NumEBRs = (len(PhyPartition[k])-3) SectorOffsetPatchBefore = NumEBRs SectorOffsetPatchAfter = ExtendedPartitionBegins+NumEBRs-1 ByteOffset = 0x1CA ## Patch no matter what UpdatePatch(str(SectorOffsetPatchBefore),str(ByteOffset),PhysicalPartitionNumber,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA+1),"partition%d.bin" % k, "Update last partition with actual size.") 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.") UpdatePatch(str(SectorOffsetPatchAfter), str(ByteOffset),PhysicalPartitionNumber,4,"NUM_DISK_SECTORS-%s." % str(FirstLBA+1),"DISK", "Update last partition with actual size.") print "\tPhyPartition[k][j]['align']=",PhyPartition[k][j]['align'] print "\tSectorsTillNextBoundary=",SectorsTillNextBoundary if PhyPartition[k][j]['readonly']=="true": ## to be here means this partition is read-only, so see if we need to move the start if FirstLBA <= hash_w[NumWPregions]["end_sector"]: 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"]) pass else: 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) FirstLBA += SectorsTillNextBoundary elif PhyPartition[k][j]['align']=="true": ## to be here means this partition *must* be on an ALIGN boundary SectorsTillNextBoundary = ReturnNumSectorsTillBoundary(FirstLBA,HashInstructions['ALIGN_BOUNDARY_IN_KB']) if SectorsTillNextBoundary>0: print "\tSectorsTillNextBoundary=%d, FirstLBA=%d it needs to be moved to be aligned to %d" % (SectorsTillNextBoundary,FirstLBA,FirstLBA + SectorsTillNextBoundary) print "\tHashInstructions['ALIGN_BOUNDARY_IN_KB']=",HashInstructions['ALIGN_BOUNDARY_IN_KB'] FirstLBA += SectorsTillNextBoundary AlignedRemainder = FirstLBA % HashInstructions['ALIGN_BOUNDARY_IN_KB']; if AlignedRemainder==0: 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']))) else: print "\n\tThis partition is *NOT* readonly (or does not have align='true')" ## to be here means this partition is writeable, so see if we need to move the start if FirstLBA <= hash_w[NumWPregions]["end_sector"]: 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"]) print "\nhash_w[NumWPregions]['end_sector']=%i" % hash_w[NumWPregions]["end_sector"]; print "FirstLBA=%i\n" %FirstLBA; FirstLBA += SectorsTillNextBoundary print "\tFirstLBA is now %d" % (FirstLBA) else: #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"]) pass if HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']>0: AlignedRemainder = FirstLBA % HashInstructions['WRITE_PROTECT_BOUNDARY_IN_KB']; if AlignedRemainder==0: 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']))) if PhyPartition[k][j]['readonly']=="true": UpdateWPhash(FirstLBA, PartitionSectorSize) LastLBA = FirstLBA + PartitionSectorSize print "\n\tFirstLBA=%u, LastLBA=%u, PartitionSectorSize=%u" % (FirstLBA,LastLBA,PartitionSectorSize) print "\tLastLBA is currently %i sectors" % LastLBA print "\tCard size of at least %.1fMB needed (%u sectors)" % (LastLBA/2048.0,LastLBA) PhyPartition[k][j]['size_in_kb'] = PartitionSectorSize/2 ## Default for each partition is no file FileToProgram = [""] FileOffset = [0] FilePartitionOffset = [0] FileAppsbin = ["false"] FileSparse = ["false"] if 'filename' in PhyPartition[k][j]: ##print "filename exists" #print PhyPartition[k][j]['filename'] #print FileToProgram[0] FileToProgram[0] = PhyPartition[k][j]['filename'][0] FileOffset[0] = PhyPartition[k][j]['fileoffset'][0] FilePartitionOffset[0] = PhyPartition[k][j]['filepartitionoffset'][0] FileAppsbin[0] = PhyPartition[k][j]['appsbin'][0] FileSparse[0] = PhyPartition[k][j]['sparse'][0] for z in range(1,len(PhyPartition[k][j]['filename'])): FileToProgram.append( PhyPartition[k][j]['filename'][z] ) FileOffset.append( PhyPartition[k][j]['fileoffset'][z] ) FilePartitionOffset.append( PhyPartition[k][j]['filepartitionoffset'][z] ) FileAppsbin.append( PhyPartition[k][j]['appsbin'][z] ) FileSparse.append( PhyPartition[k][j]['sparse'][z] ) #print PhyPartition[k][j]['fileoffset'] #for z in range(len(FileToProgram)): # print "FileToProgram[",z,"]=",FileToProgram[z] # print "FileOffset[",z,"]=",FileOffset[z] # print " " PartitionLabel = "" Type = "" Bootable = "false" if 'label' in PhyPartition[k][j]: PartitionLabel = PhyPartition[k][j]['label'] if 'type' in PhyPartition[k][j]: Type = PhyPartition[k][j]['type'] if 'bootable' in PhyPartition[k][j]: Bootable = PhyPartition[k][j]['bootable'] ## Update main logical partition offset += 0x1BE ## this naturally increments to 0x200, then 0x400 etc ##UpdatePartitionTable(Bootable,Type,EBROffset,PartitionSectorSize,offset) ; offset +=16 EBR = UpdatePartitionTable(Bootable,Type,FirstLBA-ExtendedPartitionBegins-EBROffset,PartitionSectorSize,offset,EBR) ; offset +=16 ## Update EXT, i.e. are there more partitions to come? if (j+1) == (NumEBRPartitions+3): ## No, this is the very last so indicate no more logical partitions EBR = UpdatePartitionTable("false","00",0,0,offset,EBR) ; offset +=16 ## on last partition, so no more else: ## Yes, at least one more, so indicate EXT type of 05 EBR = UpdatePartitionTable("false","05",j-2,1,offset,EBR) ; offset +=16 ## Update last 2 which are always blank EBR = UpdatePartitionTable("false","00",0,0,offset,EBR) ; offset +=16 EBR = UpdatePartitionTable("false","00",0,0,offset,EBR) ; offset +=16 EBR[offset] = 0x55 ; offset +=1 EBR[offset] = 0xAA ; offset +=1 ## Now update EBROffset EBROffset += 1 # Each EBR gets us one closer for z in range(len(FileToProgram)): #print "File: ",FileToProgram[z] #print "FilePartitionOffset[z]=",FilePartitionOffset[z] UpdateRawProgram(RawProgramXML,FirstLBA+FilePartitionOffset[z], PartitionSectorSize*SECTOR_SIZE_IN_BYTES/1024.0, k, FileOffset[z], PartitionSectorSize-FilePartitionOffset[z], FileToProgram[z], FileSparse[z], PartitionLabel) FirstLBA = LastLBA # getting ready for next partition, FirstLBA is now where we left off print "\n------------------------------------------------------------------------------" print " LastLBA is currently %i sectors" % (LastLBA) print " Card size of at least %.1fMB needed (%u sectors)" % (LastLBA/2048.0,LastLBA) print "------------------------------------------------------------------------------" def ReturnNumSectorsTillBoundary(CurrentLBA, BoundaryInKB): #Say BoundaryInKB is 65536 (64MB) # if SECTOR_SIZE_IN_BYTES=512, BoundaryLBA=131072 # if SECTOR_SIZE_IN_BYTES=4096, BoundaryLBA=16384 #Say were at the 63MB boundary, then # if SECTOR_SIZE_IN_BYTES=512, CurrentLBA=129024 # if SECTOR_SIZE_IN_BYTES=4096, CurrentLBA=16128 # Distance is then 1MB # if SECTOR_SIZE_IN_BYTES=512, DistanceLBA=2048 (2048*512=1MB) # if SECTOR_SIZE_IN_BYTES=4096, DistanceLBA=256 (256*4096=1MB) ##import pdb; pdb.set_trace() x = 0 if BoundaryInKB>0: if (CurrentLBA%ConvertKBtoSectors(BoundaryInKB)) > 0: x = ConvertKBtoSectors(BoundaryInKB) - (CurrentLBA%ConvertKBtoSectors(BoundaryInKB)) ##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) return x def WriteMBR(): global opfile,MBR for b in MBR: opfile.write(struct.pack("B", b)) def WriteEBR(): global opfile,EBR for b in EBR: opfile.write(struct.pack("B", b)) def PrintBigError(sz): print "\t _________________ ___________ " print "\t| ___| ___ \\ ___ \\ _ | ___ \\" print "\t| |__ | |_/ / |_/ / | | | |_/ /" print "\t| __|| /| /| | | | / " print "\t| |___| |\\ \\| |\\ \\\\ \\_/ / |\\ \\ " print "\t\\____/\\_| \\_\\_| \\_|\\___/\\_| \\_|\n" if len(sz)>0: print sz sys.exit(1) def find_file(filename, search_paths): print "\n\n\tLooking for ",filename print "\t"+"-"*40 for x in search_paths: print "\tSearching ",x temp = os.path.join(x, filename) if os.path.exists(temp): print "\n\t**Found %s (%i bytes)" % (temp,os.path.getsize(temp)) return temp ## search cwd last print "\tSearching ",os.getcwd() if os.path.exists(filename): print "\n\t**Found %s (%i bytes)" % (filename,os.path.getsize(filename)) return filename print "\tCound't find file\n" return None ## ============================================================================================== ## ============================================================================================== ## ============================================================================================== ## =====main()=================================================================================== ## ============================================================================================== ## ============================================================================================== ## ============================================================================================== if len(sys.argv) < 2: CreateErasingRawProgramFiles() ShowUsage() sys.exit(); # error print "\nCWD: ", os.getcwd(), "\n" try: opts, args = getopt.getopt(sys.argv[1:], "x:f:p:s:t:g:k:v", ["xml=", "format=", "partition=", "search_path=", "location=", "sequentialguid=", "use128partitions=", "verbose="]) except getopt.GetoptError, err: # print help information and exit: print str(err) # will print something like "option -a not recognized" ShowUsage() sys.exit(1) XMLFile= "aaron" OutputToCreate = None ## sys.argv[2] PhysicalPartitionNumber = 0 ## sys.argv[3] search_paths = [] verbose = False UsingGetOpts = False sequentialguid = 0 force128partitions = 0 for o, a in opts: if o in ("-x", "--xml"): UsingGetOpts = True XMLFile = a elif o in ("-t", "--location"): OutputFolder = a OutputFolder = re.sub(r"\\$","",OutputFolder) # remove final slash if it exists OutputFolder = re.sub(r"/$","",OutputFolder) # remove final slash if it exists OutputFolder += "/" # slashes will all be corrected below if sys.platform.startswith("linux"): OutputFolder = re.sub(r"\\","/",OutputFolder) # correct slashes else: OutputFolder = re.sub(r"/","\\\\",OutputFolder) # correct slashes print "OutputFolder=",OutputFolder EnsureDirectoryExists(OutputFolder) # only need to call once elif o in ("-f", "--format"): UsingGetOpts = True OutputToCreate = a m = re.search("^(mbr|gpt)$", a) #mbr|gpt if type(m) is NoneType: PrintBigError("ERROR: Only MBR or GPT is supported") else: OutputToCreate = m.group(1) elif o in ("-s", "--search_path"): ## also allow seperating commas for x in a.strip("\n").split(","): search_paths.append(x) elif o in ("-k", "--use128partitions"): ## Force there to be 128 partitions in the partition table m = re.search("\d", a) #mbr|gpt if type(m) is NoneType: force128partitions = 0 else: force128partitions = 1 elif o in ("-g", "--sequentialguid"): ## also allow seperating commas m = re.search("\d", a) #mbr|gpt if type(m) is NoneType: sequentialguid = 0 else: sequentialguid = 1 elif o in ("-p", "--partition"): UsingGetOpts = True PhysicalPartitionNumber = a m = re.search("^(\d)$", a) #0|1|2 if type(m) is NoneType: PrintBigError("ERROR: PhysicalPartitionNumber (-p) must be a number, you supplied *",a,"*") else: PhysicalPartitionNumber = int(m.group(1)) elif o in ("-v", "--verbose"): UsingGetOpts = True verbose = True else: print "o=",o assert False, "unhandled option" if UsingGetOpts is False: #ParseCommandLine() PrintBanner("NEW USAGE - Note this program will auto-detect if it's GPT or MBR") ShowUsage() sys.exit(1) print "XMLFile=",XMLFile if len(OutputFolder)>0: print "OutputFolder=",OutputFolder print "OutputToCreate",OutputToCreate print "PhysicalPartitionNumber",PhysicalPartitionNumber print "verbose",verbose XMLFile = find_file(XMLFile, search_paths) if XMLFile is None: PrintBigError("ERROR: Could not find file") ParseXML(XMLFile) # parses XMLFile, discovers if GPT or MBR PrintBanner("OutputToCreate ===> '%s'" % OutputToCreate) EmmcLockRegionsXML = Element('protect') EmmcLockRegionsXML.append(Comment("NOTE: This is an ** Autogenerated file **")) 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'])))) EmmcLockRegionsXML.append(Comment("NOTE: \"num_sectors\" in HEX \"start_sector\" in HEX, i.e. 10 really equals 16 !!")) RawProgramXML = Element('data') RawProgramXML.append(Comment('NOTE: This is an ** Autogenerated file **')) RawProgramXML.append(Comment('NOTE: Sector size is %ibytes'%SECTOR_SIZE_IN_BYTES)) RawProgramXML_Blank = Element('data') RawProgramXML_Blank.append(Comment('NOTE: This is an ** Autogenerated file **')) RawProgramXML_Blank.append(Comment('NOTE: Sector size is %ibytes'%SECTOR_SIZE_IN_BYTES)) PatchesXML = Element('patches') PatchesXML.append(Comment('NOTE: This is an ** Autogenerated file **')) 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')) 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.')) if OutputToCreate == "gpt": CreateGPTPartitionTable( PhysicalPartitionNumber ) ## wants it in LBA format, i.e. 1KB = 2 sectors of size SECTOR_SIZE_IN_BYTES else: CreateMBRPartitionTable( PhysicalPartitionNumber ) CreateFinalPartitionBin() CreateErasingRawProgramFiles()