• 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 - 2014, 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                if PCD._IsBoolean(PCD.PcdValue, PCD.PcdSize):
426                    PCD._PackBooleanValue(PCD.PcdValue)
427                    self.FileLinesList[count] = PCD
428                    count += 1
429                    continue
430                #
431                # Try to translate value to an integer firstly.
432                #
433                IsInteger = True
434                PackValue = None
435                try:
436                    PackValue = int(PCD.PcdValue)
437                except:
438                    try:
439                        PackValue = int(PCD.PcdValue, 16)
440                    except:
441                        IsInteger = False
442
443                if IsInteger:
444                    PCD._PackIntValue(PackValue, PackSize)
445                else:
446                    PCD._PackPtrValue(PCD.PcdValue, PackSize)
447
448                self.FileLinesList[count] = PCD
449                count += 1
450            else :
451                continue
452
453    ##
454    # This function used to create a clean list only contain useful information and reorganized to make it
455    # easy to be sorted
456    #
457    def FormatFileLine (self) :
458
459        for eachPcd in self.FileLinesList :
460            if eachPcd.PcdOffset != '*' :
461                # Use pcd's Offset value as key, and pcd's Value as value
462                self.PcdFixedOffsetSizeList.append(eachPcd)
463            else :
464                # Use pcd's CName as key, and pcd's Size as value
465                self.PcdUnknownOffsetList.append(eachPcd)
466
467
468    ##
469    # This function is use to fix the offset value which the not specified in the map file.
470    # Usually it use the star (meaning any offset) character in the offset field
471    #
472    def FixVpdOffset (self):
473        # At first, the offset should start at 0
474        # Sort fixed offset list in order to find out where has free spaces for the pcd's offset
475        # value is "*" to insert into.
476
477        self.PcdFixedOffsetSizeList.sort(lambda x, y: cmp(x.PcdBinOffset, y.PcdBinOffset))
478
479        #
480        # Sort the un-fixed pcd's offset by it's size.
481        #
482        self.PcdUnknownOffsetList.sort(lambda x, y: cmp(x.PcdBinSize, y.PcdBinSize))
483
484        #
485        # Process all Offset value are "*"
486        #
487        if (len(self.PcdFixedOffsetSizeList) == 0) and (len(self.PcdUnknownOffsetList) != 0) :
488            # The offset start from 0
489            NowOffset = 0
490            for Pcd in self.PcdUnknownOffsetList :
491                Pcd.PcdBinOffset = NowOffset
492                Pcd.PcdOffset    = str(hex(Pcd.PcdBinOffset))
493                NowOffset       += Pcd.PcdBinSize
494
495            self.PcdFixedOffsetSizeList = self.PcdUnknownOffsetList
496            return
497
498        # Check the offset of VPD type pcd's offset start from 0.
499        if self.PcdFixedOffsetSizeList[0].PcdBinOffset != 0 :
500            EdkLogger.warn("BPDG", "The offset of VPD type pcd should start with 0, please check it.",
501                            None)
502
503        # Judge whether the offset in fixed pcd offset list is overlapped or not.
504        lenOfList = len(self.PcdFixedOffsetSizeList)
505        count     = 0
506        while (count < lenOfList - 1) :
507            PcdNow  = self.PcdFixedOffsetSizeList[count]
508            PcdNext = self.PcdFixedOffsetSizeList[count+1]
509            # Two pcd's offset is same
510            if PcdNow.PcdBinOffset == PcdNext.PcdBinOffset :
511                EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE,
512                                "The offset of %s at line: %s is same with %s at line: %s in file %s" % \
513                                (PcdNow.PcdCName, PcdNow.Lineno, PcdNext.PcdCName, PcdNext.Lineno, PcdNext.FileName),
514                                None)
515
516            # Overlapped
517            if PcdNow.PcdBinOffset + PcdNow.PcdBinSize > PcdNext.PcdBinOffset :
518                EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE,
519                                "The offset of %s at line: %s is overlapped with %s at line: %s in file %s" % \
520                                (PcdNow.PcdCName, PcdNow.Lineno, PcdNext.PcdCName, PcdNext.Lineno, PcdNext.FileName),
521                                None)
522
523            # Has free space, raise a warning message
524            if PcdNow.PcdBinOffset + PcdNow.PcdBinSize < PcdNext.PcdBinOffset :
525                EdkLogger.warn("BPDG", BuildToolError.ATTRIBUTE_GET_FAILURE,
526                               "The offsets have free space of between %s at line: %s and %s at line: %s in file %s" % \
527                               (PcdNow.PcdCName, PcdNow.Lineno, PcdNext.PcdCName, PcdNext.Lineno, PcdNext.FileName),
528                                None)
529            count += 1
530
531        LastOffset              = self.PcdFixedOffsetSizeList[0].PcdBinOffset
532        FixOffsetSizeListCount  = 0
533        lenOfList               = len(self.PcdFixedOffsetSizeList)
534        lenOfUnfixedList        = len(self.PcdUnknownOffsetList)
535
536        ##
537        # Insert the un-fixed offset pcd's list into fixed offset pcd's list if has free space between those pcds.
538        #
539        while (FixOffsetSizeListCount < lenOfList) :
540
541            eachFixedPcd     = self.PcdFixedOffsetSizeList[FixOffsetSizeListCount]
542            NowOffset        = eachFixedPcd.PcdBinOffset
543
544            # Has free space
545            if LastOffset < NowOffset :
546                if lenOfUnfixedList != 0 :
547                    countOfUnfixedList = 0
548                    while(countOfUnfixedList < lenOfUnfixedList) :
549                        eachUnfixedPcd      = self.PcdUnknownOffsetList[countOfUnfixedList]
550                        needFixPcdSize      = eachUnfixedPcd.PcdBinSize
551                        # Not been fixed
552                        if eachUnfixedPcd.PcdOffset == '*' :
553                            # The offset un-fixed pcd can write into this free space
554                            if needFixPcdSize <= (NowOffset - LastOffset) :
555                                # Change the offset value of un-fixed pcd
556                                eachUnfixedPcd.PcdOffset    = str(hex(LastOffset))
557                                eachUnfixedPcd.PcdBinOffset = LastOffset
558                                # Insert this pcd into fixed offset pcd list.
559                                self.PcdFixedOffsetSizeList.insert(FixOffsetSizeListCount,eachUnfixedPcd)
560
561                                # Delete the item's offset that has been fixed and added into fixed offset list
562                                self.PcdUnknownOffsetList.pop(countOfUnfixedList)
563
564                                # After item added, should enlarge the length of fixed pcd offset list
565                                lenOfList               += 1
566                                FixOffsetSizeListCount  += 1
567
568                                # Decrease the un-fixed pcd offset list's length
569                                lenOfUnfixedList        -= 1
570
571                                # Modify the last offset value
572                                LastOffset              += needFixPcdSize
573                            else :
574                                # It can not insert into those two pcds, need to check still has other space can store it.
575                                LastOffset             = NowOffset + self.PcdFixedOffsetSizeList[FixOffsetSizeListCount].PcdBinSize
576                                FixOffsetSizeListCount += 1
577                                break
578
579                # Set the FixOffsetSizeListCount = lenOfList for quit the loop
580                else :
581                    FixOffsetSizeListCount = lenOfList
582
583            # No free space, smoothly connect with previous pcd.
584            elif LastOffset == NowOffset :
585                LastOffset = NowOffset + eachFixedPcd.PcdBinSize
586                FixOffsetSizeListCount += 1
587            # Usually it will not enter into this thunk, if so, means it overlapped.
588            else :
589                EdkLogger.error("BPDG", BuildToolError.ATTRIBUTE_NOT_AVAILABLE,
590                                "The offset value definition has overlapped at pcd: %s, it's offset is: %s, in file: %s line: %s" % \
591                                (eachFixedPcd.PcdCName, eachFixedPcd.PcdOffset, eachFixedPcd.InputFileName, eachFixedPcd.Lineno),
592                                None)
593                FixOffsetSizeListCount += 1
594
595        # Continue to process the un-fixed offset pcd's list, add this time, just append them behind the fixed pcd's offset list.
596        lenOfUnfixedList  = len(self.PcdUnknownOffsetList)
597        lenOfList         = len(self.PcdFixedOffsetSizeList)
598        while (lenOfUnfixedList > 0) :
599            # Still has items need to process
600            # The last pcd instance
601            LastPcd    = self.PcdFixedOffsetSizeList[lenOfList-1]
602            NeedFixPcd = self.PcdUnknownOffsetList[0]
603
604            NeedFixPcd.PcdBinOffset = LastPcd.PcdBinOffset + LastPcd.PcdBinSize
605            NeedFixPcd.PcdOffset    = str(hex(NeedFixPcd.PcdBinOffset))
606
607            # Insert this pcd into fixed offset pcd list's tail.
608            self.PcdFixedOffsetSizeList.insert(lenOfList, NeedFixPcd)
609            # Delete the item's offset that has been fixed and added into fixed offset list
610            self.PcdUnknownOffsetList.pop(0)
611
612            lenOfList          += 1
613            lenOfUnfixedList   -= 1
614    ##
615    # Write the final data into output files.
616    #
617    def GenerateVpdFile (self, MapFileName, BinFileName):
618        #Open an VPD file to process
619
620        try:
621            fVpdFile = open(BinFileName, "wb", 0)
622        except:
623            # Open failed
624            EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" % self.VpdFileName, None)
625
626        try :
627            fMapFile = open(MapFileName, "w", 0)
628        except:
629            # Open failed
630            EdkLogger.error("BPDG", BuildToolError.FILE_OPEN_FAILURE, "File open failed for %s" % self.MapFileName, None)
631
632        # Use a instance of StringIO to cache data
633        fStringIO = StringIO.StringIO('')
634
635        # Write the header of map file.
636        try :
637            fMapFile.write (st.MAP_FILE_COMMENT_TEMPLATE + "\n")
638        except:
639            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)
640
641        for eachPcd in self.PcdFixedOffsetSizeList  :
642            # write map file
643            try :
644                fMapFile.write("%s | %s | %s | %s | %s  \n" % (eachPcd.PcdCName, eachPcd.SkuId,eachPcd.PcdOffset, eachPcd.PcdSize,eachPcd.PcdUnpackValue))
645            except:
646                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)
647
648            # Write Vpd binary file
649            fStringIO.seek (eachPcd.PcdBinOffset)
650            if isinstance(eachPcd.PcdValue, list):
651                ValueList = [chr(Item) for Item in eachPcd.PcdValue]
652                fStringIO.write(''.join(ValueList))
653            else:
654                fStringIO.write (eachPcd.PcdValue)
655
656        try :
657            fVpdFile.write (fStringIO.getvalue())
658        except:
659            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)
660
661        fStringIO.close ()
662        fVpdFile.close ()
663        fMapFile.close ()
664
665