/ util / qualcomm / qgpt.py
qgpt.py
  1  #!/usr/bin/env python3
  2  #============================================================================
  3  #
  4  #/** @file qgpt.py
  5  #
  6  # GENERAL DESCRIPTION
  7  #   Generates QCom GPT header for wrapping Bootblock
  8  #
  9  # Copyright (c) 2018, The Linux Foundation. All rights reserved.
 10  #
 11  # SPDX-License-Identifier: BSD-3-Clause
 12  
 13  #**/
 14  #
 15  
 16  import os
 17  import math
 18  import random
 19  import re
 20  import struct
 21  import sys
 22  import tempfile
 23  
 24  from binascii import crc32
 25  from optparse import OptionParser
 26  from types import *
 27  
 28  
 29  def UpdateMBR(options, GPTBlobBuffer):
 30      i = 0x1BE
 31      GPTBlobBuffer[i + 0] = 0x00                  # not bootable
 32      GPTBlobBuffer[i + 1] = 0x00                  # head
 33      GPTBlobBuffer[i + 2] = 0x01                  # sector
 34      GPTBlobBuffer[i + 3] = 0x00                  # cylinder
 35      GPTBlobBuffer[i + 4] = 0xEE                  # type
 36      GPTBlobBuffer[i + 5] = 0xFF                  # head
 37      GPTBlobBuffer[i + 6] = 0xFF                  # sector
 38      GPTBlobBuffer[i + 7] = 0xFF                  # cylinder
 39      GPTBlobBuffer[i + 8:i + 8 + 4] = [0x01, 0x00, 0x00, 0x00]
 40  
 41      GPTBlobBuffer[i + 12:i + 16] = [0x00, 0x0f, 0x00, 0x00]
 42  
 43      # magic byte for MBR partitioning - always at this location regardless of
 44      # options.sector
 45      GPTBlobBuffer[510:512] = [0x55, 0xAA]
 46      return i
 47  
 48  
 49  def UpdatePartitionEntry(options, GPTBlobBuffer):
 50  
 51      i = 2 * options.sector_size
 52      # GUID of Boot Block
 53      GPTBlobBuffer[i:i + 16] = [0x2c, 0xba, 0xa0, 0xde, 0xdd, 0xcb, 0x05, 0x48,
 54          0xb4, 0xf9, 0xf4, 0x28, 0x25, 0x1c, 0x3e, 0x98]
 55      i += 16
 56  
 57      #This is to set Unique Partition GUID. Below Hex Value is : 00ChezaBootblock00
 58      GPTBlobBuffer[i:i + 16] = [0x00, 0x43, 0x68, 0x65, 0x7a, 0x61, 0x42, 0x6f,
 59          0x6f, 0x74, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x00]
 60      i += 16
 61  
 62      # LBA of BootBlock Start Content
 63      GPTBlobBuffer[i:i + 8] = [0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
 64      i += 8
 65  
 66      # End LBA of BootBlock Content
 67      GPTBlobBuffer[i] = options.end_lba & 0xFF
 68      GPTBlobBuffer[i+1] = (options.end_lba>>8) & 0xFF
 69      GPTBlobBuffer[i+2] = (options.end_lba>>16) & 0xFF
 70      GPTBlobBuffer[i+3] = (options.end_lba>>24) & 0xFF
 71      GPTBlobBuffer[i+4] = (options.end_lba>>32) & 0xFF
 72      GPTBlobBuffer[i+5] = (options.end_lba>>40) & 0xFF
 73      GPTBlobBuffer[i+6] = (options.end_lba>>48) & 0xFF
 74      GPTBlobBuffer[i+7] = (options.end_lba>>56) & 0xFF
 75      i += 8
 76  
 77      # Attributes
 78      GPTBlobBuffer[i:i + 8] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
 79      i += 8
 80  
 81      # Label
 82      GPTBlobBuffer[i:i + 17] = [0x62, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00,
 83          0x62, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x6b]
 84  
 85      return i
 86  
 87  def UpdateGPTHeader(options, GPTBlobBuffer):
 88  
 89      i = options.sector_size
 90      # Signature and Revision and HeaderSize i.e. "EFI PART" and 00 00 01 00
 91      # and 5C 00 00 00
 92      GPTBlobBuffer[i:i + 16] = [0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54,
 93          0x00, 0x00, 0x01, 0x00, 0x5C, 0x00, 0x00, 0x00]
 94      i += 16
 95  
 96      # CRC is zeroed out till calculated later
 97      GPTBlobBuffer[i:i + 4] = [0x00, 0x00, 0x00, 0x00]
 98      i += 4
 99  
100      # Reserved, set to 0
101      GPTBlobBuffer[i:i + 4] = [0x00, 0x00, 0x00, 0x00]
102      i += 4
103  
104      # Current LBA
105      GPTBlobBuffer[i:i + 8] = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
106      i += 8
107  
108      # Backup LBA, No Backup Gpt Used
109      GPTBlobBuffer[i:i + 8] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
110      i += 8
111  
112      # First Usuable LBA (qc_sec + bootblock location)
113      GPTBlobBuffer[i:i + 8] = [0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
114      i += 8
115  
116      # Last Usuable LBA (qc_sec + bootblock end location)
117      GPTBlobBuffer[i] = options.end_lba & 0xFF
118      GPTBlobBuffer[i+1] = (options.end_lba>>8) & 0xFF
119      GPTBlobBuffer[i+2] = (options.end_lba>>16) & 0xFF
120      GPTBlobBuffer[i+3] = (options.end_lba>>24) & 0xFF
121      GPTBlobBuffer[i+4] = (options.end_lba>>32) & 0xFF
122      GPTBlobBuffer[i+5] = (options.end_lba>>40) & 0xFF
123      GPTBlobBuffer[i+6] = (options.end_lba>>48) & 0xFF
124      GPTBlobBuffer[i+7] = (options.end_lba>>56) & 0xFF
125      i += 8
126  
127      # GUID
128      GPTBlobBuffer[i:i + 16] = [0x32,0x1B,0x10,0x98,0xE2,0xBB,0xF2,0x4B,
129          0xA0,0x6E,0x2B,0xB3,0x3D,0x00,0x0C,0x20]
130      i += 16
131  
132      # Partition Table Entry LBA
133      GPTBlobBuffer[i:i + 8] = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
134      i += 8
135  
136      # Number of Partition Entries
137      GPTBlobBuffer[i:i + 4] = [0x01, 0x00, 0x00, 0x00]
138      i += 4
139  
140      # Size of One Partition Entry
141      GPTBlobBuffer[i:i + 4] = [0x80, 0x00, 0x00, 0x00]
142      i += 4
143  
144      # CRC of Partition Entry
145  
146      PartEntry = GPTBlobBuffer[options.sector_size*2:options.sector_size*2 + 128]
147      CalcEntryCRC = crc32(b''.join(struct.pack("B", x) for x in PartEntry))
148  
149      GPTBlobBuffer[i] = CalcEntryCRC & 0xFF
150      GPTBlobBuffer[i+1] = (CalcEntryCRC>>8) & 0xFF
151      GPTBlobBuffer[i+2] = (CalcEntryCRC>>16) & 0xFF
152      GPTBlobBuffer[i+3] = (CalcEntryCRC>>24) & 0xFF
153      i += 4
154  
155      # CRC of Partition Table Header
156      GPTHeader = GPTBlobBuffer[options.sector_size:options.sector_size + 92]
157      CalcEntryCRC = crc32(b''.join(struct.pack("B", x) for x in GPTHeader))
158      i = options.sector_size + 16
159  
160      GPTBlobBuffer[i] = CalcEntryCRC & 0xFF
161      GPTBlobBuffer[i+1] = (CalcEntryCRC>>8) & 0xFF
162      GPTBlobBuffer[i+2] = (CalcEntryCRC>>16) & 0xFF
163      GPTBlobBuffer[i+3] = (CalcEntryCRC>>24) & 0xFF
164  
165      return i
166  
167  
168  if __name__ == '__main__':
169      usage = 'usage: %prog [OPTIONS] INFILE OUTFILE\n\n' + \
170              'Packages IMAGE in a GPT format.'
171      parser = OptionParser(usage)
172      parser.add_option('-s', type="int", dest='sector_size', default=4096,
173                        help='Sector size in bytes [Default:4096(4KB)]',
174                        metavar='SIZE')
175  
176      (options, args) = parser.parse_args()
177      if len(args) != 2:
178          print("Invalid arguments! Exiting...\n")
179          parser.print_help()
180          sys.exit(1)
181  
182      if options.sector_size != 4096 and options.sector_size != 512:
183          print("Invalid Sector Size")
184          sys.exit(1)
185  
186      options.inputfile = args[0]
187      options.outputfile = args[1]
188  
189      with open(options.inputfile, 'rb+') as fin:
190        bb_buffer = fin.read()
191  
192      # Round up to next sector if bootblock size not evenly divisible
193      options.end_lba = ((len(bb_buffer) + options.sector_size - 1) //
194        options.sector_size)
195      # Add 3 sectors for MBR, GPT header and GPT partition entry
196      options.end_lba += 3
197      # Subtract one because this is last usable LBA, not amount of LBAs
198      options.end_lba -= 1
199  
200      GPTBlobBuffer = [0] * (options.sector_size*3) #Size of MBR+GPT+PART_ENTRY
201  
202      UpdateMBR(options, GPTBlobBuffer)
203  
204      UpdatePartitionEntry(options, GPTBlobBuffer)
205  
206      UpdateGPTHeader(options, GPTBlobBuffer)
207  
208      with open(options.outputfile, 'wb') as fout:
209        for b in GPTBlobBuffer:
210          fout.write(struct.pack("B", b))
211        fout.write(bb_buffer)