]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/BuildReport.py
ff632b6759b2303c608875579a78e2537e45ce86
[mirror_edk2.git] / BaseTools / Source / Python / build / BuildReport.py
1 ## @file
2 # Routines for generating build report.
3 #
4 # This module contains the functionality to generate build report after
5 # build all target completes successfully.
6 #
7 # Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
8 # This program and the accompanying materials
9 # are licensed and made available under the terms and conditions of the BSD License
10 # which accompanies this distribution. The full text of the license may be found at
11 # http://opensource.org/licenses/bsd-license.php
12 #
13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #
16
17 ## Import Modules
18 #
19 import Common.LongFilePathOs as os
20 import re
21 import platform
22 import textwrap
23 import traceback
24 import sys
25 import time
26 import struct
27 import hashlib
28 import subprocess
29 import threading
30 from datetime import datetime
31 from io import BytesIO
32 from Common import EdkLogger
33 from Common.Misc import SaveFileOnChange
34 from Common.Misc import GuidStructureByteArrayToGuidString
35 from Common.Misc import GuidStructureStringToGuidString
36 from Common.BuildToolError import FILE_WRITE_FAILURE
37 from Common.BuildToolError import CODE_ERROR
38 from Common.BuildToolError import COMMAND_FAILURE
39 from Common.BuildToolError import FORMAT_INVALID
40 from Common.LongFilePathSupport import OpenLongFilePath as open
41 from Common.MultipleWorkspace import MultipleWorkspace as mws
42 import Common.GlobalData as GlobalData
43 from AutoGen.AutoGen import ModuleAutoGen
44 from Common.Misc import PathClass
45 from Common.StringUtils import NormPath
46 from Common.DataType import *
47 import collections
48 from Common.Expression import *
49 from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID
50
51 ## Pattern to extract contents in EDK DXS files
52 gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)
53
54 ## Pattern to find total FV total size, occupied size in flash report intermediate file
55 gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
56 gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
57
58 ## Pattern to find module size and time stamp in module summary report intermediate file
59 gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")
60 gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")
61
62 ## Pattern to find GUID value in flash description files
63 gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")
64
65 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
66 gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
67
68 ## Pattern to find module base address and entry point in fixed flash map file
69 gModulePattern = r"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
70 gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
71
72 ## Pattern to find all module referenced header files in source files
73 gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')
74 gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
75
76 ## Pattern to find the entry point for EDK module using EDKII Glue library
77 gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
78
79 ## Tags for MaxLength of line in report
80 gLineMaxLength = 120
81
82 ## Tags for end of line in report
83 gEndOfLine = "\r\n"
84
85 ## Tags for section start, end and separator
86 gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<"
87 gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n"
88 gSectionSep = "=" * gLineMaxLength
89
90 ## Tags for subsection start, end and separator
91 gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<"
92 gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">"
93 gSubSectionSep = "-" * gLineMaxLength
94
95
96 ## The look up table to map PCD type to pair of report display type and DEC type
97 gPcdTypeMap = {
98 TAB_PCDS_FIXED_AT_BUILD : ('FIXED', TAB_PCDS_FIXED_AT_BUILD),
99 TAB_PCDS_PATCHABLE_IN_MODULE: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE),
100 TAB_PCDS_FEATURE_FLAG : ('FLAG', TAB_PCDS_FEATURE_FLAG),
101 TAB_PCDS_DYNAMIC : ('DYN', TAB_PCDS_DYNAMIC),
102 TAB_PCDS_DYNAMIC_HII : ('DYNHII', TAB_PCDS_DYNAMIC),
103 TAB_PCDS_DYNAMIC_VPD : ('DYNVPD', TAB_PCDS_DYNAMIC),
104 TAB_PCDS_DYNAMIC_EX : ('DEX', TAB_PCDS_DYNAMIC_EX),
105 TAB_PCDS_DYNAMIC_EX_HII : ('DEXHII', TAB_PCDS_DYNAMIC_EX),
106 TAB_PCDS_DYNAMIC_EX_VPD : ('DEXVPD', TAB_PCDS_DYNAMIC_EX),
107 }
108
109 ## The look up table to map module type to driver type
110 gDriverTypeMap = {
111 SUP_MODULE_SEC : '0x3 (SECURITY_CORE)',
112 SUP_MODULE_PEI_CORE : '0x4 (PEI_CORE)',
113 SUP_MODULE_PEIM : '0x6 (PEIM)',
114 SUP_MODULE_DXE_CORE : '0x5 (DXE_CORE)',
115 SUP_MODULE_DXE_DRIVER : '0x7 (DRIVER)',
116 SUP_MODULE_DXE_SAL_DRIVER : '0x7 (DRIVER)',
117 SUP_MODULE_DXE_SMM_DRIVER : '0x7 (DRIVER)',
118 SUP_MODULE_DXE_RUNTIME_DRIVER: '0x7 (DRIVER)',
119 SUP_MODULE_UEFI_DRIVER : '0x7 (DRIVER)',
120 SUP_MODULE_UEFI_APPLICATION : '0x9 (APPLICATION)',
121 SUP_MODULE_SMM_CORE : '0xD (SMM_CORE)',
122 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
123 SUP_MODULE_MM_STANDALONE : '0xE (MM_STANDALONE)',
124 SUP_MODULE_MM_CORE_STANDALONE : '0xF (MM_CORE_STANDALONE)'
125 }
126
127 ## The look up table of the supported opcode in the dependency expression binaries
128 gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
129
130 ## Save VPD Pcd
131 VPDPcdList = []
132
133 ##
134 # Writes a string to the file object.
135 #
136 # This function writes a string to the file object and a new line is appended
137 # afterwards. It may optionally wraps the string for better readability.
138 #
139 # @File The file object to write
140 # @String The string to be written to the file
141 # @Wrapper Indicates whether to wrap the string
142 #
143 def FileWrite(File, String, Wrapper=False):
144 if Wrapper:
145 String = textwrap.fill(String, 120)
146 File.write(String + gEndOfLine)
147
148 def ByteArrayForamt(Value):
149 IsByteArray = False
150 SplitNum = 16
151 ArrayList = []
152 if Value.startswith('{') and Value.endswith('}'):
153 Value = Value[1:-1]
154 ValueList = Value.split(',')
155 if len(ValueList) >= SplitNum:
156 IsByteArray = True
157 if IsByteArray:
158 if ValueList:
159 Len = len(ValueList)/SplitNum
160 for i, element in enumerate(ValueList):
161 ValueList[i] = '0x%02X' % int(element.strip(), 16)
162 if Len:
163 Id = 0
164 while (Id <= Len):
165 End = min(SplitNum*(Id+1), len(ValueList))
166 Str = ','.join(ValueList[SplitNum*Id : End])
167 if End == len(ValueList):
168 Str += '}'
169 ArrayList.append(Str)
170 break
171 else:
172 Str += ','
173 ArrayList.append(Str)
174 Id += 1
175 else:
176 ArrayList = [Value + '}']
177 return IsByteArray, ArrayList
178
179 ##
180 # Find all the header file that the module source directly includes.
181 #
182 # This function scans source code to find all header files the module may
183 # include. This is not accurate but very effective to find all the header
184 # file the module might include with #include statement.
185 #
186 # @Source The source file name
187 # @IncludePathList The list of include path to find the source file.
188 # @IncludeFiles The dictionary of current found include files.
189 #
190 def FindIncludeFiles(Source, IncludePathList, IncludeFiles):
191 FileContents = open(Source).read()
192 #
193 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
194 #
195 for Match in gIncludePattern.finditer(FileContents):
196 FileName = Match.group(1).strip()
197 for Dir in [os.path.dirname(Source)] + IncludePathList:
198 FullFileName = os.path.normpath(os.path.join(Dir, FileName))
199 if os.path.exists(FullFileName):
200 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
201 break
202
203 #
204 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
205 #
206 for Match in gIncludePattern2.finditer(FileContents):
207 Key = Match.group(2)
208 Type = Match.group(1)
209 if "ARCH_PROTOCOL" in Type:
210 FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
211 elif "PROTOCOL" in Type:
212 FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
213 elif "PPI" in Type:
214 FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}
215 elif TAB_GUID in Type:
216 FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}
217 else:
218 continue
219 for Dir in IncludePathList:
220 FullFileName = os.path.normpath(os.path.join(Dir, FileName))
221 if os.path.exists(FullFileName):
222 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
223 break
224
225 ## Split each lines in file
226 #
227 # This method is used to split the lines in file to make the length of each line
228 # less than MaxLength.
229 #
230 # @param Content The content of file
231 # @param MaxLength The Max Length of the line
232 #
233 def FileLinesSplit(Content=None, MaxLength=None):
234 ContentList = Content.split(TAB_LINE_BREAK)
235 NewContent = ''
236 NewContentList = []
237 for Line in ContentList:
238 while len(Line.rstrip()) > MaxLength:
239 LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)
240 LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)
241 LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)
242 if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:
243 LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)
244 else:
245 LineBreakIndex = MaxLength
246 NewContentList.append(Line[:LineBreakIndex])
247 Line = Line[LineBreakIndex:]
248 if Line:
249 NewContentList.append(Line)
250 for NewLine in NewContentList:
251 NewContent += NewLine + TAB_LINE_BREAK
252
253 NewContent = NewContent.replace(gEndOfLine, TAB_LINE_BREAK).replace('\r\r\n', gEndOfLine)
254 return NewContent
255
256
257
258 ##
259 # Parse binary dependency expression section
260 #
261 # This utility class parses the dependency expression section and translate the readable
262 # GUID name and value.
263 #
264 class DepexParser(object):
265 ##
266 # Constructor function for class DepexParser
267 #
268 # This constructor function collect GUID values so that the readable
269 # GUID name can be translated.
270 #
271 # @param self The object pointer
272 # @param Wa Workspace context information
273 #
274 def __init__(self, Wa):
275 self._GuidDb = {}
276 for Pa in Wa.AutoGenObjectList:
277 for Package in Pa.PackageList:
278 for Protocol in Package.Protocols:
279 GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])
280 self._GuidDb[GuidValue.upper()] = Protocol
281 for Ppi in Package.Ppis:
282 GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])
283 self._GuidDb[GuidValue.upper()] = Ppi
284 for Guid in Package.Guids:
285 GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])
286 self._GuidDb[GuidValue.upper()] = Guid
287 for Ma in Pa.ModuleAutoGenList:
288 for Pcd in Ma.FixedVoidTypePcds:
289 PcdValue = Ma.FixedVoidTypePcds[Pcd]
290 if len(PcdValue.split(',')) == 16:
291 GuidValue = GuidStructureByteArrayToGuidString(PcdValue)
292 self._GuidDb[GuidValue.upper()] = Pcd
293 ##
294 # Parse the binary dependency expression files.
295 #
296 # This function parses the binary dependency expression file and translate it
297 # to the instruction list.
298 #
299 # @param self The object pointer
300 # @param DepexFileName The file name of binary dependency expression file.
301 #
302 def ParseDepexFile(self, DepexFileName):
303 DepexFile = open(DepexFileName, "rb")
304 DepexStatement = []
305 OpCode = DepexFile.read(1)
306 while OpCode:
307 Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]
308 if Statement in ["BEFORE", "AFTER", "PUSH"]:
309 GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
310 struct.unpack(PACK_PATTERN_GUID, DepexFile.read(16))
311 GuidString = self._GuidDb.get(GuidValue, GuidValue)
312 Statement = "%s %s" % (Statement, GuidString)
313 DepexStatement.append(Statement)
314 OpCode = DepexFile.read(1)
315
316 return DepexStatement
317
318 ##
319 # Reports library information
320 #
321 # This class reports the module library subsection in the build report file.
322 #
323 class LibraryReport(object):
324 ##
325 # Constructor function for class LibraryReport
326 #
327 # This constructor function generates LibraryReport object for
328 # a module.
329 #
330 # @param self The object pointer
331 # @param M Module context information
332 #
333 def __init__(self, M):
334 self.LibraryList = []
335
336 for Lib in M.DependentLibraryList:
337 LibInfPath = str(Lib)
338 LibClassList = Lib.LibraryClass[0].LibraryClass
339 LibConstructorList = Lib.ConstructorList
340 LibDesstructorList = Lib.DestructorList
341 LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]
342 for LibAutoGen in M.LibraryAutoGenList:
343 if LibInfPath == LibAutoGen.MetaFile.Path:
344 LibTime = LibAutoGen.BuildTime
345 break
346 self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList, LibTime))
347
348 ##
349 # Generate report for module library information
350 #
351 # This function generates report for the module library.
352 # If the module is EDKII style one, the additional library class, library
353 # constructor/destructor and dependency expression may also be reported.
354 #
355 # @param self The object pointer
356 # @param File The file object for report
357 #
358 def GenerateReport(self, File):
359 if len(self.LibraryList) > 0:
360 FileWrite(File, gSubSectionStart)
361 FileWrite(File, TAB_BRG_LIBRARY)
362 FileWrite(File, gSubSectionSep)
363 for LibraryItem in self.LibraryList:
364 LibInfPath = LibraryItem[0]
365 FileWrite(File, LibInfPath)
366
367 LibClass = LibraryItem[1]
368 EdkIILibInfo = ""
369 LibConstructor = " ".join(LibraryItem[2])
370 if LibConstructor:
371 EdkIILibInfo += " C = " + LibConstructor
372 LibDestructor = " ".join(LibraryItem[3])
373 if LibDestructor:
374 EdkIILibInfo += " D = " + LibDestructor
375 LibDepex = " ".join(LibraryItem[4])
376 if LibDepex:
377 EdkIILibInfo += " Depex = " + LibDepex
378 if LibraryItem[5]:
379 EdkIILibInfo += " Time = " + LibraryItem[5]
380 if EdkIILibInfo:
381 FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))
382 else:
383 FileWrite(File, "{%s}" % LibClass)
384
385 FileWrite(File, gSubSectionEnd)
386
387 ##
388 # Reports dependency expression information
389 #
390 # This class reports the module dependency expression subsection in the build report file.
391 #
392 class DepexReport(object):
393 ##
394 # Constructor function for class DepexReport
395 #
396 # This constructor function generates DepexReport object for
397 # a module. If the module source contains the DXS file (usually EDK
398 # style module), it uses the dependency in DXS file; otherwise,
399 # it uses the dependency expression from its own INF [Depex] section
400 # and then merges with the ones from its dependent library INF.
401 #
402 # @param self The object pointer
403 # @param M Module context information
404 #
405 def __init__(self, M):
406 self.Depex = ""
407 self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex")
408 ModuleType = M.ModuleType
409 if not ModuleType:
410 ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")
411
412 if ModuleType in [SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_DXE_CORE, SUP_MODULE_SMM_CORE, SUP_MODULE_MM_CORE_STANDALONE, SUP_MODULE_UEFI_APPLICATION]:
413 return
414
415 for Source in M.SourceFileList:
416 if os.path.splitext(Source.Path)[1].lower() == ".dxs":
417 Match = gDxsDependencyPattern.search(open(Source.Path).read())
418 if Match:
419 self.Depex = Match.group(1).strip()
420 self.Source = "DXS"
421 break
422 else:
423 self.Depex = M.DepexExpressionDict.get(M.ModuleType, "")
424 self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])
425 if not self.ModuleDepex:
426 self.ModuleDepex = "(None)"
427
428 LibDepexList = []
429 for Lib in M.DependentLibraryList:
430 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()
431 if LibDepex != "":
432 LibDepexList.append("(" + LibDepex + ")")
433 self.LibraryDepex = " AND ".join(LibDepexList)
434 if not self.LibraryDepex:
435 self.LibraryDepex = "(None)"
436 self.Source = "INF"
437
438 ##
439 # Generate report for module dependency expression information
440 #
441 # This function generates report for the module dependency expression.
442 #
443 # @param self The object pointer
444 # @param File The file object for report
445 # @param GlobalDepexParser The platform global Dependency expression parser object
446 #
447 def GenerateReport(self, File, GlobalDepexParser):
448 if not self.Depex:
449 return
450 FileWrite(File, gSubSectionStart)
451 if os.path.isfile(self._DepexFileName):
452 try:
453 DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)
454 FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")
455 for DepexStatement in DepexStatements:
456 FileWrite(File, " %s" % DepexStatement)
457 FileWrite(File, gSubSectionSep)
458 except:
459 EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)
460
461 FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)
462
463 if self.Source == "INF":
464 FileWrite(File, self.Depex, True)
465 FileWrite(File, gSubSectionSep)
466 FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)
467 FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)
468 else:
469 FileWrite(File, self.Depex)
470 FileWrite(File, gSubSectionEnd)
471
472 ##
473 # Reports dependency expression information
474 #
475 # This class reports the module build flags subsection in the build report file.
476 #
477 class BuildFlagsReport(object):
478 ##
479 # Constructor function for class BuildFlagsReport
480 #
481 # This constructor function generates BuildFlagsReport object for
482 # a module. It reports the build tool chain tag and all relevant
483 # build flags to build the module.
484 #
485 # @param self The object pointer
486 # @param M Module context information
487 #
488 def __init__(self, M):
489 BuildOptions = {}
490 #
491 # Add build flags according to source file extension so that
492 # irrelevant ones can be filtered out.
493 #
494 for Source in M.SourceFileList:
495 Ext = os.path.splitext(Source.File)[1].lower()
496 if Ext in [".c", ".cc", ".cpp"]:
497 BuildOptions["CC"] = 1
498 elif Ext in [".s", ".asm"]:
499 BuildOptions["PP"] = 1
500 BuildOptions["ASM"] = 1
501 elif Ext in [".vfr"]:
502 BuildOptions["VFRPP"] = 1
503 BuildOptions["VFR"] = 1
504 elif Ext in [".dxs"]:
505 BuildOptions["APP"] = 1
506 BuildOptions["CC"] = 1
507 elif Ext in [".asl"]:
508 BuildOptions["ASLPP"] = 1
509 BuildOptions["ASL"] = 1
510 elif Ext in [".aslc"]:
511 BuildOptions["ASLCC"] = 1
512 BuildOptions["ASLDLINK"] = 1
513 BuildOptions["CC"] = 1
514 elif Ext in [".asm16"]:
515 BuildOptions["ASMLINK"] = 1
516 BuildOptions["SLINK"] = 1
517 BuildOptions["DLINK"] = 1
518
519 #
520 # Save module build flags.
521 #
522 self.ToolChainTag = M.ToolChain
523 self.BuildFlags = {}
524 for Tool in BuildOptions:
525 self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")
526
527 ##
528 # Generate report for module build flags information
529 #
530 # This function generates report for the module build flags expression.
531 #
532 # @param self The object pointer
533 # @param File The file object for report
534 #
535 def GenerateReport(self, File):
536 FileWrite(File, gSubSectionStart)
537 FileWrite(File, "Build Flags")
538 FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)
539 for Tool in self.BuildFlags:
540 FileWrite(File, gSubSectionSep)
541 FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)
542
543 FileWrite(File, gSubSectionEnd)
544
545
546 ##
547 # Reports individual module information
548 #
549 # This class reports the module section in the build report file.
550 # It comprises of module summary, module PCD, library, dependency expression,
551 # build flags sections.
552 #
553 class ModuleReport(object):
554 ##
555 # Constructor function for class ModuleReport
556 #
557 # This constructor function generates ModuleReport object for
558 # a separate module in a platform build.
559 #
560 # @param self The object pointer
561 # @param M Module context information
562 # @param ReportType The kind of report items in the final report file
563 #
564 def __init__(self, M, ReportType):
565 self.ModuleName = M.Module.BaseName
566 self.ModuleInfPath = M.MetaFile.File
567 self.FileGuid = M.Guid
568 self.Size = 0
569 self.BuildTimeStamp = None
570 self.Hash = 0
571 self.DriverType = ""
572 if not M.IsLibrary:
573 ModuleType = M.ModuleType
574 if not ModuleType:
575 ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")
576 #
577 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
578 #
579 if ModuleType == SUP_MODULE_DXE_SMM_DRIVER:
580 PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")
581 if int(PiSpec, 0) >= 0x0001000A:
582 ModuleType = "SMM_DRIVER"
583 self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")
584 self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")
585 self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")
586 self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")
587 self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")
588 self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")
589 self.BuildTime = M.BuildTime
590
591 self._BuildDir = M.BuildDir
592 self.ModulePcdSet = {}
593 if "PCD" in ReportType:
594 #
595 # Collect all module used PCD set: module INF referenced directly or indirectly.
596 # It also saves module INF default values of them in case they exist.
597 #
598 for Pcd in M.ModulePcdList + M.LibraryPcdList:
599 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))
600
601 self.LibraryReport = None
602 if "LIBRARY" in ReportType:
603 self.LibraryReport = LibraryReport(M)
604
605 self.DepexReport = None
606 if "DEPEX" in ReportType:
607 self.DepexReport = DepexReport(M)
608
609 if "BUILD_FLAGS" in ReportType:
610 self.BuildFlagsReport = BuildFlagsReport(M)
611
612
613 ##
614 # Generate report for module information
615 #
616 # This function generates report for separate module expression
617 # in a platform build.
618 #
619 # @param self The object pointer
620 # @param File The file object for report
621 # @param GlobalPcdReport The platform global PCD report object
622 # @param GlobalPredictionReport The platform global Prediction report object
623 # @param GlobalDepexParser The platform global Dependency expression parser object
624 # @param ReportType The kind of report items in the final report file
625 #
626 def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType):
627 FileWrite(File, gSectionStart)
628
629 FwReportFileName = os.path.join(self._BuildDir, "DEBUG", self.ModuleName + ".txt")
630 if os.path.isfile(FwReportFileName):
631 try:
632 FileContents = open(FwReportFileName).read()
633 Match = gModuleSizePattern.search(FileContents)
634 if Match:
635 self.Size = int(Match.group(1))
636
637 Match = gTimeStampPattern.search(FileContents)
638 if Match:
639 self.BuildTimeStamp = datetime.fromtimestamp(int(Match.group(1)))
640 except IOError:
641 EdkLogger.warn(None, "Fail to read report file", FwReportFileName)
642
643 if "HASH" in ReportType:
644 OutputDir = os.path.join(self._BuildDir, "OUTPUT")
645 DefaultEFIfile = os.path.join(OutputDir, self.ModuleName + ".efi")
646 if os.path.isfile(DefaultEFIfile):
647 Tempfile = os.path.join(OutputDir, self.ModuleName + "_hash.tmp")
648 # rebase the efi image since its base address may not zero
649 cmd = ["GenFw", "--rebase", str(0), "-o", Tempfile, DefaultEFIfile]
650 try:
651 PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
652 except Exception as X:
653 EdkLogger.error("GenFw", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))
654 EndOfProcedure = threading.Event()
655 EndOfProcedure.clear()
656 if PopenObject.stderr:
657 StdErrThread = threading.Thread(target=ReadMessage, args=(PopenObject.stderr, EdkLogger.quiet, EndOfProcedure))
658 StdErrThread.setName("STDERR-Redirector")
659 StdErrThread.setDaemon(False)
660 StdErrThread.start()
661 # waiting for program exit
662 PopenObject.wait()
663 if PopenObject.stderr:
664 StdErrThread.join()
665 if PopenObject.returncode != 0:
666 EdkLogger.error("GenFw", COMMAND_FAILURE, "Failed to generate firmware hash image for %s" % (DefaultEFIfile))
667 if os.path.isfile(Tempfile):
668 self.Hash = hashlib.sha1()
669 buf = open(Tempfile, 'rb').read()
670 if self.Hash.update(buf):
671 self.Hash = self.Hash.update(buf)
672 self.Hash = self.Hash.hexdigest()
673 os.remove(Tempfile)
674
675 FileWrite(File, "Module Summary")
676 FileWrite(File, "Module Name: %s" % self.ModuleName)
677 FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)
678 FileWrite(File, "File GUID: %s" % self.FileGuid)
679 if self.Size:
680 FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))
681 if self.Hash:
682 FileWrite(File, "SHA1 HASH: %s *%s" % (self.Hash, self.ModuleName + ".efi"))
683 if self.BuildTimeStamp:
684 FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)
685 if self.BuildTime:
686 FileWrite(File, "Module Build Time: %s" % self.BuildTime)
687 if self.DriverType:
688 FileWrite(File, "Driver Type: %s" % self.DriverType)
689 if self.UefiSpecVersion:
690 FileWrite(File, "UEFI Spec Version: %s" % self.UefiSpecVersion)
691 if self.PiSpecVersion:
692 FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)
693 if self.PciDeviceId:
694 FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)
695 if self.PciVendorId:
696 FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)
697 if self.PciClassCode:
698 FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)
699
700 FileWrite(File, gSectionSep)
701
702 if "PCD" in ReportType:
703 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet)
704
705 if "LIBRARY" in ReportType:
706 self.LibraryReport.GenerateReport(File)
707
708 if "DEPEX" in ReportType:
709 self.DepexReport.GenerateReport(File, GlobalDepexParser)
710
711 if "BUILD_FLAGS" in ReportType:
712 self.BuildFlagsReport.GenerateReport(File)
713
714 if "FIXED_ADDRESS" in ReportType and self.FileGuid:
715 GlobalPredictionReport.GenerateReport(File, self.FileGuid)
716
717 FileWrite(File, gSectionEnd)
718
719 def ReadMessage(From, To, ExitFlag):
720 while True:
721 # read one line a time
722 Line = From.readline()
723 # empty string means "end"
724 if Line is not None and Line != "":
725 To(Line.rstrip())
726 else:
727 break
728 if ExitFlag.isSet():
729 break
730
731 ##
732 # Reports platform and module PCD information
733 #
734 # This class reports the platform PCD section and module PCD subsection
735 # in the build report file.
736 #
737 class PcdReport(object):
738 ##
739 # Constructor function for class PcdReport
740 #
741 # This constructor function generates PcdReport object a platform build.
742 # It collects the whole PCD database from platform DSC files, platform
743 # flash description file and package DEC files.
744 #
745 # @param self The object pointer
746 # @param Wa Workspace context information
747 #
748 def __init__(self, Wa):
749 self.AllPcds = {}
750 self.UnusedPcds = {}
751 self.ConditionalPcds = {}
752 self.MaxLen = 0
753 self.Arch = None
754 if Wa.FdfProfile:
755 self.FdfPcdSet = Wa.FdfProfile.PcdDict
756 else:
757 self.FdfPcdSet = {}
758
759 self.DefaultStoreSingle = True
760 self.SkuSingle = True
761 if GlobalData.gDefaultStores and len(GlobalData.gDefaultStores) > 1:
762 self.DefaultStoreSingle = False
763 if GlobalData.gSkuids and len(GlobalData.gSkuids) > 1:
764 self.SkuSingle = False
765
766 self.ModulePcdOverride = {}
767 for Pa in Wa.AutoGenObjectList:
768 self.Arch = Pa.Arch
769 #
770 # Collect all platform referenced PCDs and grouped them by PCD token space
771 # GUID C Names
772 #
773 for Pcd in Pa.AllPcdList:
774 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
775 if Pcd not in PcdList:
776 PcdList.append(Pcd)
777 if len(Pcd.TokenCName) > self.MaxLen:
778 self.MaxLen = len(Pcd.TokenCName)
779 #
780 # Collect the PCD defined in DSC/FDF file, but not used in module
781 #
782 UnusedPcdFullList = []
783 for item in Pa.Platform.Pcds:
784 Pcd = Pa.Platform.Pcds[item]
785 if not Pcd.Type:
786 # check the Pcd in FDF file, whether it is used in module first
787 for T in PCD_TYPE_LIST:
788 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(T, [])
789 if Pcd in PcdList:
790 Pcd.Type = T
791 break
792 if not Pcd.Type:
793 PcdTypeFlag = False
794 for package in Pa.PackageList:
795 for T in PCD_TYPE_LIST:
796 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T) in package.Pcds:
797 Pcd.Type = T
798 PcdTypeFlag = True
799 if not Pcd.DatumType:
800 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T)].DatumType
801 break
802 if PcdTypeFlag:
803 break
804 if not Pcd.DatumType:
805 PcdType = Pcd.Type
806 # Try to remove Hii and Vpd suffix
807 if PcdType.startswith(TAB_PCDS_DYNAMIC_EX):
808 PcdType = TAB_PCDS_DYNAMIC_EX
809 elif PcdType.startswith(TAB_PCDS_DYNAMIC):
810 PcdType = TAB_PCDS_DYNAMIC
811 for package in Pa.PackageList:
812 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType) in package.Pcds:
813 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType)].DatumType
814 break
815
816 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
817 UnusedPcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
818 if Pcd in UnusedPcdList:
819 UnusedPcdList.remove(Pcd)
820 if Pcd not in PcdList and Pcd not in UnusedPcdFullList:
821 UnusedPcdFullList.append(Pcd)
822 if len(Pcd.TokenCName) > self.MaxLen:
823 self.MaxLen = len(Pcd.TokenCName)
824
825 if GlobalData.gConditionalPcds:
826 for PcdItem in GlobalData.gConditionalPcds:
827 if '.' in PcdItem:
828 (TokenSpaceGuidCName, TokenCName) = PcdItem.split('.')
829 if (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
830 Pcd = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)]
831 PcdList = self.ConditionalPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
832 if Pcd not in PcdList:
833 PcdList.append(Pcd)
834
835 UnusedPcdList = []
836 if UnusedPcdFullList:
837 for Pcd in UnusedPcdFullList:
838 if Pcd.TokenSpaceGuidCName + '.' + Pcd.TokenCName in GlobalData.gConditionalPcds:
839 continue
840 UnusedPcdList.append(Pcd)
841
842 for Pcd in UnusedPcdList:
843 PcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
844 if Pcd not in PcdList:
845 PcdList.append(Pcd)
846
847 for Module in Pa.Platform.Modules.values():
848 #
849 # Collect module override PCDs
850 #
851 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:
852 TokenCName = ModulePcd.TokenCName
853 TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName
854 ModuleDefault = ModulePcd.DefaultValue
855 ModulePath = os.path.basename(Module.M.MetaFile.File)
856 self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), {})[ModulePath] = ModuleDefault
857
858
859 #
860 # Collect PCD DEC default value.
861 #
862 self.DecPcdDefault = {}
863 self._GuidDict = {}
864 for Pa in Wa.AutoGenObjectList:
865 for Package in Pa.PackageList:
866 Guids = Package.Guids
867 self._GuidDict.update(Guids)
868 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
869 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
870 self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)
871 #
872 # Collect PCDs defined in DSC common section
873 #
874 self.DscPcdDefault = {}
875 for Pa in Wa.AutoGenObjectList:
876 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
877 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DscDefaultValue
878 if DscDefaultValue:
879 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
880
881 def GenerateReport(self, File, ModulePcdSet):
882 if not ModulePcdSet:
883 if self.ConditionalPcds:
884 self.GenerateReportDetail(File, ModulePcdSet, 1)
885 if self.UnusedPcds:
886 IsEmpty = True
887 for Token in self.UnusedPcds:
888 TokenDict = self.UnusedPcds[Token]
889 for Type in TokenDict:
890 if TokenDict[Type]:
891 IsEmpty = False
892 break
893 if not IsEmpty:
894 break
895 if not IsEmpty:
896 self.GenerateReportDetail(File, ModulePcdSet, 2)
897 self.GenerateReportDetail(File, ModulePcdSet)
898
899 ##
900 # Generate report for PCD information
901 #
902 # This function generates report for separate module expression
903 # in a platform build.
904 #
905 # @param self The object pointer
906 # @param File The file object for report
907 # @param ModulePcdSet Set of all PCDs referenced by module or None for
908 # platform PCD report
909 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
910 # directives section report, 2 means Unused Pcds section report
911 # @param DscOverridePcds Module DSC override PCDs set
912 #
913 def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0):
914 PcdDict = self.AllPcds
915 if ReportSubType == 1:
916 PcdDict = self.ConditionalPcds
917 elif ReportSubType == 2:
918 PcdDict = self.UnusedPcds
919
920 if not ModulePcdSet:
921 FileWrite(File, gSectionStart)
922 if ReportSubType == 1:
923 FileWrite(File, "Conditional Directives used by the build system")
924 elif ReportSubType == 2:
925 FileWrite(File, "PCDs not used by modules or in conditional directives")
926 else:
927 FileWrite(File, "Platform Configuration Database Report")
928
929 FileWrite(File, " *B - PCD override in the build option")
930 FileWrite(File, " *P - Platform scoped PCD override in DSC file")
931 FileWrite(File, " *F - Platform scoped PCD override in FDF file")
932 if not ReportSubType:
933 FileWrite(File, " *M - Module scoped PCD override")
934 FileWrite(File, gSectionSep)
935 else:
936 if not ReportSubType and ModulePcdSet:
937 #
938 # For module PCD sub-section
939 #
940 FileWrite(File, gSubSectionStart)
941 FileWrite(File, TAB_BRG_PCD)
942 FileWrite(File, gSubSectionSep)
943 AllPcdDict = {}
944 for Key in PcdDict:
945 AllPcdDict[Key] = {}
946 for Type in PcdDict[Key]:
947 for Pcd in PcdDict[Key][Type]:
948 AllPcdDict[Key][(Pcd.TokenCName, Type)] = Pcd
949 for Key in sorted(AllPcdDict):
950 #
951 # Group PCD by their token space GUID C Name
952 #
953 First = True
954 for PcdTokenCName, Type in sorted(AllPcdDict[Key]):
955 #
956 # Group PCD by their usage type
957 #
958 Pcd = AllPcdDict[Key][(PcdTokenCName, Type)]
959 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))
960 MixedPcdFlag = False
961 if GlobalData.MixedPcd:
962 for PcdKey in GlobalData.MixedPcd:
963 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdKey]:
964 PcdTokenCName = PcdKey[0]
965 MixedPcdFlag = True
966 if MixedPcdFlag and not ModulePcdSet:
967 continue
968 #
969 # Get PCD default value and their override relationship
970 #
971 DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))
972 DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
973 DscDefaultValBak = DscDefaultValue
974 Field = ''
975 for (CName, Guid, Field) in self.FdfPcdSet:
976 if CName == PcdTokenCName and Guid == Key:
977 DscDefaultValue = self.FdfPcdSet[(CName, Guid, Field)]
978 break
979 if DscDefaultValue != DscDefaultValBak:
980 try:
981 DscDefaultValue = ValueExpressionEx(DscDefaultValue, Pcd.DatumType, self._GuidDict)(True)
982 except BadExpression as DscDefaultValue:
983 EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" %(DscDefaultValue, Pcd.DatumType))
984
985 InfDefaultValue = None
986
987 PcdValue = DecDefaultValue
988 if DscDefaultValue:
989 PcdValue = DscDefaultValue
990 #The DefaultValue of StructurePcd already be the latest, no need to update.
991 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
992 Pcd.DefaultValue = PcdValue
993 if ModulePcdSet is not None:
994 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:
995 continue
996 InfDefaultValue, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
997 #The DefaultValue of StructurePcd already be the latest, no need to update.
998 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
999 Pcd.DefaultValue = PcdValue
1000 if InfDefaultValue:
1001 try:
1002 InfDefaultValue = ValueExpressionEx(InfDefaultValue, Pcd.DatumType, self._GuidDict)(True)
1003 except BadExpression as InfDefaultValue:
1004 EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" % (InfDefaultValue, Pcd.DatumType))
1005 if InfDefaultValue == "":
1006 InfDefaultValue = None
1007
1008 BuildOptionMatch = False
1009 if GlobalData.BuildOptionPcd:
1010 for pcd in GlobalData.BuildOptionPcd:
1011 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]):
1012 if pcd[2]:
1013 continue
1014 PcdValue = pcd[3]
1015 #The DefaultValue of StructurePcd already be the latest, no need to update.
1016 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
1017 Pcd.DefaultValue = PcdValue
1018 BuildOptionMatch = True
1019 break
1020
1021 if First:
1022 if ModulePcdSet is None:
1023 FileWrite(File, "")
1024 FileWrite(File, Key)
1025 First = False
1026
1027
1028 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
1029 if PcdValue.startswith('0') and not PcdValue.lower().startswith('0x') and len(PcdValue) > 2:
1030 PcdValue = PcdValue.lstrip('0')
1031 PcdValueNumber = int(PcdValue.strip(), 0)
1032 if DecDefaultValue is None:
1033 DecMatch = True
1034 else:
1035 if DecDefaultValue.startswith('0') and not DecDefaultValue.lower().startswith('0x') and len(DecDefaultValue) > 2:
1036 DecDefaultValue = DecDefaultValue.lstrip('0')
1037 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)
1038 DecMatch = (DecDefaultValueNumber == PcdValueNumber)
1039
1040 if InfDefaultValue is None:
1041 InfMatch = True
1042 else:
1043 if InfDefaultValue.startswith('0') and not InfDefaultValue.lower().startswith('0x') and len(InfDefaultValue) > 2:
1044 InfDefaultValue = InfDefaultValue.lstrip('0')
1045 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)
1046 InfMatch = (InfDefaultValueNumber == PcdValueNumber)
1047
1048 if DscDefaultValue is None:
1049 DscMatch = True
1050 else:
1051 if DscDefaultValue.startswith('0') and not DscDefaultValue.lower().startswith('0x') and len(DscDefaultValue) > 2:
1052 DscDefaultValue = DscDefaultValue.lstrip('0')
1053 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)
1054 DscMatch = (DscDefaultValueNumber == PcdValueNumber)
1055 else:
1056 if DecDefaultValue is None:
1057 DecMatch = True
1058 else:
1059 DecMatch = (DecDefaultValue.strip() == PcdValue.strip())
1060
1061 if InfDefaultValue is None:
1062 InfMatch = True
1063 else:
1064 InfMatch = (InfDefaultValue.strip() == PcdValue.strip())
1065
1066 if DscDefaultValue is None:
1067 DscMatch = True
1068 else:
1069 DscMatch = (DscDefaultValue.strip() == PcdValue.strip())
1070
1071 IsStructure = False
1072 if self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
1073 IsStructure = True
1074 if TypeName in ('DYNVPD', 'DEXVPD'):
1075 SkuInfoList = Pcd.SkuInfoList
1076 Pcd = GlobalData.gStructurePcd[self.Arch][(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]
1077 Pcd.DatumType = Pcd.StructName
1078 if TypeName in ('DYNVPD', 'DEXVPD'):
1079 Pcd.SkuInfoList = SkuInfoList
1080 if Pcd.PcdValueFromComm or Pcd.PcdFieldValueFromComm:
1081 BuildOptionMatch = True
1082 DecMatch = False
1083 elif Pcd.PcdValueFromFdf or Pcd.PcdFieldValueFromFdf:
1084 DscDefaultValue = True
1085 DscMatch = True
1086 DecMatch = False
1087 elif Pcd.SkuOverrideValues:
1088 DscOverride = False
1089 if Pcd.DefaultFromDSC:
1090 DscOverride = True
1091 else:
1092 DictLen = 0
1093 for item in Pcd.SkuOverrideValues:
1094 DictLen += len(Pcd.SkuOverrideValues[item])
1095 if not DictLen:
1096 DscOverride = False
1097 else:
1098 if not Pcd.SkuInfoList:
1099 OverrideValues = Pcd.SkuOverrideValues
1100 if OverrideValues:
1101 for Data in OverrideValues.values():
1102 Struct = list(Data.values())
1103 if Struct:
1104 DscOverride = self.ParseStruct(Struct[0])
1105 break
1106 else:
1107 SkuList = sorted(Pcd.SkuInfoList.keys())
1108 for Sku in SkuList:
1109 SkuInfo = Pcd.SkuInfoList[Sku]
1110 if TypeName in ('DYNHII', 'DEXHII'):
1111 if SkuInfo.DefaultStoreDict:
1112 DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())
1113 for DefaultStore in DefaultStoreList:
1114 OverrideValues = Pcd.SkuOverrideValues[Sku]
1115 DscOverride = self.ParseStruct(OverrideValues[DefaultStore])
1116 if DscOverride:
1117 break
1118 else:
1119 OverrideValues = Pcd.SkuOverrideValues[Sku]
1120 if OverrideValues:
1121 Keys = list(OverrideValues.keys())
1122 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[Keys[0]])
1123 DscOverride = self.ParseStruct(OverrideFieldStruct)
1124 if DscOverride:
1125 break
1126 if DscOverride:
1127 DscDefaultValue = True
1128 DscMatch = True
1129 DecMatch = False
1130 else:
1131 DecMatch = True
1132 else:
1133 DscDefaultValue = True
1134 DscMatch = True
1135 DecMatch = False
1136
1137 #
1138 # Report PCD item according to their override relationship
1139 #
1140 if Pcd.DatumType == 'BOOLEAN':
1141 if DscDefaultValue:
1142 DscDefaultValue = str(int(DscDefaultValue, 0))
1143 if DecDefaultValue:
1144 DecDefaultValue = str(int(DecDefaultValue, 0))
1145 if InfDefaultValue:
1146 InfDefaultValue = str(int(InfDefaultValue, 0))
1147 if Pcd.DefaultValue:
1148 Pcd.DefaultValue = str(int(Pcd.DefaultValue, 0))
1149 if DecMatch:
1150 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, ' ')
1151 elif InfDefaultValue and InfMatch:
1152 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')
1153 elif BuildOptionMatch:
1154 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*B')
1155 else:
1156 if DscDefaultValue and DscMatch:
1157 if (Pcd.TokenCName, Key, Field) in self.FdfPcdSet:
1158 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*F')
1159 else:
1160 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*P')
1161 else:
1162 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')
1163
1164 if ModulePcdSet is None:
1165 if IsStructure:
1166 continue
1167 if not TypeName in ('PATCH', 'FLAG', 'FIXED'):
1168 continue
1169 if not BuildOptionMatch:
1170 ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})
1171 for ModulePath in ModuleOverride:
1172 ModuleDefault = ModuleOverride[ModulePath]
1173 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
1174 if ModuleDefault.startswith('0') and not ModuleDefault.lower().startswith('0x') and len(ModuleDefault) > 2:
1175 ModuleDefault = ModuleDefault.lstrip('0')
1176 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)
1177 Match = (ModulePcdDefaultValueNumber == PcdValueNumber)
1178 if Pcd.DatumType == 'BOOLEAN':
1179 ModuleDefault = str(ModulePcdDefaultValueNumber)
1180 else:
1181 Match = (ModuleDefault.strip() == PcdValue.strip())
1182 if Match:
1183 continue
1184 IsByteArray, ArrayList = ByteArrayForamt(ModuleDefault.strip())
1185 if IsByteArray:
1186 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, '{'))
1187 for Array in ArrayList:
1188 FileWrite(File, Array)
1189 else:
1190 Value = ModuleDefault.strip()
1191 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1192 if Value.startswith(('0x', '0X')):
1193 Value = '{} ({:d})'.format(Value, int(Value, 0))
1194 else:
1195 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1196 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, Value))
1197
1198 if ModulePcdSet is None:
1199 FileWrite(File, gSectionEnd)
1200 else:
1201 if not ReportSubType and ModulePcdSet:
1202 FileWrite(File, gSubSectionEnd)
1203
1204 def ParseStruct(self, struct):
1205 HasDscOverride = False
1206 if struct:
1207 for _, Values in struct.items():
1208 for Key, value in Values.items():
1209 if value[1] and value[1].endswith('.dsc'):
1210 HasDscOverride = True
1211 break
1212 if HasDscOverride == True:
1213 break
1214 return HasDscOverride
1215
1216 def PrintPcdDefault(self, File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue):
1217 if not DscMatch and DscDefaultValue is not None:
1218 Value = DscDefaultValue.strip()
1219 IsByteArray, ArrayList = ByteArrayForamt(Value)
1220 if IsByteArray:
1221 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', "{"))
1222 for Array in ArrayList:
1223 FileWrite(File, Array)
1224 else:
1225 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1226 if Value.startswith(('0x', '0X')):
1227 Value = '{} ({:d})'.format(Value, int(Value, 0))
1228 else:
1229 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1230 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', Value))
1231 if not InfMatch and InfDefaultValue is not None:
1232 Value = InfDefaultValue.strip()
1233 IsByteArray, ArrayList = ByteArrayForamt(Value)
1234 if IsByteArray:
1235 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', "{"))
1236 for Array in ArrayList:
1237 FileWrite(File, Array)
1238 else:
1239 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1240 if Value.startswith(('0x', '0X')):
1241 Value = '{} ({:d})'.format(Value, int(Value, 0))
1242 else:
1243 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1244 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', Value))
1245
1246 if not DecMatch and DecDefaultValue is not None:
1247 Value = DecDefaultValue.strip()
1248 IsByteArray, ArrayList = ByteArrayForamt(Value)
1249 if IsByteArray:
1250 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', "{"))
1251 for Array in ArrayList:
1252 FileWrite(File, Array)
1253 else:
1254 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1255 if Value.startswith(('0x', '0X')):
1256 Value = '{} ({:d})'.format(Value, int(Value, 0))
1257 else:
1258 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1259 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', Value))
1260 if IsStructure:
1261 for filedvalues in Pcd.DefaultValues.values():
1262 self.PrintStructureInfo(File, filedvalues)
1263 if DecMatch and IsStructure:
1264 for filedvalues in Pcd.DefaultValues.values():
1265 self.PrintStructureInfo(File, filedvalues)
1266
1267 def PrintPcdValue(self, File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, Flag = ' '):
1268 if not Pcd.SkuInfoList:
1269 Value = Pcd.DefaultValue
1270 IsByteArray, ArrayList = ByteArrayForamt(Value)
1271 if IsByteArray:
1272 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))
1273 for Array in ArrayList:
1274 FileWrite(File, Array)
1275 else:
1276 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1277 if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 2:
1278 Value = Value.lstrip('0')
1279 if Value.startswith(('0x', '0X')):
1280 Value = '{} ({:d})'.format(Value, int(Value, 0))
1281 else:
1282 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1283 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
1284 if IsStructure:
1285 FiledOverrideFlag = False
1286 OverrideValues = Pcd.SkuOverrideValues
1287 if OverrideValues:
1288 for Data in OverrideValues.values():
1289 Struct = list(Data.values())
1290 if Struct:
1291 OverrideFieldStruct = self.OverrideFieldValue(Pcd, Struct[0])
1292 self.PrintStructureInfo(File, OverrideFieldStruct)
1293 FiledOverrideFlag = True
1294 break
1295 if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):
1296 OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})
1297 self.PrintStructureInfo(File, OverrideFieldStruct)
1298 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
1299 else:
1300 FirstPrint = True
1301 SkuList = sorted(Pcd.SkuInfoList.keys())
1302 for Sku in SkuList:
1303 SkuInfo = Pcd.SkuInfoList[Sku]
1304 SkuIdName = SkuInfo.SkuIdName
1305 if TypeName in ('DYNHII', 'DEXHII'):
1306 if SkuInfo.DefaultStoreDict:
1307 DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())
1308 for DefaultStore in DefaultStoreList:
1309 Value = SkuInfo.DefaultStoreDict[DefaultStore]
1310 IsByteArray, ArrayList = ByteArrayForamt(Value)
1311 if Pcd.DatumType == 'BOOLEAN':
1312 Value = str(int(Value, 0))
1313 if FirstPrint:
1314 FirstPrint = False
1315 if IsByteArray:
1316 if self.DefaultStoreSingle and self.SkuSingle:
1317 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))
1318 elif self.DefaultStoreSingle and not self.SkuSingle:
1319 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))
1320 elif not self.DefaultStoreSingle and self.SkuSingle:
1321 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))
1322 else:
1323 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))
1324 for Array in ArrayList:
1325 FileWrite(File, Array)
1326 else:
1327 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1328 if Value.startswith(('0x', '0X')):
1329 Value = '{} ({:d})'.format(Value, int(Value, 0))
1330 else:
1331 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1332 if self.DefaultStoreSingle and self.SkuSingle:
1333 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
1334 elif self.DefaultStoreSingle and not self.SkuSingle:
1335 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
1336 elif not self.DefaultStoreSingle and self.SkuSingle:
1337 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))
1338 else:
1339 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))
1340 else:
1341 if IsByteArray:
1342 if self.DefaultStoreSingle and self.SkuSingle:
1343 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '{'))
1344 elif self.DefaultStoreSingle and not self.SkuSingle:
1345 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))
1346 elif not self.DefaultStoreSingle and self.SkuSingle:
1347 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))
1348 else:
1349 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))
1350 for Array in ArrayList:
1351 FileWrite(File, Array)
1352 else:
1353 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1354 if Value.startswith(('0x', '0X')):
1355 Value = '{} ({:d})'.format(Value, int(Value, 0))
1356 else:
1357 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1358 if self.DefaultStoreSingle and self.SkuSingle:
1359 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))
1360 elif self.DefaultStoreSingle and not self.SkuSingle:
1361 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
1362 elif not self.DefaultStoreSingle and self.SkuSingle:
1363 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))
1364 else:
1365 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))
1366 FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))
1367 if IsStructure:
1368 OverrideValues = Pcd.SkuOverrideValues[Sku]
1369 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[DefaultStore])
1370 self.PrintStructureInfo(File, OverrideFieldStruct)
1371 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
1372 else:
1373 Value = SkuInfo.DefaultValue
1374 IsByteArray, ArrayList = ByteArrayForamt(Value)
1375 if Pcd.DatumType == 'BOOLEAN':
1376 Value = str(int(Value, 0))
1377 if FirstPrint:
1378 FirstPrint = False
1379 if IsByteArray:
1380 if self.SkuSingle:
1381 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', "{"))
1382 else:
1383 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))
1384 for Array in ArrayList:
1385 FileWrite(File, Array)
1386 else:
1387 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1388 if Value.startswith(('0x', '0X')):
1389 Value = '{} ({:d})'.format(Value, int(Value, 0))
1390 else:
1391 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1392 if self.SkuSingle:
1393 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
1394 else:
1395 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
1396 else:
1397 if IsByteArray:
1398 if self.SkuSingle:
1399 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', "{"))
1400 else:
1401 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))
1402 for Array in ArrayList:
1403 FileWrite(File, Array)
1404 else:
1405 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1406 if Value.startswith(('0x', '0X')):
1407 Value = '{} ({:d})'.format(Value, int(Value, 0))
1408 else:
1409 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1410 if self.SkuSingle:
1411 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))
1412 else:
1413 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
1414 if TypeName in ('DYNVPD', 'DEXVPD'):
1415 FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))
1416 VPDPcdItem = (Pcd.TokenSpaceGuidCName + '.' + PcdTokenCName, SkuIdName, SkuInfo.VpdOffset, Pcd.MaxDatumSize, SkuInfo.DefaultValue)
1417 if VPDPcdItem not in VPDPcdList:
1418 VPDPcdList.append(VPDPcdItem)
1419 if IsStructure:
1420 FiledOverrideFlag = False
1421 OverrideValues = Pcd.SkuOverrideValues[Sku]
1422 if OverrideValues:
1423 Keys = OverrideValues.keys()
1424 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[Keys[0]])
1425 self.PrintStructureInfo(File, OverrideFieldStruct)
1426 FiledOverrideFlag = True
1427 if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):
1428 OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})
1429 self.PrintStructureInfo(File, OverrideFieldStruct)
1430 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
1431
1432 def OverrideFieldValue(self, Pcd, OverrideStruct):
1433 OverrideFieldStruct = collections.OrderedDict()
1434 if OverrideStruct:
1435 for _, Values in OverrideStruct.items():
1436 for Key,value in Values.items():
1437 if value[1] and value[1].endswith('.dsc'):
1438 OverrideFieldStruct[Key] = value
1439 if Pcd.PcdFieldValueFromFdf:
1440 for Key, Values in Pcd.PcdFieldValueFromFdf.items():
1441 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
1442 continue
1443 OverrideFieldStruct[Key] = Values
1444 if Pcd.PcdFieldValueFromComm:
1445 for Key, Values in Pcd.PcdFieldValueFromComm.items():
1446 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
1447 continue
1448 OverrideFieldStruct[Key] = Values
1449 return OverrideFieldStruct
1450
1451 def PrintStructureInfo(self, File, Struct):
1452 for Key, Value in sorted(Struct.items(), key=lambda x: x[0]):
1453 if Value[1] and 'build command options' in Value[1]:
1454 FileWrite(File, ' *B %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1455 elif Value[1] and Value[1].endswith('.fdf'):
1456 FileWrite(File, ' *F %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1457 else:
1458 FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1459
1460 def StrtoHex(self, value):
1461 try:
1462 value = hex(int(value))
1463 return value
1464 except:
1465 if value.startswith("L\"") and value.endswith("\""):
1466 valuelist = []
1467 for ch in value[2:-1]:
1468 valuelist.append(hex(ord(ch)))
1469 valuelist.append('0x00')
1470 return valuelist
1471 elif value.startswith("\"") and value.endswith("\""):
1472 return hex(ord(value[1:-1]))
1473 elif value.startswith("{") and value.endswith("}"):
1474 valuelist = []
1475 if ',' not in value:
1476 return value[1:-1]
1477 for ch in value[1:-1].split(','):
1478 ch = ch.strip()
1479 if ch.startswith('0x') or ch.startswith('0X'):
1480 valuelist.append(ch)
1481 continue
1482 try:
1483 valuelist.append(hex(int(ch.strip())))
1484 except:
1485 pass
1486 return valuelist
1487 else:
1488 return value
1489
1490 def IsStructurePcd(self, PcdToken, PcdTokenSpaceGuid):
1491 if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd) and ((PcdToken, PcdTokenSpaceGuid) in GlobalData.gStructurePcd[self.Arch]):
1492 return True
1493 else:
1494 return False
1495
1496 ##
1497 # Reports platform and module Prediction information
1498 #
1499 # This class reports the platform execution order prediction section and
1500 # module load fixed address prediction subsection in the build report file.
1501 #
1502 class PredictionReport(object):
1503 ##
1504 # Constructor function for class PredictionReport
1505 #
1506 # This constructor function generates PredictionReport object for the platform.
1507 #
1508 # @param self: The object pointer
1509 # @param Wa Workspace context information
1510 #
1511 def __init__(self, Wa):
1512 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")
1513 self._MapFileParsed = False
1514 self._EotToolInvoked = False
1515 self._FvDir = Wa.FvDir
1516 self._EotDir = Wa.BuildDir
1517 self._FfsEntryPoint = {}
1518 self._GuidMap = {}
1519 self._SourceList = []
1520 self.FixedMapDict = {}
1521 self.ItemList = []
1522 self.MaxLen = 0
1523
1524 #
1525 # Collect all platform reference source files and GUID C Name
1526 #
1527 for Pa in Wa.AutoGenObjectList:
1528 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:
1529 #
1530 # BASE typed modules are EFI agnostic, so we need not scan
1531 # their source code to find PPI/Protocol produce or consume
1532 # information.
1533 #
1534 if Module.ModuleType == SUP_MODULE_BASE:
1535 continue
1536 #
1537 # Add module referenced source files
1538 #
1539 self._SourceList.append(str(Module))
1540 IncludeList = {}
1541 for Source in Module.SourceFileList:
1542 if os.path.splitext(str(Source))[1].lower() == ".c":
1543 self._SourceList.append(" " + str(Source))
1544 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)
1545 for IncludeFile in IncludeList.values():
1546 self._SourceList.append(" " + IncludeFile)
1547
1548 for Guid in Module.PpiList:
1549 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])
1550 for Guid in Module.ProtocolList:
1551 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])
1552 for Guid in Module.GuidList:
1553 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])
1554
1555 if Module.Guid and not Module.IsLibrary:
1556 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)
1557
1558 RealEntryPoint = "_ModuleEntryPoint"
1559
1560 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)
1561
1562
1563 #
1564 # Collect platform firmware volume list as the input of EOT.
1565 #
1566 self._FvList = []
1567 if Wa.FdfProfile:
1568 for Fd in Wa.FdfProfile.FdDict:
1569 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:
1570 if FdRegion.RegionType != BINARY_FILE_TYPE_FV:
1571 continue
1572 for FvName in FdRegion.RegionDataList:
1573 if FvName in self._FvList:
1574 continue
1575 self._FvList.append(FvName)
1576 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1577 for Section in Ffs.SectionList:
1578 try:
1579 for FvSection in Section.SectionList:
1580 if FvSection.FvName in self._FvList:
1581 continue
1582 self._FvList.append(FvSection.FvName)
1583 except AttributeError:
1584 pass
1585
1586
1587 ##
1588 # Parse platform fixed address map files
1589 #
1590 # This function parses the platform final fixed address map file to get
1591 # the database of predicted fixed address for module image base, entry point
1592 # etc.
1593 #
1594 # @param self: The object pointer
1595 #
1596 def _ParseMapFile(self):
1597 if self._MapFileParsed:
1598 return
1599 self._MapFileParsed = True
1600 if os.path.isfile(self._MapFileName):
1601 try:
1602 FileContents = open(self._MapFileName).read()
1603 for Match in gMapFileItemPattern.finditer(FileContents):
1604 AddressType = Match.group(1)
1605 BaseAddress = Match.group(2)
1606 EntryPoint = Match.group(3)
1607 Guid = Match.group(4).upper()
1608 List = self.FixedMapDict.setdefault(Guid, [])
1609 List.append((AddressType, BaseAddress, "*I"))
1610 List.append((AddressType, EntryPoint, "*E"))
1611 except:
1612 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)
1613
1614 ##
1615 # Invokes EOT tool to get the predicted the execution order.
1616 #
1617 # This function invokes EOT tool to calculate the predicted dispatch order
1618 #
1619 # @param self: The object pointer
1620 #
1621 def _InvokeEotTool(self):
1622 if self._EotToolInvoked:
1623 return
1624
1625 self._EotToolInvoked = True
1626 FvFileList = []
1627 for FvName in self._FvList:
1628 FvFile = os.path.join(self._FvDir, FvName + ".Fv")
1629 if os.path.isfile(FvFile):
1630 FvFileList.append(FvFile)
1631
1632 if len(FvFileList) == 0:
1633 return
1634 #
1635 # Write source file list and GUID file list to an intermediate file
1636 # as the input for EOT tool and dispatch List as the output file
1637 # from EOT tool.
1638 #
1639 SourceList = os.path.join(self._EotDir, "SourceFile.txt")
1640 GuidList = os.path.join(self._EotDir, "GuidList.txt")
1641 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")
1642
1643 TempFile = open(SourceList, "w+")
1644 for Item in self._SourceList:
1645 FileWrite(TempFile, Item)
1646 TempFile.close()
1647 TempFile = open(GuidList, "w+")
1648 for Key in self._GuidMap:
1649 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))
1650 TempFile.close()
1651
1652 try:
1653 from Eot.EotMain import Eot
1654
1655 #
1656 # Invoke EOT tool and echo its runtime performance
1657 #
1658 EotStartTime = time.time()
1659 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,
1660 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)
1661 EotEndTime = time.time()
1662 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))
1663 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)
1664
1665 #
1666 # Parse the output of EOT tool
1667 #
1668 for Line in open(DispatchList):
1669 if len(Line.split()) < 4:
1670 continue
1671 (Guid, Phase, FfsName, FilePath) = Line.split()
1672 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]
1673 if len(Symbol) > self.MaxLen:
1674 self.MaxLen = len(Symbol)
1675 self.ItemList.append((Phase, Symbol, FilePath))
1676 except:
1677 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
1678 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1679
1680
1681 ##
1682 # Generate platform execution order report
1683 #
1684 # This function generates the predicted module execution order.
1685 #
1686 # @param self The object pointer
1687 # @param File The file object for report
1688 #
1689 def _GenerateExecutionOrderReport(self, File):
1690 self._InvokeEotTool()
1691 if len(self.ItemList) == 0:
1692 return
1693 FileWrite(File, gSectionStart)
1694 FileWrite(File, "Execution Order Prediction")
1695 FileWrite(File, "*P PEI phase")
1696 FileWrite(File, "*D DXE phase")
1697 FileWrite(File, "*E Module INF entry point name")
1698 FileWrite(File, "*N Module notification function name")
1699
1700 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))
1701 FileWrite(File, gSectionSep)
1702 for Item in self.ItemList:
1703 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))
1704
1705 FileWrite(File, gSectionStart)
1706
1707 ##
1708 # Generate Fixed Address report.
1709 #
1710 # This function generate the predicted fixed address report for a module
1711 # specified by Guid.
1712 #
1713 # @param self The object pointer
1714 # @param File The file object for report
1715 # @param Guid The module Guid value.
1716 # @param NotifyList The list of all notify function in a module
1717 #
1718 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):
1719 self._ParseMapFile()
1720 FixedAddressList = self.FixedMapDict.get(Guid)
1721 if not FixedAddressList:
1722 return
1723
1724 FileWrite(File, gSubSectionStart)
1725 FileWrite(File, "Fixed Address Prediction")
1726 FileWrite(File, "*I Image Loading Address")
1727 FileWrite(File, "*E Entry Point Address")
1728 FileWrite(File, "*N Notification Function Address")
1729 FileWrite(File, "*F Flash Address")
1730 FileWrite(File, "*M Memory Address")
1731 FileWrite(File, "*S SMM RAM Offset")
1732 FileWrite(File, "TOM Top of Memory")
1733
1734 FileWrite(File, "Type Address Name")
1735 FileWrite(File, gSubSectionSep)
1736 for Item in FixedAddressList:
1737 Type = Item[0]
1738 Value = Item[1]
1739 Symbol = Item[2]
1740 if Symbol == "*I":
1741 Name = "(Image Base)"
1742 elif Symbol == "*E":
1743 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]
1744 elif Symbol in NotifyList:
1745 Name = Symbol
1746 Symbol = "*N"
1747 else:
1748 continue
1749
1750 if "Flash" in Type:
1751 Symbol += "F"
1752 elif "Memory" in Type:
1753 Symbol += "M"
1754 else:
1755 Symbol += "S"
1756
1757 if Value[0] == "-":
1758 Value = "TOM" + Value
1759
1760 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))
1761
1762 ##
1763 # Generate report for the prediction part
1764 #
1765 # This function generate the predicted fixed address report for a module or
1766 # predicted module execution order for a platform.
1767 # If the input Guid is None, then, it generates the predicted module execution order;
1768 # otherwise it generated the module fixed loading address for the module specified by
1769 # Guid.
1770 #
1771 # @param self The object pointer
1772 # @param File The file object for report
1773 # @param Guid The module Guid value.
1774 #
1775 def GenerateReport(self, File, Guid):
1776 if Guid:
1777 self._GenerateFixedAddressReport(File, Guid.upper(), [])
1778 else:
1779 self._GenerateExecutionOrderReport(File)
1780
1781 ##
1782 # Reports FD region information
1783 #
1784 # This class reports the FD subsection in the build report file.
1785 # It collects region information of platform flash device.
1786 # If the region is a firmware volume, it lists the set of modules
1787 # and its space information; otherwise, it only lists its region name,
1788 # base address and size in its sub-section header.
1789 # If there are nesting FVs, the nested FVs will list immediate after
1790 # this FD region subsection
1791 #
1792 class FdRegionReport(object):
1793 ##
1794 # Discover all the nested FV name list.
1795 #
1796 # This is an internal worker function to discover the all the nested FV information
1797 # in the parent firmware volume. It uses deep first search algorithm recursively to
1798 # find all the FV list name and append them to the list.
1799 #
1800 # @param self The object pointer
1801 # @param FvName The name of current firmware file system
1802 # @param Wa Workspace context information
1803 #
1804 def _DiscoverNestedFvList(self, FvName, Wa):
1805 FvDictKey=FvName.upper()
1806 if FvDictKey in Wa.FdfProfile.FvDict:
1807 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1808 for Section in Ffs.SectionList:
1809 try:
1810 for FvSection in Section.SectionList:
1811 if FvSection.FvName in self.FvList:
1812 continue
1813 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName
1814 self.FvList.append(FvSection.FvName)
1815 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)
1816 self._DiscoverNestedFvList(FvSection.FvName, Wa)
1817 except AttributeError:
1818 pass
1819
1820 ##
1821 # Constructor function for class FdRegionReport
1822 #
1823 # This constructor function generates FdRegionReport object for a specified FdRegion.
1824 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1825 # volume list. This function also collects GUID map in order to dump module identification
1826 # in the final report.
1827 #
1828 # @param self: The object pointer
1829 # @param FdRegion The current FdRegion object
1830 # @param Wa Workspace context information
1831 #
1832 def __init__(self, FdRegion, Wa):
1833 self.Type = FdRegion.RegionType
1834 self.BaseAddress = FdRegion.Offset
1835 self.Size = FdRegion.Size
1836 self.FvList = []
1837 self.FvInfo = {}
1838 self._GuidsDb = {}
1839 self._FvDir = Wa.FvDir
1840 self._WorkspaceDir = Wa.WorkspaceDir
1841
1842 #
1843 # If the input FdRegion is not a firmware volume,
1844 # we are done.
1845 #
1846 if self.Type != BINARY_FILE_TYPE_FV:
1847 return
1848
1849 #
1850 # Find all nested FVs in the FdRegion
1851 #
1852 for FvName in FdRegion.RegionDataList:
1853 if FvName in self.FvList:
1854 continue
1855 self.FvList.append(FvName)
1856 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)
1857 self._DiscoverNestedFvList(FvName, Wa)
1858
1859 PlatformPcds = {}
1860 #
1861 # Collect PCDs declared in DEC files.
1862 #
1863 for Pa in Wa.AutoGenObjectList:
1864 for Package in Pa.PackageList:
1865 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
1866 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
1867 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue
1868 #
1869 # Collect PCDs defined in DSC file
1870 #
1871 for Pa in Wa.AutoGenObjectList:
1872 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
1873 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
1874 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
1875
1876 #
1877 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1878 #
1879 self._GuidsDb[PEI_APRIORI_GUID] = "PEI Apriori"
1880 self._GuidsDb[DXE_APRIORI_GUID] = "DXE Apriori"
1881 #
1882 # Add ACPI table storage file
1883 #
1884 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1885
1886 for Pa in Wa.AutoGenObjectList:
1887 for ModuleKey in Pa.Platform.Modules:
1888 M = Pa.Platform.Modules[ModuleKey].M
1889 InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)
1890 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)
1891
1892 #
1893 # Collect the GUID map in the FV firmware volume
1894 #
1895 for FvName in self.FvList:
1896 FvDictKey=FvName.upper()
1897 if FvDictKey in Wa.FdfProfile.FvDict:
1898 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1899 try:
1900 #
1901 # collect GUID map for binary EFI file in FDF file.
1902 #
1903 Guid = Ffs.NameGuid.upper()
1904 Match = gPcdGuidPattern.match(Ffs.NameGuid)
1905 if Match:
1906 PcdTokenspace = Match.group(1)
1907 PcdToken = Match.group(2)
1908 if (PcdToken, PcdTokenspace) in PlatformPcds:
1909 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]
1910 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()
1911 for Section in Ffs.SectionList:
1912 try:
1913 ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)
1914 self._GuidsDb[Guid] = ModuleSectFile
1915 except AttributeError:
1916 pass
1917 except AttributeError:
1918 pass
1919
1920
1921 ##
1922 # Internal worker function to generate report for the FD region
1923 #
1924 # This internal worker function to generate report for the FD region.
1925 # It the type is firmware volume, it lists offset and module identification.
1926 #
1927 # @param self The object pointer
1928 # @param File The file object for report
1929 # @param Title The title for the FD subsection
1930 # @param BaseAddress The base address for the FD region
1931 # @param Size The size of the FD region
1932 # @param FvName The FV name if the FD region is a firmware volume
1933 #
1934 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):
1935 FileWrite(File, gSubSectionStart)
1936 FileWrite(File, Title)
1937 FileWrite(File, "Type: %s" % Type)
1938 FileWrite(File, "Base Address: 0x%X" % BaseAddress)
1939
1940 if self.Type == BINARY_FILE_TYPE_FV:
1941 FvTotalSize = 0
1942 FvTakenSize = 0
1943 FvFreeSize = 0
1944 if FvName.upper().endswith('.FV'):
1945 FileExt = FvName + ".txt"
1946 else:
1947 FileExt = FvName + ".Fv.txt"
1948
1949 if not os.path.isfile(FileExt):
1950 FvReportFileName = mws.join(self._WorkspaceDir, FileExt)
1951 if not os.path.isfile(FvReportFileName):
1952 FvReportFileName = os.path.join(self._FvDir, FileExt)
1953 try:
1954 #
1955 # Collect size info in the firmware volume.
1956 #
1957 FvReport = open(FvReportFileName).read()
1958 Match = gFvTotalSizePattern.search(FvReport)
1959 if Match:
1960 FvTotalSize = int(Match.group(1), 16)
1961 Match = gFvTakenSizePattern.search(FvReport)
1962 if Match:
1963 FvTakenSize = int(Match.group(1), 16)
1964 FvFreeSize = FvTotalSize - FvTakenSize
1965 #
1966 # Write size information to the report file.
1967 #
1968 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))
1969 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))
1970 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))
1971 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))
1972 FileWrite(File, "Offset Module")
1973 FileWrite(File, gSubSectionSep)
1974 #
1975 # Write module offset and module identification to the report file.
1976 #
1977 OffsetInfo = {}
1978 for Match in gOffsetGuidPattern.finditer(FvReport):
1979 Guid = Match.group(2).upper()
1980 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)
1981 OffsetList = sorted(OffsetInfo.keys())
1982 for Offset in OffsetList:
1983 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))
1984 except IOError:
1985 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)
1986 else:
1987 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))
1988 FileWrite(File, gSubSectionEnd)
1989
1990 ##
1991 # Generate report for the FD region
1992 #
1993 # This function generates report for the FD region.
1994 #
1995 # @param self The object pointer
1996 # @param File The file object for report
1997 #
1998 def GenerateReport(self, File):
1999 if (len(self.FvList) > 0):
2000 for FvItem in self.FvList:
2001 Info = self.FvInfo[FvItem]
2002 self._GenerateReport(File, Info[0], TAB_FV_DIRECTORY, Info[1], Info[2], FvItem)
2003 else:
2004 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)
2005
2006 ##
2007 # Reports FD information
2008 #
2009 # This class reports the FD section in the build report file.
2010 # It collects flash device information for a platform.
2011 #
2012 class FdReport(object):
2013 ##
2014 # Constructor function for class FdReport
2015 #
2016 # This constructor function generates FdReport object for a specified
2017 # firmware device.
2018 #
2019 # @param self The object pointer
2020 # @param Fd The current Firmware device object
2021 # @param Wa Workspace context information
2022 #
2023 def __init__(self, Fd, Wa):
2024 self.FdName = Fd.FdUiName
2025 self.BaseAddress = Fd.BaseAddress
2026 self.Size = Fd.Size
2027 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]
2028 self.FvPath = os.path.join(Wa.BuildDir, TAB_FV_DIRECTORY)
2029 self.VPDBaseAddress = 0
2030 self.VPDSize = 0
2031 for index, FdRegion in enumerate(Fd.RegionList):
2032 if str(FdRegion.RegionType) is 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
2033 self.VPDBaseAddress = self.FdRegionList[index].BaseAddress
2034 self.VPDSize = self.FdRegionList[index].Size
2035 break
2036
2037 ##
2038 # Generate report for the firmware device.
2039 #
2040 # This function generates report for the firmware device.
2041 #
2042 # @param self The object pointer
2043 # @param File The file object for report
2044 #
2045 def GenerateReport(self, File):
2046 FileWrite(File, gSectionStart)
2047 FileWrite(File, "Firmware Device (FD)")
2048 FileWrite(File, "FD Name: %s" % self.FdName)
2049 FileWrite(File, "Base Address: %s" % self.BaseAddress)
2050 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))
2051 if len(self.FdRegionList) > 0:
2052 FileWrite(File, gSectionSep)
2053 for FdRegionItem in self.FdRegionList:
2054 FdRegionItem.GenerateReport(File)
2055
2056 if VPDPcdList:
2057 VPDPcdList.sort(key=lambda x: int(x[2], 0))
2058 FileWrite(File, gSubSectionStart)
2059 FileWrite(File, "FD VPD Region")
2060 FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)
2061 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))
2062 FileWrite(File, gSubSectionSep)
2063 for item in VPDPcdList:
2064 # Add BaseAddress for offset
2065 Offset = '0x%08X' % (int(item[2], 16) + self.VPDBaseAddress)
2066 IsByteArray, ArrayList = ByteArrayForamt(item[-1])
2067 Skuinfo = item[1]
2068 if len(GlobalData.gSkuids) == 1 :
2069 Skuinfo = GlobalData.gSkuids[0]
2070 if IsByteArray:
2071 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], '{'))
2072 for Array in ArrayList:
2073 FileWrite(File, Array)
2074 else:
2075 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], item[-1]))
2076 FileWrite(File, gSubSectionEnd)
2077 FileWrite(File, gSectionEnd)
2078
2079
2080
2081 ##
2082 # Reports platform information
2083 #
2084 # This class reports the whole platform information
2085 #
2086 class PlatformReport(object):
2087 ##
2088 # Constructor function for class PlatformReport
2089 #
2090 # This constructor function generates PlatformReport object a platform build.
2091 # It generates report for platform summary, flash, global PCDs and detailed
2092 # module information for modules involved in platform build.
2093 #
2094 # @param self The object pointer
2095 # @param Wa Workspace context information
2096 # @param MaList The list of modules in the platform build
2097 #
2098 def __init__(self, Wa, MaList, ReportType):
2099 self._WorkspaceDir = Wa.WorkspaceDir
2100 self.PlatformName = Wa.Name
2101 self.PlatformDscPath = Wa.Platform
2102 self.Architectures = " ".join(Wa.ArchList)
2103 self.ToolChain = Wa.ToolChain
2104 self.Target = Wa.BuildTarget
2105 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)
2106 self.BuildEnvironment = platform.platform()
2107
2108 self.PcdReport = None
2109 if "PCD" in ReportType:
2110 self.PcdReport = PcdReport(Wa)
2111
2112 self.FdReportList = []
2113 if "FLASH" in ReportType and Wa.FdfProfile and MaList is None:
2114 for Fd in Wa.FdfProfile.FdDict:
2115 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))
2116
2117 self.PredictionReport = None
2118 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:
2119 self.PredictionReport = PredictionReport(Wa)
2120
2121 self.DepexParser = None
2122 if "DEPEX" in ReportType:
2123 self.DepexParser = DepexParser(Wa)
2124
2125 self.ModuleReportList = []
2126 if MaList is not None:
2127 self._IsModuleBuild = True
2128 for Ma in MaList:
2129 self.ModuleReportList.append(ModuleReport(Ma, ReportType))
2130 else:
2131 self._IsModuleBuild = False
2132 for Pa in Wa.AutoGenObjectList:
2133 ModuleAutoGenList = []
2134 for ModuleKey in Pa.Platform.Modules:
2135 ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)
2136 if GlobalData.gFdfParser is not None:
2137 if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:
2138 INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]
2139 for InfName in INFList:
2140 InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)
2141 Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile)
2142 if Ma is None:
2143 continue
2144 if Ma not in ModuleAutoGenList:
2145 ModuleAutoGenList.append(Ma)
2146 for MGen in ModuleAutoGenList:
2147 self.ModuleReportList.append(ModuleReport(MGen, ReportType))
2148
2149
2150
2151 ##
2152 # Generate report for the whole platform.
2153 #
2154 # This function generates report for platform information.
2155 # It comprises of platform summary, global PCD, flash and
2156 # module list sections.
2157 #
2158 # @param self The object pointer
2159 # @param File The file object for report
2160 # @param BuildDuration The total time to build the modules
2161 # @param AutoGenTime The total time of AutoGen Phase
2162 # @param MakeTime The total time of Make Phase
2163 # @param GenFdsTime The total time of GenFds Phase
2164 # @param ReportType The kind of report items in the final report file
2165 #
2166 def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):
2167 FileWrite(File, "Platform Summary")
2168 FileWrite(File, "Platform Name: %s" % self.PlatformName)
2169 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)
2170 FileWrite(File, "Architectures: %s" % self.Architectures)
2171 FileWrite(File, "Tool Chain: %s" % self.ToolChain)
2172 FileWrite(File, "Target: %s" % self.Target)
2173 if GlobalData.gSkuids:
2174 FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids))
2175 if GlobalData.gDefaultStores:
2176 FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores))
2177 FileWrite(File, "Output Path: %s" % self.OutputPath)
2178 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)
2179 FileWrite(File, "Build Duration: %s" % BuildDuration)
2180 if AutoGenTime:
2181 FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)
2182 if MakeTime:
2183 FileWrite(File, "Make Duration: %s" % MakeTime)
2184 if GenFdsTime:
2185 FileWrite(File, "GenFds Duration: %s" % GenFdsTime)
2186 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))
2187
2188 if GlobalData.MixedPcd:
2189 FileWrite(File, gSectionStart)
2190 FileWrite(File, "The following PCDs use different access methods:")
2191 FileWrite(File, gSectionSep)
2192 for PcdItem in GlobalData.MixedPcd:
2193 FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))
2194 FileWrite(File, gSectionEnd)
2195
2196 if not self._IsModuleBuild:
2197 if "PCD" in ReportType:
2198 self.PcdReport.GenerateReport(File, None)
2199
2200 if "FLASH" in ReportType:
2201 for FdReportListItem in self.FdReportList:
2202 FdReportListItem.GenerateReport(File)
2203
2204 for ModuleReportItem in self.ModuleReportList:
2205 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)
2206
2207 if not self._IsModuleBuild:
2208 if "EXECUTION_ORDER" in ReportType:
2209 self.PredictionReport.GenerateReport(File, None)
2210
2211 ## BuildReport class
2212 #
2213 # This base class contain the routines to collect data and then
2214 # applies certain format to the output report
2215 #
2216 class BuildReport(object):
2217 ##
2218 # Constructor function for class BuildReport
2219 #
2220 # This constructor function generates BuildReport object a platform build.
2221 # It generates report for platform summary, flash, global PCDs and detailed
2222 # module information for modules involved in platform build.
2223 #
2224 # @param self The object pointer
2225 # @param ReportFile The file name to save report file
2226 # @param ReportType The kind of report items in the final report file
2227 #
2228 def __init__(self, ReportFile, ReportType):
2229 self.ReportFile = ReportFile
2230 if ReportFile:
2231 self.ReportList = []
2232 self.ReportType = []
2233 if ReportType:
2234 for ReportTypeItem in ReportType:
2235 if ReportTypeItem not in self.ReportType:
2236 self.ReportType.append(ReportTypeItem)
2237 else:
2238 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2239 ##
2240 # Adds platform report to the list
2241 #
2242 # This function adds a platform report to the final report list.
2243 #
2244 # @param self The object pointer
2245 # @param Wa Workspace context information
2246 # @param MaList The list of modules in the platform build
2247 #
2248 def AddPlatformReport(self, Wa, MaList=None):
2249 if self.ReportFile:
2250 self.ReportList.append((Wa, MaList))
2251
2252 ##
2253 # Generates the final report.
2254 #
2255 # This function generates platform build report. It invokes GenerateReport()
2256 # method for every platform report in the list.
2257 #
2258 # @param self The object pointer
2259 # @param BuildDuration The total time to build the modules
2260 # @param AutoGenTime The total time of AutoGen phase
2261 # @param MakeTime The total time of Make phase
2262 # @param GenFdsTime The total time of GenFds phase
2263 #
2264 def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):
2265 if self.ReportFile:
2266 try:
2267 File = BytesIO('')
2268 for (Wa, MaList) in self.ReportList:
2269 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)
2270 Content = FileLinesSplit(File.getvalue(), gLineMaxLength)
2271 SaveFileOnChange(self.ReportFile, Content, True)
2272 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))
2273 except IOError:
2274 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)
2275 except:
2276 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)
2277 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
2278 File.close()
2279
2280 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2281 if __name__ == '__main__':
2282 pass
2283