1## @file 2# Convert a binary file to a VOID* PCD value or DSC file VOID* PCD statement. 3# 4# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> 5# SPDX-License-Identifier: BSD-2-Clause-Patent 6# 7 8''' 9BinToPcd 10''' 11from __future__ import print_function 12 13import sys 14import argparse 15import re 16import xdrlib 17 18# 19# Globals for help information 20# 21__prog__ = 'BinToPcd' 22__copyright__ = 'Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.' 23__description__ = 'Convert one or more binary files to a VOID* PCD value or DSC file VOID* PCD statement.\n' 24 25if __name__ == '__main__': 26 def ValidateUnsignedInteger (Argument): 27 try: 28 Value = int (Argument, 0) 29 except: 30 Message = '{Argument} is not a valid integer value.'.format (Argument = Argument) 31 raise argparse.ArgumentTypeError (Message) 32 if Value < 0: 33 Message = '{Argument} is a negative value.'.format (Argument = Argument) 34 raise argparse.ArgumentTypeError (Message) 35 return Value 36 37 def ValidatePcdName (Argument): 38 if re.split ('[a-zA-Z\_][a-zA-Z0-9\_]*\.[a-zA-Z\_][a-zA-Z0-9\_]*', Argument) != ['', '']: 39 Message = '{Argument} is not in the form <PcdTokenSpaceGuidCName>.<PcdCName>'.format (Argument = Argument) 40 raise argparse.ArgumentTypeError (Message) 41 return Argument 42 43 def ValidateGuidName (Argument): 44 if re.split ('[a-zA-Z\_][a-zA-Z0-9\_]*', Argument) != ['', '']: 45 Message = '{Argument} is not a valid GUID C name'.format (Argument = Argument) 46 raise argparse.ArgumentTypeError (Message) 47 return Argument 48 49 def ByteArray (Buffer, Xdr = False): 50 if Xdr: 51 # 52 # If Xdr flag is set then encode data using the Variable-Length Opaque 53 # Data format of RFC 4506 External Data Representation Standard (XDR). 54 # 55 XdrEncoder = xdrlib.Packer () 56 for Item in Buffer: 57 XdrEncoder.pack_bytes (Item) 58 Buffer = bytearray (XdrEncoder.get_buffer ()) 59 else: 60 # 61 # If Xdr flag is not set, then concatenate all the data 62 # 63 Buffer = bytearray (b''.join (Buffer)) 64 # 65 # Return a PCD value of the form '{0x01, 0x02, ...}' along with the PCD length in bytes 66 # 67 return '{' + (', '.join (['0x{Byte:02X}'.format (Byte = Item) for Item in Buffer])) + '}', len (Buffer) 68 69 # 70 # Create command line argument parser object 71 # 72 parser = argparse.ArgumentParser (prog = __prog__, 73 description = __description__ + __copyright__, 74 conflict_handler = 'resolve') 75 parser.add_argument ("-i", "--input", dest = 'InputFile', type = argparse.FileType ('rb'), action='append', required = True, 76 help = "Input binary filename. Multiple input files are combined into a single PCD.") 77 parser.add_argument ("-o", "--output", dest = 'OutputFile', type = argparse.FileType ('w'), 78 help = "Output filename for PCD value or PCD statement") 79 parser.add_argument ("-p", "--pcd", dest = 'PcdName', type = ValidatePcdName, 80 help = "Name of the PCD in the form <PcdTokenSpaceGuidCName>.<PcdCName>") 81 parser.add_argument ("-t", "--type", dest = 'PcdType', default = None, choices = ['VPD', 'HII'], 82 help = "PCD statement type (HII or VPD). Default is standard.") 83 parser.add_argument ("-m", "--max-size", dest = 'MaxSize', type = ValidateUnsignedInteger, 84 help = "Maximum size of the PCD. Ignored with --type HII.") 85 parser.add_argument ("-f", "--offset", dest = 'Offset', type = ValidateUnsignedInteger, 86 help = "VPD offset if --type is VPD. UEFI Variable offset if --type is HII. Must be 8-byte aligned.") 87 parser.add_argument ("-n", "--variable-name", dest = 'VariableName', 88 help = "UEFI variable name. Only used with --type HII.") 89 parser.add_argument ("-g", "--variable-guid", type = ValidateGuidName, dest = 'VariableGuid', 90 help = "UEFI variable GUID C name. Only used with --type HII.") 91 parser.add_argument ("-x", "--xdr", dest = 'Xdr', action = "store_true", 92 help = "Encode PCD using the Variable-Length Opaque Data format of RFC 4506 External Data Representation Standard (XDR)") 93 parser.add_argument ("-v", "--verbose", dest = 'Verbose', action = "store_true", 94 help = "Increase output messages") 95 parser.add_argument ("-q", "--quiet", dest = 'Quiet', action = "store_true", 96 help = "Reduce output messages") 97 parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0, 98 help = "Set debug level") 99 100 # 101 # Parse command line arguments 102 # 103 args = parser.parse_args () 104 105 # 106 # Read all binary input files 107 # 108 Buffer = [] 109 for File in args.InputFile: 110 try: 111 Buffer.append (File.read ()) 112 File.close () 113 except: 114 print ('BinToPcd: error: can not read binary input file {File}'.format (File = File)) 115 sys.exit (1) 116 117 # 118 # Convert PCD to an encoded string of hex values and determine the size of 119 # the encoded PCD in bytes. 120 # 121 PcdValue, PcdSize = ByteArray (Buffer, args.Xdr) 122 123 # 124 # Convert binary buffer to a DSC file PCD statement 125 # 126 if args.PcdName is None: 127 # 128 # If PcdName is None, then only a PCD value is being requested. 129 # 130 Pcd = PcdValue 131 if args.Verbose: 132 print ('BinToPcd: Convert binary file to PCD Value') 133 elif args.PcdType is None: 134 # 135 # If --type is neither VPD nor HII, then use PCD statement syntax that is 136 # compatible with [PcdsFixedAtBuild], [PcdsPatchableInModule], 137 # [PcdsDynamicDefault], and [PcdsDynamicExDefault]. 138 # 139 if args.MaxSize is None: 140 # 141 # If --max-size is not provided, then do not generate the syntax that 142 # includes the maximum size. 143 # 144 Pcd = ' {Name}|{Value}'.format (Name = args.PcdName, Value = PcdValue) 145 elif args.MaxSize < PcdSize: 146 print ('BinToPcd: error: argument --max-size is smaller than input file.') 147 sys.exit (1) 148 else: 149 Pcd = ' {Name}|{Value}|VOID*|{Size}'.format (Name = args.PcdName, Value = PcdValue, Size = args.MaxSize) 150 151 if args.Verbose: 152 print ('BinToPcd: Convert binary file to PCD statement compatible with PCD sections:') 153 print (' [PcdsFixedAtBuild]') 154 print (' [PcdsPatchableInModule]') 155 print (' [PcdsDynamicDefault]') 156 print (' [PcdsDynamicExDefault]') 157 elif args.PcdType == 'VPD': 158 if args.MaxSize is None: 159 # 160 # If --max-size is not provided, then set maximum size to the size of the 161 # binary input file 162 # 163 args.MaxSize = PcdSize 164 if args.MaxSize < PcdSize: 165 print ('BinToPcd: error: argument --max-size is smaller than input file.') 166 sys.exit (1) 167 if args.Offset is None: 168 # 169 # if --offset is not provided, then set offset field to '*' so build 170 # tools will compute offset of PCD in VPD region. 171 # 172 Pcd = ' {Name}|*|{Size}|{Value}'.format (Name = args.PcdName, Size = args.MaxSize, Value = PcdValue) 173 else: 174 # 175 # --offset value must be 8-byte aligned 176 # 177 if (args.Offset % 8) != 0: 178 print ('BinToPcd: error: argument --offset must be 8-byte aligned.') 179 sys.exit (1) 180 # 181 # Use the --offset value provided. 182 # 183 Pcd = ' {Name}|{Offset}|{Size}|{Value}'.format (Name = args.PcdName, Offset = args.Offset, Size = args.MaxSize, Value = PcdValue) 184 if args.Verbose: 185 print ('BinToPcd: Convert binary file to PCD statement compatible with PCD sections') 186 print (' [PcdsDynamicVpd]') 187 print (' [PcdsDynamicExVpd]') 188 elif args.PcdType == 'HII': 189 if args.VariableGuid is None or args.VariableName is None: 190 print ('BinToPcd: error: arguments --variable-guid and --variable-name are required for --type HII.') 191 sys.exit (1) 192 if args.Offset is None: 193 # 194 # Use UEFI Variable offset of 0 if --offset is not provided 195 # 196 args.Offset = 0 197 # 198 # --offset value must be 8-byte aligned 199 # 200 if (args.Offset % 8) != 0: 201 print ('BinToPcd: error: argument --offset must be 8-byte aligned.') 202 sys.exit (1) 203 Pcd = ' {Name}|L"{VarName}"|{VarGuid}|{Offset}|{Value}'.format (Name = args.PcdName, VarName = args.VariableName, VarGuid = args.VariableGuid, Offset = args.Offset, Value = PcdValue) 204 if args.Verbose: 205 print ('BinToPcd: Convert binary file to PCD statement compatible with PCD sections') 206 print (' [PcdsDynamicHii]') 207 print (' [PcdsDynamicExHii]') 208 209 # 210 # Write PCD value or PCD statement to the output file 211 # 212 try: 213 args.OutputFile.write (Pcd) 214 args.OutputFile.close () 215 except: 216 # 217 # If output file is not specified or it can not be written, then write the 218 # PCD value or PCD statement to the console 219 # 220 print (Pcd) 221