]>
Commit | Line | Data |
---|---|---|
52302d4d LG |
1 | ## @file |
2 | # Patch value into the binary file. | |
3 | # | |
40d841f6 LG |
4 | # Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> |
5 | # This program and the accompanying materials | |
52302d4d LG |
6 | # are licensed and made available under the terms and conditions of the BSD License |
7 | # which accompanies this distribution. The full text of the license may be found at | |
8 | # http://opensource.org/licenses/bsd-license.php | |
9 | # | |
10 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
11 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
12 | # | |
13 | ||
14 | ## | |
15 | # Import Modules | |
16 | # | |
17 | import os | |
18 | import sys | |
19 | import re | |
20 | ||
21 | from optparse import OptionParser | |
22 | from optparse import make_option | |
23 | from Common.BuildToolError import * | |
24 | import Common.EdkLogger as EdkLogger | |
b36d134f LG |
25 | from Common.BuildVersion import gBUILD_VERSION |
26 | ||
52302d4d LG |
27 | import array |
28 | ||
29 | # Version and Copyright | |
b36d134f | 30 | __version_number__ = ("0.10" + " " + gBUILD_VERSION) |
52302d4d LG |
31 | __version__ = "%prog Version " + __version_number__ |
32 | __copyright__ = "Copyright (c) 2010, Intel Corporation. All rights reserved." | |
33 | ||
34 | ## PatchBinaryFile method | |
35 | # | |
36 | # This method mainly patches the data into binary file. | |
37 | # | |
38 | # @param FileName File path of the binary file | |
39 | # @param ValueOffset Offset value | |
40 | # @param TypeName DataType Name | |
41 | # @param Value Value String | |
42 | # @param MaxSize MaxSize value | |
43 | # | |
44 | # @retval 0 File is updated successfully. | |
45 | # @retval not 0 File is updated failed. | |
46 | # | |
47 | def PatchBinaryFile(FileName, ValueOffset, TypeName, ValueString, MaxSize=0): | |
48 | # | |
49 | # Length of Binary File | |
50 | # | |
51 | FileHandle = open (FileName, 'rb') | |
52 | FileHandle.seek (0, 2) | |
53 | FileLength = FileHandle.tell() | |
54 | FileHandle.close() | |
55 | # | |
56 | # Unify string to upper string | |
57 | # | |
58 | TypeName = TypeName.upper() | |
59 | # | |
60 | # Get PCD value data length | |
61 | # | |
62 | ValueLength = 0 | |
63 | if TypeName == 'BOOLEAN': | |
64 | ValueLength = 1 | |
65 | elif TypeName == 'UINT8': | |
66 | ValueLength = 1 | |
67 | elif TypeName == 'UINT16': | |
68 | ValueLength = 2 | |
69 | elif TypeName == 'UINT32': | |
70 | ValueLength = 4 | |
71 | elif TypeName == 'UINT64': | |
72 | ValueLength = 8 | |
73 | elif TypeName == 'VOID*': | |
74 | if MaxSize == 0: | |
75 | return OPTION_MISSING, "PcdMaxSize is not specified for VOID* type PCD." | |
76 | ValueLength = MaxSize | |
77 | else: | |
78 | return PARAMETER_INVALID, "PCD type %s is not valid." %(CommandOptions.PcdTypeName) | |
79 | # | |
80 | # Check PcdValue is in the input binary file. | |
81 | # | |
82 | if ValueOffset + ValueLength > FileLength: | |
83 | return PARAMETER_INVALID, "PcdOffset + PcdMaxSize(DataType) is larger than the input file size." | |
84 | # | |
85 | # Read binary file into array | |
86 | # | |
87 | FileHandle = open (FileName, 'rb') | |
88 | ByteArray = array.array('B') | |
89 | ByteArray.fromfile(FileHandle, FileLength) | |
90 | FileHandle.close() | |
91 | OrigByteList = ByteArray.tolist() | |
92 | ByteList = ByteArray.tolist() | |
93 | # | |
94 | # Clear the data in file | |
95 | # | |
96 | for Index in range(ValueLength): | |
97 | ByteList[ValueOffset + Index] = 0 | |
98 | # | |
99 | # Patch value into offset | |
100 | # | |
101 | ValueString = ValueString.upper() | |
102 | ValueNumber = 0 | |
103 | if TypeName == 'BOOLEAN': | |
104 | # | |
105 | # Get PCD value for BOOLEAN data type | |
106 | # | |
107 | try: | |
108 | if ValueString == 'TRUE': | |
109 | ValueNumber = 1 | |
110 | elif ValueString == 'FALSE': | |
111 | ValueNumber = 0 | |
112 | elif ValueString.startswith('0X'): | |
113 | ValueNumber = int (Value, 16) | |
114 | else: | |
115 | ValueNumber = int (Value) | |
116 | if ValueNumber != 0: | |
117 | ValueNumber = 1 | |
118 | except: | |
119 | return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string." %(ValueString) | |
120 | # | |
121 | # Set PCD value into binary data | |
122 | # | |
123 | ByteList[ValueOffset] = ValueNumber | |
124 | elif TypeName in ['UINT8', 'UINT16', 'UINT32', 'UINT64']: | |
125 | # | |
126 | # Get PCD value for UINT* data type | |
127 | # | |
128 | try: | |
129 | if ValueString.startswith('0X'): | |
130 | ValueNumber = int (ValueString, 16) | |
131 | else: | |
132 | ValueNumber = int (ValueString) | |
133 | except: | |
134 | return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string." %(ValueString) | |
135 | # | |
136 | # Set PCD value into binary data | |
137 | # | |
138 | for Index in range(ValueLength): | |
139 | ByteList[ValueOffset + Index] = ValueNumber % 0x100 | |
140 | ValueNumber = ValueNumber / 0x100 | |
141 | elif TypeName == 'VOID*': | |
142 | if ValueString.startswith("L "): | |
143 | # | |
144 | # Patch Unicode String | |
145 | # | |
146 | Index = 0 | |
147 | for ByteString in ValueString[2:]: | |
148 | # | |
149 | # Reserve zero as unicode tail | |
150 | # | |
151 | if Index + 2 >= ValueLength: | |
152 | break | |
153 | # | |
154 | # Set string value one by one | |
155 | # | |
156 | ByteList[ValueOffset + Index] = ord(ByteString) | |
157 | Index = Index + 2 | |
158 | elif ValueString.startswith("{") and ValueString.endswith("}"): | |
159 | # | |
160 | # Patch {0x1, 0x2, ...} byte by byte | |
161 | # | |
162 | ValueList = ValueString[1 : len(ValueString) - 1].split(', ') | |
163 | Index = 0 | |
164 | try: | |
165 | for ByteString in ValueList: | |
166 | if ByteString.upper().startswith('0X'): | |
167 | ByteValue = int(ByteString, 16) | |
168 | else: | |
169 | ByteValue = int(ByteString) | |
170 | ByteList[ValueOffset + Index] = ByteValue % 0x100 | |
171 | Index = Index + 1 | |
172 | if Index >= ValueLength: | |
173 | break | |
174 | except: | |
175 | return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string array." %(ValueString) | |
176 | else: | |
177 | # | |
178 | # Patch ascii string | |
179 | # | |
180 | Index = 0 | |
181 | for ByteString in ValueString: | |
182 | # | |
183 | # Reserve zero as string tail | |
184 | # | |
185 | if Index + 1 >= ValueLength: | |
186 | break | |
187 | # | |
188 | # Set string value one by one | |
189 | # | |
190 | ByteList[ValueOffset + Index] = ord(ByteString) | |
191 | Index = Index + 1 | |
192 | # | |
193 | # Update new data into input file. | |
194 | # | |
195 | if ByteList != OrigByteList: | |
196 | ByteArray = array.array('B') | |
197 | ByteArray.fromlist(ByteList) | |
198 | FileHandle = open (FileName, 'wb') | |
199 | ByteArray.tofile(FileHandle) | |
200 | FileHandle.close() | |
201 | return 0, "Patch Value into File %s successfully." %(FileName) | |
202 | ||
203 | ## Parse command line options | |
204 | # | |
205 | # Using standard Python module optparse to parse command line option of this tool. | |
206 | # | |
207 | # @retval Options A optparse.Values object containing the parsed options | |
208 | # @retval InputFile Path of file to be trimmed | |
209 | # | |
210 | def Options(): | |
211 | OptionList = [ | |
212 | make_option("-f", "--offset", dest="PcdOffset", action="store", type="int", | |
213 | help="Start offset to the image is used to store PCD value."), | |
214 | make_option("-u", "--value", dest="PcdValue", action="store", | |
215 | help="PCD value will be updated into the image."), | |
216 | make_option("-t", "--type", dest="PcdTypeName", action="store", | |
217 | help="The name of PCD data type may be one of VOID*,BOOLEAN, UINT8, UINT16, UINT32, UINT64."), | |
218 | make_option("-s", "--maxsize", dest="PcdMaxSize", action="store", type="int", | |
219 | help="Max size of data buffer is taken by PCD value.It must be set when PCD type is VOID*."), | |
220 | make_option("-v", "--verbose", dest="LogLevel", action="store_const", const=EdkLogger.VERBOSE, | |
221 | help="Run verbosely"), | |
222 | make_option("-d", "--debug", dest="LogLevel", type="int", | |
223 | help="Run with debug information"), | |
224 | make_option("-q", "--quiet", dest="LogLevel", action="store_const", const=EdkLogger.QUIET, | |
225 | help="Run quietly"), | |
226 | make_option("-?", action="help", help="show this help message and exit"), | |
227 | ] | |
228 | ||
229 | # use clearer usage to override default usage message | |
230 | UsageString = "%prog -f Offset -u Value -t Type [-s MaxSize] <input_file>" | |
231 | ||
232 | Parser = OptionParser(description=__copyright__, version=__version__, option_list=OptionList, usage=UsageString) | |
233 | Parser.set_defaults(LogLevel=EdkLogger.INFO) | |
234 | ||
235 | Options, Args = Parser.parse_args() | |
236 | ||
237 | # error check | |
238 | if len(Args) == 0: | |
239 | EdkLogger.error("PatchPcdValue", PARAMETER_INVALID, ExtraData=Parser.get_usage()) | |
240 | ||
241 | InputFile = Args[len(Args) - 1] | |
242 | return Options, InputFile | |
243 | ||
244 | ## Entrance method | |
245 | # | |
246 | # This method mainly dispatch specific methods per the command line options. | |
247 | # If no error found, return zero value so the caller of this tool can know | |
248 | # if it's executed successfully or not. | |
249 | # | |
250 | # @retval 0 Tool was successful | |
251 | # @retval 1 Tool failed | |
252 | # | |
253 | def Main(): | |
254 | try: | |
255 | # | |
256 | # Check input parameter | |
257 | # | |
258 | EdkLogger.Initialize() | |
259 | CommandOptions, InputFile = Options() | |
260 | if CommandOptions.LogLevel < EdkLogger.DEBUG_9: | |
261 | EdkLogger.SetLevel(CommandOptions.LogLevel + 1) | |
262 | else: | |
263 | EdkLogger.SetLevel(CommandOptions.LogLevel) | |
264 | if not os.path.exists (InputFile): | |
265 | EdkLogger.error("PatchPcdValue", FILE_NOT_FOUND, ExtraData=InputFile) | |
266 | return 1 | |
267 | if CommandOptions.PcdOffset == None or CommandOptions.PcdValue == None or CommandOptions.PcdTypeName == None: | |
268 | EdkLogger.error("PatchPcdValue", OPTION_MISSING, ExtraData="PcdOffset or PcdValue of PcdTypeName is not specified.") | |
269 | return 1 | |
270 | if CommandOptions.PcdTypeName.upper() not in ["BOOLEAN", "UINT8", "UINT16", "UINT32", "UINT64", "VOID*"]: | |
271 | EdkLogger.error("PatchPcdValue", PARAMETER_INVALID, ExtraData="PCD type %s is not valid." %(CommandOptions.PcdTypeName)) | |
272 | return 1 | |
273 | if CommandOptions.PcdTypeName.upper() == "VOID*" and CommandOptions.PcdMaxSize == None: | |
274 | EdkLogger.error("PatchPcdValue", OPTION_MISSING, ExtraData="PcdMaxSize is not specified for VOID* type PCD.") | |
275 | return 1 | |
276 | # | |
277 | # Patch value into binary image. | |
278 | # | |
279 | ReturnValue, ErrorInfo = PatchBinaryFile (InputFile, CommandOptions.PcdOffset, CommandOptions.PcdTypeName, CommandOptions.PcdValue, CommandOptions.PcdMaxSize) | |
280 | if ReturnValue != 0: | |
281 | EdkLogger.error("PatchPcdValue", ReturnValue, ExtraData=ErrorInfo) | |
282 | return 1 | |
283 | return 0 | |
284 | except: | |
285 | return 1 | |
286 | ||
287 | if __name__ == '__main__': | |
288 | r = Main() | |
289 | sys.exit(r) |