]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/BPDG/GenVpd.py
BaseTools: Replace StringIO.StringIO with io.BytesIO
[mirror_edk2.git] / BaseTools / Source / Python / BPDG / GenVpd.py
CommitLineData
111be80f 1## @file\r
2# This file include GenVpd class for fix the Vpd type PCD offset, and PcdEntry for describe\r
3# and process each entry of vpd type PCD.\r
4#\r
86737681 5# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
111be80f 6#\r
7# This program and the accompanying materials\r
8# are licensed and made available under the terms and conditions of the BSD License\r
9# which accompanies this distribution. The full text of the license may be found at\r
10# http://opensource.org/licenses/bsd-license.php\r
11#\r
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14#\r
15\r
1be2ed90 16import Common.LongFilePathOs as os\r
86379ac4 17from io import BytesIO\r
111be80f 18import StringTable as st\r
19import array\r
6780eef1 20import re\r
1be2ed90 21from Common.LongFilePathSupport import OpenLongFilePath as open\r
111be80f 22from struct import *\r
23import Common.EdkLogger as EdkLogger\r
24import Common.BuildToolError as BuildToolError\r
25\r
26_FORMAT_CHAR = {1: 'B',\r
27 2: 'H',\r
28 4: 'I',\r
29 8: 'Q'\r
30 }\r
31\r
08dd311f
LG
32## The VPD PCD data structure for store and process each VPD PCD entry.\r
33#\r
34# This class contain method to format and pack pcd's value. \r
35#\r
111be80f 36class PcdEntry:\r
e8a47801 37 def __init__(self, PcdCName, SkuId,PcdOffset, PcdSize, PcdValue, Lineno=None, FileName=None, PcdUnpackValue=None, \r
86737681 38 PcdBinOffset=None, PcdBinSize=None, Alignment=None):\r
111be80f 39 self.PcdCName = PcdCName.strip()\r
e8a47801 40 self.SkuId = SkuId.strip()\r
111be80f 41 self.PcdOffset = PcdOffset.strip()\r
42 self.PcdSize = PcdSize.strip()\r
43 self.PcdValue = PcdValue.strip()\r
44 self.Lineno = Lineno.strip()\r
45 self.FileName = FileName.strip()\r
46 self.PcdUnpackValue = PcdUnpackValue\r
47 self.PcdBinOffset = PcdBinOffset\r
48 self.PcdBinSize = PcdBinSize\r
86737681 49 self.Alignment = Alignment\r
111be80f 50 \r
51 if self.PcdValue == '' :\r
47fea6af
YZ
52 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
53 "Invalid PCD format(Name: %s File: %s line: %s) , no Value specified!" % (self.PcdCName, self.FileName, self.Lineno))\r
54\r
111be80f 55 if self.PcdOffset == '' :\r
47fea6af
YZ
56 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
57 "Invalid PCD format(Name: %s File: %s Line: %s) , no Offset specified!" % (self.PcdCName, self.FileName, self.Lineno))\r
58\r
111be80f 59 if self.PcdSize == '' :\r
47fea6af
YZ
60 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
61 "Invalid PCD format(Name: %s File: %s Line: %s), no PcdSize specified!" % (self.PcdCName, self.FileName, self.Lineno))\r
62\r
111be80f 63 self._GenOffsetValue ()\r
47fea6af 64\r
d5988a8a 65 ## Analyze the string value to judge the PCD's datum type equal to Boolean or not.\r
08dd311f
LG
66 # \r
67 # @param ValueString PCD's value\r
68 # @param Size PCD's size\r
69 # \r
70 # @retval True PCD's datum type is Boolean\r
71 # @retval False PCD's datum type is not Boolean. \r
72 # \r
73 def _IsBoolean(self, ValueString, Size):\r
74 if (Size == "1"):\r
75 if ValueString.upper() in ["TRUE", "FALSE"]:\r
76 return True\r
77 elif ValueString in ["0", "1", "0x0", "0x1", "0x00", "0x01"]:\r
47fea6af
YZ
78 return True\r
79\r
111be80f 80 return False\r
47fea6af 81\r
08dd311f
LG
82 ## Convert the PCD's value from string to integer.\r
83 # \r
84 # This function will try to convert the Offset value form string to integer\r
85 # for both hexadecimal and decimal.\r
86 # \r
111be80f 87 def _GenOffsetValue(self):\r
88 if self.PcdOffset != "*" :\r
89 try:\r
90 self.PcdBinOffset = int (self.PcdOffset)\r
91 except:\r
92 try:\r
93 self.PcdBinOffset = int(self.PcdOffset, 16)\r
94 except:\r
47fea6af
YZ
95 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
96 "Invalid offset value %s for PCD %s (File: %s Line: %s)" % (self.PcdOffset, self.PcdCName, self.FileName, self.Lineno))\r
97\r
08dd311f
LG
98 ## Pack Boolean type VPD PCD's value form string to binary type.\r
99 # \r
100 # @param ValueString The boolean type string for pack.\r
101 # \r
102 # \r
111be80f 103 def _PackBooleanValue(self, ValueString):\r
08dd311f 104 if ValueString.upper() == "TRUE" or ValueString in ["1", "0x1", "0x01"]:\r
47fea6af
YZ
105 try:\r
106 self.PcdValue = pack(_FORMAT_CHAR[1], 1)\r
111be80f 107 except:\r
47fea6af
YZ
108 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
109 "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno))\r
111be80f 110 else:\r
111 try:\r
47fea6af 112 self.PcdValue = pack(_FORMAT_CHAR[1], 0)\r
111be80f 113 except:\r
47fea6af
YZ
114 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
115 "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno))\r
116\r
08dd311f
LG
117 ## Pack Integer type VPD PCD's value form string to binary type.\r
118 # \r
119 # @param ValueString The Integer type string for pack.\r
120 # \r
121 # \r
111be80f 122 def _PackIntValue(self, IntValue, Size):\r
9eb87141 123 if Size not in _FORMAT_CHAR:\r
47fea6af
YZ
124 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
125 "Invalid size %d for PCD %s in integer datum size(File: %s Line: %s)." % (Size, self.PcdCName, self.FileName, self.Lineno))\r
126\r
127 if Size == 1:\r
08dd311f 128 if IntValue < 0:\r
47fea6af 129 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
08dd311f
LG
130 "PCD can't be set to negative value %d for PCD %s in UINT8 datum type(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno))\r
131 elif IntValue >= 0x100:\r
47fea6af
YZ
132 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
133 "Too large PCD value %d for datum type UINT8 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno))\r
08dd311f
LG
134 elif Size == 2:\r
135 if IntValue < 0:\r
47fea6af 136 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
08dd311f
LG
137 "PCD can't be set to negative value %d for PCD %s in UINT16 datum type(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno))\r
138 elif IntValue >= 0x10000:\r
47fea6af
YZ
139 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
140 "Too large PCD value %d for datum type UINT16 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno))\r
08dd311f
LG
141 elif Size == 4:\r
142 if IntValue < 0:\r
47fea6af 143 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
08dd311f
LG
144 "PCD can't be set to negative value %d for PCD %s in UINT32 datum type(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno))\r
145 elif IntValue >= 0x100000000:\r
47fea6af 146 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
08dd311f
LG
147 "Too large PCD value %d for datum type UINT32 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno))\r
148 elif Size == 8:\r
149 if IntValue < 0:\r
47fea6af 150 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
08dd311f
LG
151 "PCD can't be set to negative value %d for PCD %s in UINT32 datum type(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno))\r
152 elif IntValue >= 0x10000000000000000:\r
47fea6af 153 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
08dd311f
LG
154 "Too large PCD value %d for datum type UINT32 for PCD %s(File: %s Line: %s)." % (IntValue, self.PcdCName, self.FileName, self.Lineno))\r
155 else:\r
47fea6af
YZ
156 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
157 "Invalid size %d for PCD %s in integer datum size(File: %s Line: %s)." % (Size, self.PcdCName, self.FileName, self.Lineno))\r
158\r
111be80f 159 try:\r
47fea6af 160 self.PcdValue = pack(_FORMAT_CHAR[Size], IntValue)\r
111be80f 161 except:\r
47fea6af
YZ
162 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
163 "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno))\r
08dd311f
LG
164\r
165 ## Pack VOID* type VPD PCD's value form string to binary type.\r
166 #\r
167 # The VOID* type of string divided into 3 sub-type:\r
d5988a8a
YZ
168 # 1: L"String"/L'String', Unicode type string.\r
169 # 2: "String"/'String', Ascii type string.\r
08dd311f
LG
170 # 3: {bytearray}, only support byte-array.\r
171 #\r
172 # @param ValueString The Integer type string for pack.\r
173 # \r
111be80f 174 def _PackPtrValue(self, ValueString, Size):\r
d5988a8a 175 if ValueString.startswith('L"') or ValueString.startswith("L'"):\r
111be80f 176 self._PackUnicode(ValueString, Size)\r
177 elif ValueString.startswith('{') and ValueString.endswith('}'):\r
178 self._PackByteArray(ValueString, Size)\r
d5988a8a 179 elif (ValueString.startswith('"') and ValueString.endswith('"')) or (ValueString.startswith("'") and ValueString.endswith("'")):\r
111be80f 180 self._PackString(ValueString, Size)\r
181 else:\r
47fea6af
YZ
182 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
183 "Invalid VOID* type PCD %s value %s (File: %s Line: %s)" % (self.PcdCName, ValueString, self.FileName, self.Lineno))\r
184\r
08dd311f
LG
185 ## Pack an Ascii PCD value.\r
186 # \r
d5988a8a 187 # An Ascii string for a PCD should be in format as ""/''.\r
08dd311f 188 # \r
111be80f 189 def _PackString(self, ValueString, Size):\r
190 if (Size < 0):\r
47fea6af 191 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
111be80f 192 "Invalid parameter Size %s of PCD %s!(File: %s Line: %s)" % (self.PcdBinSize, self.PcdCName, self.FileName, self.Lineno))\r
193 if (ValueString == ""):\r
47fea6af 194 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter ValueString %s of PCD %s!(File: %s Line: %s)" % (self.PcdUnpackValue, self.PcdCName, self.FileName, self.Lineno))\r
d5988a8a
YZ
195\r
196 QuotedFlag = True\r
197 if ValueString.startswith("'"):\r
198 QuotedFlag = False\r
47fea6af 199\r
111be80f 200 ValueString = ValueString[1:-1]\r
d5988a8a
YZ
201 # No null-terminator in 'string' \r
202 if (QuotedFlag and len(ValueString) + 1 > Size) or (not QuotedFlag and len(ValueString) > Size):\r
47fea6af 203 EdkLogger.error("BPDG", BuildToolError.RESOURCE_OVERFLOW,\r
111be80f 204 "PCD value string %s is exceed to size %d(File: %s Line: %s)" % (ValueString, Size, self.FileName, self.Lineno))\r
205 try:\r
47fea6af 206 self.PcdValue = pack('%ds' % Size, ValueString)\r
111be80f 207 except:\r
47fea6af
YZ
208 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
209 "Invalid size or value for PCD %s to pack(File: %s Line: %s)." % (self.PcdCName, self.FileName, self.Lineno))\r
210\r
08dd311f
LG
211 ## Pack a byte-array PCD value.\r
212 # \r
213 # A byte-array for a PCD should be in format as {0x01, 0x02, ...}.\r
214 # \r
111be80f 215 def _PackByteArray(self, ValueString, Size):\r
47fea6af 216 if (Size < 0):\r
111be80f 217 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter Size %s of PCD %s!(File: %s Line: %s)" % (self.PcdBinSize, self.PcdCName, self.FileName, self.Lineno))\r
218 if (ValueString == ""):\r
47fea6af
YZ
219 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter ValueString %s of PCD %s!(File: %s Line: %s)" % (self.PcdUnpackValue, self.PcdCName, self.FileName, self.Lineno))\r
220\r
111be80f 221 ValueString = ValueString.strip()\r
222 ValueString = ValueString.lstrip('{').strip('}')\r
223 ValueList = ValueString.split(',')\r
224 ValueList = [item.strip() for item in ValueList]\r
47fea6af 225\r
111be80f 226 if len(ValueList) > Size:\r
47fea6af 227 EdkLogger.error("BPDG", BuildToolError.RESOURCE_OVERFLOW,\r
111be80f 228 "The byte array %s is too large for size %d(File: %s Line: %s)" % (ValueString, Size, self.FileName, self.Lineno))\r
47fea6af 229\r
111be80f 230 ReturnArray = array.array('B')\r
47fea6af 231\r
111be80f 232 for Index in xrange(len(ValueList)):\r
233 Value = None\r
25918452 234 if ValueList[Index].lower().startswith('0x'):\r
111be80f 235 # translate hex value\r
236 try:\r
237 Value = int(ValueList[Index], 16)\r
238 except:\r
47fea6af 239 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
111be80f 240 "The value item %s in byte array %s is an invalid HEX value.(File: %s Line: %s)" % \\r
241 (ValueList[Index], ValueString, self.FileName, self.Lineno))\r
242 else:\r
243 # translate decimal value\r
244 try:\r
245 Value = int(ValueList[Index], 10)\r
246 except:\r
247 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
248 "The value item %s in byte array %s is an invalid DECIMAL value.(File: %s Line: %s)" % \\r
249 (ValueList[Index], ValueString, self.FileName, self.Lineno))\r
47fea6af 250\r
111be80f 251 if Value > 255:\r
47fea6af
YZ
252 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
253 "The value item %s in byte array %s do not in range 0 ~ 0xFF(File: %s Line: %s)" % \\r
111be80f 254 (ValueList[Index], ValueString, self.FileName, self.Lineno))\r
47fea6af 255\r
111be80f 256 ReturnArray.append(Value)\r
47fea6af 257\r
111be80f 258 for Index in xrange(len(ValueList), Size):\r
259 ReturnArray.append(0)\r
47fea6af
YZ
260\r
261 self.PcdValue = ReturnArray.tolist()\r
111be80f 262\r
263 ## Pack a unicode PCD value into byte array.\r
264 # \r
d5988a8a 265 # A unicode string for a PCD should be in format as L""/L''.\r
111be80f 266 #\r
267 def _PackUnicode(self, UnicodeString, Size):\r
47fea6af
YZ
268 if (Size < 0):\r
269 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid parameter Size %s of PCD %s!(File: %s Line: %s)" % \\r
111be80f 270 (self.PcdBinSize, self.PcdCName, self.FileName, self.Lineno))\r
47fea6af 271\r
d5988a8a
YZ
272 QuotedFlag = True\r
273 if UnicodeString.startswith("L'"):\r
274 QuotedFlag = False \r
111be80f 275 UnicodeString = UnicodeString[2:-1]\r
47fea6af 276\r
d5988a8a
YZ
277 # No null-terminator in L'string'\r
278 if (QuotedFlag and (len(UnicodeString) + 1) * 2 > Size) or (not QuotedFlag and len(UnicodeString) * 2 > Size):\r
111be80f 279 EdkLogger.error("BPDG", BuildToolError.RESOURCE_OVERFLOW,\r
280 "The size of unicode string %s is too larger for size %s(File: %s Line: %s)" % \\r
281 (UnicodeString, Size, self.FileName, self.Lineno))\r
47fea6af 282\r
111be80f 283 ReturnArray = array.array('B')\r
284 for Value in UnicodeString:\r
285 try:\r
286 ReturnArray.append(ord(Value))\r
287 ReturnArray.append(0)\r
288 except:\r
47fea6af 289 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID,\r
111be80f 290 "Invalid unicode character %s in unicode string %s(File: %s Line: %s)" % \\r
291 (Value, UnicodeString, self.FileName, self.Lineno))\r
47fea6af 292\r
e8a47801 293 for Index in xrange(len(UnicodeString) * 2, Size):\r
111be80f 294 ReturnArray.append(0)\r
47fea6af
YZ
295\r
296 self.PcdValue = ReturnArray.tolist()\r
08dd311f
LG
297\r
298\r
299\r
300## The class implementing the BPDG VPD PCD offset fix process\r
301#\r
302# The VPD PCD offset fix process includes:\r
303# 1. Parse the input guided.txt file and store it in the data structure;\r
304# 2. Format the input file data to remove unused lines;\r
305# 3. Fixed offset if needed;\r
306# 4. Generate output file, including guided.map and guided.bin file;\r
307# \r
47fea6af 308class GenVPD :\r
111be80f 309 ## Constructor of DscBuildData\r
310 #\r
311 # Initialize object of GenVPD\r
312 # @Param InputFileName The filename include the vpd type pcd information\r
313 # @param MapFileName The filename of map file that stores vpd type pcd information.\r
314 # This file will be generated by the BPDG tool after fix the offset\r
315 # and adjust the offset to make the pcd data aligned.\r
316 # @param VpdFileName The filename of Vpd file that hold vpd pcd information.\r
317 #\r
318 def __init__(self, InputFileName, MapFileName, VpdFileName):\r
319 self.InputFileName = InputFileName\r
320 self.MapFileName = MapFileName\r
321 self.VpdFileName = VpdFileName\r
322 self.FileLinesList = []\r
323 self.PcdFixedOffsetSizeList = []\r
324 self.PcdUnknownOffsetList = []\r
325 try:\r
326 fInputfile = open(InputFileName, "r", 0)\r
327 try:\r
328 self.FileLinesList = fInputfile.readlines()\r
329 except:\r
47fea6af 330 EdkLogger.error("BPDG", BuildToolError.FILE_READ_FAILURE, "File read failed for %s" % InputFileName, None)\r
111be80f 331 finally:\r
332 fInputfile.close()\r
333 except:\r
47fea6af
YZ
334 EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" % InputFileName, None)\r
335\r
111be80f 336 ##\r
337 # Parser the input file which is generated by the build tool. Convert the value of each pcd's \r
338 # from string to it's real format. Also remove the useless line in the input file.\r
339 # \r
340 def ParserInputFile (self):\r
47fea6af 341 count = 0\r
111be80f 342 for line in self.FileLinesList:\r
343 # Strip "\r\n" generated by readlines ().\r
344 line = line.strip()\r
345 line = line.rstrip(os.linesep)\r
47fea6af 346\r
111be80f 347 # Skip the comment line\r
6780eef1
LG
348 if (not line.startswith("#")) and len(line) > 1 :\r
349 #\r
350 # Enhanced for support "|" character in the string.\r
351 #\r
ccaa7754 352 ValueList = ['', '', '', '', '']\r
47fea6af
YZ
353\r
354 ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$')\r
6780eef1 355 PtrValue = ValueRe.findall(line)\r
47fea6af 356\r
6780eef1 357 ValueUpdateFlag = False\r
47fea6af 358\r
6780eef1
LG
359 if len(PtrValue) >= 1:\r
360 line = re.sub(ValueRe, '', line)\r
47fea6af
YZ
361 ValueUpdateFlag = True\r
362\r
6780eef1
LG
363 TokenList = line.split('|')\r
364 ValueList[0:len(TokenList)] = TokenList\r
47fea6af 365\r
6780eef1 366 if ValueUpdateFlag:\r
22061fab 367 ValueList[4] = PtrValue[0]\r
6780eef1 368 self.FileLinesList[count] = ValueList\r
111be80f 369 # Store the line number\r
47fea6af 370 self.FileLinesList[count].append(str(count + 1))\r
111be80f 371 elif len(line) <= 1 :\r
372 # Set the blank line to "None"\r
373 self.FileLinesList[count] = None\r
374 else :\r
375 # Set the comment line to "None"\r
376 self.FileLinesList[count] = None\r
377 count += 1\r
47fea6af 378\r
111be80f 379 # The line count contain usage information\r
47fea6af 380 count = 0\r
111be80f 381 # Delete useless lines\r
382 while (True) :\r
383 try :\r
4231a819 384 if (self.FileLinesList[count] is None) :\r
111be80f 385 del(self.FileLinesList[count])\r
386 else :\r
387 count += 1\r
388 except :\r
47fea6af 389 break\r
111be80f 390 #\r
391 # After remove the useless line, if there are no data remain in the file line list,\r
392 # Report warning messages to user's.\r
393 # \r
394 if len(self.FileLinesList) == 0 :\r
47fea6af 395 EdkLogger.warn('BPDG', BuildToolError.RESOURCE_NOT_AVAILABLE,\r
111be80f 396 "There are no VPD type pcds defined in DSC file, Please check it.")\r
47fea6af 397\r
111be80f 398 # Process the pcds one by one base on the pcd's value and size\r
399 count = 0\r
47fea6af 400 for line in self.FileLinesList:\r
4231a819 401 if line is not None :\r
ccaa7754 402 PCD = PcdEntry(line[0], line[1], line[2], line[3], line[4], line[5], self.InputFileName)\r
111be80f 403 # Strip the space char\r
404 PCD.PcdCName = PCD.PcdCName.strip(' ')\r
e8a47801 405 PCD.SkuId = PCD.SkuId.strip(' ')\r
111be80f 406 PCD.PcdOffset = PCD.PcdOffset.strip(' ')\r
407 PCD.PcdSize = PCD.PcdSize.strip(' ')\r
22061fab 408 PCD.PcdValue = PCD.PcdValue.strip(' ')\r
111be80f 409 PCD.Lineno = PCD.Lineno.strip(' ')\r
22061fab 410\r
111be80f 411 #\r
412 # Store the original pcd value.\r
413 # This information will be useful while generate the output map file.\r
414 #\r
22061fab
YZ
415 PCD.PcdUnpackValue = str(PCD.PcdValue)\r
416\r
53c13295
YZ
417 #\r
418 # Translate PCD size string to an integer value.\r
419 PackSize = None\r
420 try:\r
421 PackSize = int(PCD.PcdSize, 10)\r
422 PCD.PcdBinSize = PackSize\r
423 except:\r
424 try:\r
425 PackSize = int(PCD.PcdSize, 16)\r
426 PCD.PcdBinSize = PackSize\r
427 except:\r
428 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "Invalid PCD size value %s at file: %s line: %s" % (PCD.PcdSize, self.InputFileName, PCD.Lineno))\r
429\r
22061fab
YZ
430 #\r
431 # If value is Unicode string (e.g. L""), then use 2-byte alignment\r
432 # If value is byte array (e.g. {}), then use 8-byte alignment\r
433 #\r
53c13295 434 PCD.PcdOccupySize = PCD.PcdBinSize\r
22061fab
YZ
435 if PCD.PcdUnpackValue.startswith("{"):\r
436 Alignment = 8\r
437 elif PCD.PcdUnpackValue.startswith("L"):\r
438 Alignment = 2\r
439 else:\r
440 Alignment = 1\r
815ada26 441\r
86737681 442 PCD.Alignment = Alignment\r
815ada26
YZ
443 if PCD.PcdOffset != '*':\r
444 if PCD.PcdOccupySize % Alignment != 0:\r
445 if PCD.PcdUnpackValue.startswith("{"):\r
446 EdkLogger.warn("BPDG", "The offset value of PCD %s is not 8-byte aligned!" %(PCD.PcdCName), File=self.InputFileName)\r
447 else:\r
448 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, 'The offset value of PCD %s should be %s-byte aligned.' % (PCD.PcdCName, Alignment))\r
449 else:\r
450 if PCD.PcdOccupySize % Alignment != 0:\r
451 PCD.PcdOccupySize = (PCD.PcdOccupySize / Alignment + 1) * Alignment\r
111be80f 452\r
86737681 453 PackSize = PCD.PcdOccupySize\r
08dd311f 454 if PCD._IsBoolean(PCD.PcdValue, PCD.PcdSize):\r
111be80f 455 PCD._PackBooleanValue(PCD.PcdValue)\r
456 self.FileLinesList[count] = PCD\r
457 count += 1\r
458 continue\r
459 #\r
460 # Try to translate value to an integer firstly.\r
461 #\r
462 IsInteger = True\r
47fea6af 463 PackValue = None\r
111be80f 464 try:\r
465 PackValue = int(PCD.PcdValue)\r
466 except:\r
467 try:\r
468 PackValue = int(PCD.PcdValue, 16)\r
469 except:\r
470 IsInteger = False\r
47fea6af 471\r
111be80f 472 if IsInteger:\r
473 PCD._PackIntValue(PackValue, PackSize)\r
474 else:\r
475 PCD._PackPtrValue(PCD.PcdValue, PackSize)\r
47fea6af 476\r
111be80f 477 self.FileLinesList[count] = PCD\r
478 count += 1\r
479 else :\r
480 continue\r
47fea6af 481\r
111be80f 482 ##\r
483 # This function used to create a clean list only contain useful information and reorganized to make it \r
484 # easy to be sorted\r
485 #\r
486 def FormatFileLine (self) :\r
47fea6af 487\r
111be80f 488 for eachPcd in self.FileLinesList :\r
489 if eachPcd.PcdOffset != '*' :\r
490 # Use pcd's Offset value as key, and pcd's Value as value \r
491 self.PcdFixedOffsetSizeList.append(eachPcd)\r
492 else :\r
493 # Use pcd's CName as key, and pcd's Size as value\r
494 self.PcdUnknownOffsetList.append(eachPcd)\r
47fea6af
YZ
495\r
496\r
111be80f 497 ##\r
498 # This function is use to fix the offset value which the not specified in the map file.\r
499 # Usually it use the star (meaning any offset) character in the offset field\r
500 # \r
47fea6af 501 def FixVpdOffset (self):\r
111be80f 502 # At first, the offset should start at 0\r
503 # Sort fixed offset list in order to find out where has free spaces for the pcd's offset\r
504 # value is "*" to insert into. \r
47fea6af
YZ
505\r
506 self.PcdFixedOffsetSizeList.sort(lambda x, y: cmp(x.PcdBinOffset, y.PcdBinOffset))\r
507\r
111be80f 508 #\r
509 # Sort the un-fixed pcd's offset by it's size.\r
510 #\r
47fea6af
YZ
511 self.PcdUnknownOffsetList.sort(lambda x, y: cmp(x.PcdBinSize, y.PcdBinSize))\r
512\r
0b6c5954
LG
513 index =0\r
514 for pcd in self.PcdUnknownOffsetList:\r
515 index += 1\r
ccaa7754 516 if pcd.PcdCName == ".".join(("gEfiMdeModulePkgTokenSpaceGuid", "PcdNvStoreDefaultValueBuffer")):\r
0b6c5954
LG
517 if index != len(self.PcdUnknownOffsetList):\r
518 for i in range(len(self.PcdUnknownOffsetList) - index):\r
ccaa7754 519 self.PcdUnknownOffsetList[index+i -1 ], self.PcdUnknownOffsetList[index+i] = self.PcdUnknownOffsetList[index+i], self.PcdUnknownOffsetList[index+i -1]\r
0b6c5954 520\r
111be80f 521 #\r
522 # Process all Offset value are "*"\r
523 #\r
524 if (len(self.PcdFixedOffsetSizeList) == 0) and (len(self.PcdUnknownOffsetList) != 0) :\r
525 # The offset start from 0\r
526 NowOffset = 0\r
47fea6af 527 for Pcd in self.PcdUnknownOffsetList :\r
86737681
YZ
528 if NowOffset % Pcd.Alignment != 0:\r
529 NowOffset = (NowOffset/ Pcd.Alignment + 1) * Pcd.Alignment\r
111be80f 530 Pcd.PcdBinOffset = NowOffset\r
531 Pcd.PcdOffset = str(hex(Pcd.PcdBinOffset))\r
22061fab 532 NowOffset += Pcd.PcdOccupySize\r
111be80f 533 \r
534 self.PcdFixedOffsetSizeList = self.PcdUnknownOffsetList\r
535 return\r
47fea6af 536\r
111be80f 537 # Check the offset of VPD type pcd's offset start from 0. \r
47fea6af 538 if self.PcdFixedOffsetSizeList[0].PcdBinOffset != 0 :\r
111be80f 539 EdkLogger.warn("BPDG", "The offset of VPD type pcd should start with 0, please check it.",\r
47fea6af
YZ
540 None)\r
541\r
111be80f 542 # Judge whether the offset in fixed pcd offset list is overlapped or not.\r
543 lenOfList = len(self.PcdFixedOffsetSizeList)\r
544 count = 0 \r
545 while (count < lenOfList - 1) :\r
546 PcdNow = self.PcdFixedOffsetSizeList[count]\r
547 PcdNext = self.PcdFixedOffsetSizeList[count+1]\r
548 # Two pcd's offset is same \r
549 if PcdNow.PcdBinOffset == PcdNext.PcdBinOffset :\r
47fea6af
YZ
550 EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE,\r
551 "The offset of %s at line: %s is same with %s at line: %s in file %s" % \\r
111be80f 552 (PcdNow.PcdCName, PcdNow.Lineno, PcdNext.PcdCName, PcdNext.Lineno, PcdNext.FileName),\r
553 None)\r
47fea6af 554\r
111be80f 555 # Overlapped \r
22061fab 556 if PcdNow.PcdBinOffset + PcdNow.PcdOccupySize > PcdNext.PcdBinOffset :\r
47fea6af
YZ
557 EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE,\r
558 "The offset of %s at line: %s is overlapped with %s at line: %s in file %s" % \\r
111be80f 559 (PcdNow.PcdCName, PcdNow.Lineno, PcdNext.PcdCName, PcdNext.Lineno, PcdNext.FileName),\r
560 None)\r
47fea6af 561\r
111be80f 562 # Has free space, raise a warning message \r
22061fab 563 if PcdNow.PcdBinOffset + PcdNow.PcdOccupySize < PcdNext.PcdBinOffset :\r
47fea6af
YZ
564 EdkLogger.warn("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE,\r
565 "The offsets have free space of between %s at line: %s and %s at line: %s in file %s" % \\r
111be80f 566 (PcdNow.PcdCName, PcdNow.Lineno, PcdNext.PcdCName, PcdNext.Lineno, PcdNext.FileName),\r
567 None)\r
568 count += 1\r
569 \r
570 LastOffset = self.PcdFixedOffsetSizeList[0].PcdBinOffset\r
571 FixOffsetSizeListCount = 0\r
572 lenOfList = len(self.PcdFixedOffsetSizeList)\r
573 lenOfUnfixedList = len(self.PcdUnknownOffsetList)\r
574 \r
575 ##\r
576 # Insert the un-fixed offset pcd's list into fixed offset pcd's list if has free space between those pcds. \r
577 # \r
578 while (FixOffsetSizeListCount < lenOfList) :\r
579 \r
580 eachFixedPcd = self.PcdFixedOffsetSizeList[FixOffsetSizeListCount] \r
581 NowOffset = eachFixedPcd.PcdBinOffset\r
582 \r
583 # Has free space \r
584 if LastOffset < NowOffset :\r
585 if lenOfUnfixedList != 0 :\r
586 countOfUnfixedList = 0\r
47fea6af 587 while(countOfUnfixedList < lenOfUnfixedList) :\r
111be80f 588 eachUnfixedPcd = self.PcdUnknownOffsetList[countOfUnfixedList]\r
22061fab 589 needFixPcdSize = eachUnfixedPcd.PcdOccupySize\r
111be80f 590 # Not been fixed\r
591 if eachUnfixedPcd.PcdOffset == '*' :\r
86737681
YZ
592 if LastOffset % eachUnfixedPcd.Alignment != 0:\r
593 LastOffset = (LastOffset / eachUnfixedPcd.Alignment + 1) * eachUnfixedPcd.Alignment\r
111be80f 594 # The offset un-fixed pcd can write into this free space\r
595 if needFixPcdSize <= (NowOffset - LastOffset) :\r
596 # Change the offset value of un-fixed pcd\r
597 eachUnfixedPcd.PcdOffset = str(hex(LastOffset))\r
598 eachUnfixedPcd.PcdBinOffset = LastOffset\r
599 # Insert this pcd into fixed offset pcd list.\r
ccaa7754 600 self.PcdFixedOffsetSizeList.insert(FixOffsetSizeListCount, eachUnfixedPcd)\r
111be80f 601 \r
602 # Delete the item's offset that has been fixed and added into fixed offset list\r
603 self.PcdUnknownOffsetList.pop(countOfUnfixedList)\r
604 \r
605 # After item added, should enlarge the length of fixed pcd offset list\r
606 lenOfList += 1 \r
607 FixOffsetSizeListCount += 1\r
608 \r
609 # Decrease the un-fixed pcd offset list's length\r
111be80f 610 lenOfUnfixedList -= 1\r
611 \r
612 # Modify the last offset value \r
6780eef1 613 LastOffset += needFixPcdSize \r
111be80f 614 else :\r
6780eef1 615 # It can not insert into those two pcds, need to check still has other space can store it.\r
22061fab 616 LastOffset = NowOffset + self.PcdFixedOffsetSizeList[FixOffsetSizeListCount].PcdOccupySize\r
111be80f 617 FixOffsetSizeListCount += 1\r
6780eef1
LG
618 break\r
619 \r
111be80f 620 # Set the FixOffsetSizeListCount = lenOfList for quit the loop\r
621 else :\r
622 FixOffsetSizeListCount = lenOfList \r
623 \r
624 # No free space, smoothly connect with previous pcd. \r
625 elif LastOffset == NowOffset :\r
22061fab 626 LastOffset = NowOffset + eachFixedPcd.PcdOccupySize\r
111be80f 627 FixOffsetSizeListCount += 1\r
628 # Usually it will not enter into this thunk, if so, means it overlapped. \r
629 else :\r
47fea6af
YZ
630 EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_NOT_AVAILABLE,\r
631 "The offset value definition has overlapped at pcd: %s, it's offset is: %s, in file: %s line: %s" % \\r
111be80f 632 (eachFixedPcd.PcdCName, eachFixedPcd.PcdOffset, eachFixedPcd.InputFileName, eachFixedPcd.Lineno),\r
633 None)\r
634 FixOffsetSizeListCount += 1\r
635 \r
636 # Continue to process the un-fixed offset pcd's list, add this time, just append them behind the fixed pcd's offset list. \r
637 lenOfUnfixedList = len(self.PcdUnknownOffsetList)\r
638 lenOfList = len(self.PcdFixedOffsetSizeList)\r
639 while (lenOfUnfixedList > 0) :\r
640 # Still has items need to process\r
641 # The last pcd instance\r
642 LastPcd = self.PcdFixedOffsetSizeList[lenOfList-1]\r
643 NeedFixPcd = self.PcdUnknownOffsetList[0]\r
644 \r
22061fab 645 NeedFixPcd.PcdBinOffset = LastPcd.PcdBinOffset + LastPcd.PcdOccupySize\r
86737681
YZ
646 if NeedFixPcd.PcdBinOffset % NeedFixPcd.Alignment != 0:\r
647 NeedFixPcd.PcdBinOffset = (NeedFixPcd.PcdBinOffset / NeedFixPcd.Alignment + 1) * NeedFixPcd.Alignment\r
648\r
111be80f 649 NeedFixPcd.PcdOffset = str(hex(NeedFixPcd.PcdBinOffset))\r
650 \r
651 # Insert this pcd into fixed offset pcd list's tail.\r
652 self.PcdFixedOffsetSizeList.insert(lenOfList, NeedFixPcd)\r
653 # Delete the item's offset that has been fixed and added into fixed offset list\r
654 self.PcdUnknownOffsetList.pop(0)\r
655 \r
656 lenOfList += 1\r
657 lenOfUnfixedList -= 1 \r
658 ##\r
659 # Write the final data into output files.\r
660 # \r
661 def GenerateVpdFile (self, MapFileName, BinFileName):\r
662 #Open an VPD file to process\r
663\r
664 try:\r
47fea6af 665 fVpdFile = open(BinFileName, "wb", 0)\r
111be80f 666 except:\r
667 # Open failed\r
47fea6af
YZ
668 EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" % self.VpdFileName, None)\r
669\r
111be80f 670 try :\r
47fea6af 671 fMapFile = open(MapFileName, "w", 0)\r
111be80f 672 except:\r
673 # Open failed\r
47fea6af
YZ
674 EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" % self.MapFileName, None)\r
675\r
86379ac4
GL
676 # Use a instance of BytesIO to cache data\r
677 fStringIO = BytesIO('')\r
47fea6af 678\r
111be80f 679 # Write the header of map file.\r
680 try :\r
681 fMapFile.write (st.MAP_FILE_COMMENT_TEMPLATE + "\n")\r
682 except:\r
47fea6af
YZ
683 EdkLogger.error("BPDG", BuildToolError.FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." % self.MapFileName, None)\r
684\r
111be80f 685 for eachPcd in self.PcdFixedOffsetSizeList :\r
686 # write map file\r
687 try :\r
ccaa7754 688 fMapFile.write("%s | %s | %s | %s | %s \n" % (eachPcd.PcdCName, eachPcd.SkuId, eachPcd.PcdOffset, eachPcd.PcdSize, eachPcd.PcdUnpackValue))\r
111be80f 689 except:\r
47fea6af
YZ
690 EdkLogger.error("BPDG", BuildToolError.FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." % self.MapFileName, None)\r
691\r
111be80f 692 # Write Vpd binary file\r
47fea6af 693 fStringIO.seek (eachPcd.PcdBinOffset)\r
111be80f 694 if isinstance(eachPcd.PcdValue, list):\r
695 ValueList = [chr(Item) for Item in eachPcd.PcdValue]\r
47fea6af
YZ
696 fStringIO.write(''.join(ValueList))\r
697 else:\r
111be80f 698 fStringIO.write (eachPcd.PcdValue)\r
47fea6af
YZ
699\r
700 try :\r
111be80f 701 fVpdFile.write (fStringIO.getvalue())\r
702 except:\r
47fea6af
YZ
703 EdkLogger.error("BPDG", BuildToolError.FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." % self.VpdFileName, None)\r
704\r
111be80f 705 fStringIO.close ()\r
706 fVpdFile.close ()\r
707 fMapFile.close ()\r
708 \r