ipq6018mibib/scripts/ptool.py
2025-09-28 10:20:07 +08:00

2228 lines
107 KiB
Python
Executable File

#!/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 <physical_partition> 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 "<!-- This is physical partition 0 -->"
print "<physical_partition>"
print " <partition label=\"SBL1\" size_in_kb=\"100\" type=\"DEA0BA2C-CBDD-4805-B4F9-F428251C3E98\" filename=\"sbl1.mbn\"/>"
print "</physical_partition>"
print " "
print "<!-- This is physical partition 1 -->"
print "<physical_partition>"
print " <partition label=\"SBL2\" size_in_kb=\"200\" type=\"8C6B52AD-8A9E-4398-AD09-AE916E53AE2D\" filename=\"sbl2.mbn\"/>"
print "</physical_partition>"
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<parser_instructions>"
print "\t\tPERFORMANCE_BOUNDARY_IN_KB = %i" % Partition['PERFORMANCE_BOUNDARY_IN_KB']
print "\t\tALIGN_PARTITIONS_TO_PERFORMANCE_BOUNDARY=true"
print "\t</parser_instructions>\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
# <physical_partition>
# </physical_partition>
# 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 <physical_partition></physical_partition> tags detected\n"
print "Please replace with"
print "<physical_partition>"
print "<partition label='placeholder' size_in_kb='0' type='00000000-0000-0000-0000-000000000001' bootable='false' readonly='false' filename='' />"
print "</physical_partition>\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 <file> 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()