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