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