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