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)