2 # Routines for generating build report.
4 # This module contains the functionality to generate build report after
5 # build all target completes successfully.
7 # Copyright (c) 2010, 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
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.
27 from datetime
import datetime
28 from StringIO
import StringIO
29 from Common
import EdkLogger
30 from Common
.Misc
import SaveFileOnChange
31 from Common
.Misc
import GuidStructureByteArrayToGuidString
32 from Common
.Misc
import GuidStructureStringToGuidString
33 from Common
.InfClassObject
import gComponentType2ModuleType
34 from Common
.BuildToolError
import FILE_WRITE_FAILURE
35 from Common
.BuildToolError
import CODE_ERROR
36 from Common
.DataType
import TAB_LINE_BREAK
37 from Common
.DataType
import TAB_DEPEX
38 from Common
.DataType
import TAB_SLASH
39 from Common
.DataType
import TAB_SPACE_SPLIT
40 from Common
.DataType
import TAB_BRG_PCD
41 from Common
.DataType
import TAB_BRG_LIBRARY
43 ## Pattern to extract contents in EDK DXS files
44 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
46 ## Pattern to find total FV total size, occupied size in flash report intermediate file
47 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
48 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
50 ## Pattern to find module size and time stamp in module summary report intermediate file
51 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
52 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
54 ## Pattern to find GUID value in flash description files
55 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
57 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
58 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
60 ## Pattern to find module base address and entry point in fixed flash map file
61 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
62 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
64 ## Pattern to find all module referenced header files in source files
65 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
66 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
68 ## Pattern to find the entry point for EDK module using EDKII Glue library
69 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
71 ## Tags for MaxLength of line in report
74 ## Tags for section start, end and separator
75 gSectionStart
= ">" + "=" * (gLineMaxLength
-2) + "<"
76 gSectionEnd
= "<" + "=" * (gLineMaxLength
-2) + ">" + "\n"
77 gSectionSep
= "=" * gLineMaxLength
79 ## Tags for subsection start, end and separator
80 gSubSectionStart
= ">" + "-" * (gLineMaxLength
-2) + "<"
81 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
-2) + ">"
82 gSubSectionSep
= "-" * gLineMaxLength
85 ## The look up table to map PCD type to pair of report display type and DEC type
87 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
88 'PatchableInModule': ('PATCH', 'PatchableInModule'),
89 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
90 'Dynamic' : ('DYN', 'Dynamic'),
91 'DynamicHii' : ('DYNHII', 'Dynamic'),
92 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
93 'DynamicEx' : ('DEX', 'Dynamic'),
94 'DynamicExHii' : ('DEXHII', 'Dynamic'),
95 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),
98 ## The look up table to map module type to driver type
100 'SEC' : '0x3 (SECURITY_CORE)',
101 'PEI_CORE' : '0x4 (PEI_CORE)',
102 'PEIM' : '0x6 (PEIM)',
103 'DXE_CORE' : '0x5 (DXE_CORE)',
104 'DXE_DRIVER' : '0x7 (DRIVER)',
105 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
106 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
107 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
108 'UEFI_DRIVER' : '0x7 (DRIVER)',
109 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
110 'SMM_CORE' : '0xD (SMM_CORE)',
111 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
114 ## The look up table of the supported opcode in the dependency expression binaries
115 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
118 # Writes a string to the file object.
120 # This function writes a string to the file object and a new line is appended
121 # afterwards. It may optionally wraps the string for better readability.
123 # @File The file object to write
124 # @String The string to be written to the file
125 # @Wrapper Indicates whether to wrap the string
127 def FileWrite(File
, String
, Wrapper
=False):
129 String
= textwrap
.fill(String
, 120)
130 File
.write(String
+ "\r\n")
133 # Find all the header file that the module source directly includes.
135 # This function scans source code to find all header files the module may
136 # include. This is not accurate but very effective to find all the header
137 # file the module might include with #include statement.
139 # @Source The source file name
140 # @IncludePathList The list of include path to find the source file.
141 # @IncludeFiles The dictionary of current found include files.
143 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
144 FileContents
= open(Source
).read()
146 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
148 for Match
in gIncludePattern
.finditer(FileContents
):
149 FileName
= Match
.group(1).strip()
150 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
151 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
152 if os
.path
.exists(FullFileName
):
153 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
157 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
159 for Match
in gIncludePattern2
.finditer(FileContents
):
161 Type
= Match
.group(1)
162 if "ARCH_PROTOCOL" in Type
:
163 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
164 elif "PROTOCOL" in Type
:
165 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
167 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
169 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
172 for Dir
in IncludePathList
:
173 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
174 if os
.path
.exists(FullFileName
):
175 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
178 ## Split each lines in file
180 # This method is used to split the lines in file to make the length of each line
181 # less than MaxLength.
183 # @param Content The content of file
184 # @param MaxLength The Max Length of the line
186 def FileLinesSplit(Content
=None, MaxLength
=None):
187 ContentList
= Content
.split(TAB_LINE_BREAK
)
190 for Line
in ContentList
:
191 while len(Line
.rstrip()) > MaxLength
:
192 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
193 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
194 LineBreakIndex
= MaxLength
195 if LineSpaceIndex
> LineSlashIndex
:
196 LineBreakIndex
= LineSpaceIndex
197 elif LineSlashIndex
> LineSpaceIndex
:
198 LineBreakIndex
= LineSlashIndex
199 NewContentList
.append(Line
[:LineBreakIndex
])
200 Line
= Line
[LineBreakIndex
:]
202 NewContentList
.append(Line
)
203 for NewLine
in NewContentList
:
204 NewContent
+= NewLine
+ TAB_LINE_BREAK
210 # Parse binary dependency expression section
212 # This utility class parses the dependency expression section and translate the readable
213 # GUID name and value.
215 class DepexParser(object):
217 # Constructor function for class DepexParser
219 # This constructor function collect GUID values so that the readable
220 # GUID name can be translated.
222 # @param self The object pointer
223 # @param Wa Workspace context information
225 def __init__(self
, Wa
):
227 for Pa
in Wa
.AutoGenObjectList
:
228 for Package
in Pa
.PackageList
:
229 for Protocol
in Package
.Protocols
:
230 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
231 self
._GuidDb
[GuidValue
.upper()] = Protocol
232 for Ppi
in Package
.Ppis
:
233 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
234 self
._GuidDb
[GuidValue
.upper()] = Ppi
235 for Guid
in Package
.Guids
:
236 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
237 self
._GuidDb
[GuidValue
.upper()] = Guid
240 # Parse the binary dependency expression files.
242 # This function parses the binary dependency expression file and translate it
243 # to the instruction list.
245 # @param self The object pointer
246 # @param DepexFileName The file name of binary dependency expression file.
248 def ParseDepexFile(self
, DepexFileName
):
249 DepexFile
= open(DepexFileName
, "rb")
251 OpCode
= DepexFile
.read(1)
253 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
254 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
255 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
256 struct
.unpack("LHHBBBBBBBB", DepexFile
.read(16))
257 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
258 Statement
= "%s %s" % (Statement
, GuidString
)
259 DepexStatement
.append(Statement
)
260 OpCode
= DepexFile
.read(1)
262 return DepexStatement
265 # Reports library information
267 # This class reports the module library subsection in the build report file.
269 class LibraryReport(object):
271 # Constructor function for class LibraryReport
273 # This constructor function generates LibraryReport object for
276 # @param self The object pointer
277 # @param M Module context information
279 def __init__(self
, M
):
280 self
.LibraryList
= []
281 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
282 self
._EdkIIModule
= True
284 self
._EdkIIModule
= False
286 for Lib
in M
.DependentLibraryList
:
287 LibInfPath
= str(Lib
)
288 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
289 LibConstructorList
= Lib
.ConstructorList
290 LibDesstructorList
= Lib
.DestructorList
291 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
292 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
))
295 # Generate report for module library information
297 # This function generates report for the module library.
298 # If the module is EDKII style one, the additional library class, library
299 # constructor/destructor and dependency expression may also be reported.
301 # @param self The object pointer
302 # @param File The file object for report
304 def GenerateReport(self
, File
):
305 FileWrite(File
, gSubSectionStart
)
306 FileWrite(File
, TAB_BRG_LIBRARY
)
307 if len(self
.LibraryList
) > 0:
308 FileWrite(File
, gSubSectionSep
)
309 for LibraryItem
in self
.LibraryList
:
310 LibInfPath
= LibraryItem
[0]
311 FileWrite(File
, LibInfPath
)
314 # Report library class, library constructor and destructor for
315 # EDKII style module.
317 if self
._EdkIIModule
:
318 LibClass
= LibraryItem
[1]
320 LibConstructor
= " ".join(LibraryItem
[2])
322 EdkIILibInfo
+= " C = " + LibConstructor
323 LibDestructor
= " ".join(LibraryItem
[3])
325 EdkIILibInfo
+= " D = " + LibDestructor
326 LibDepex
= " ".join(LibraryItem
[4])
328 EdkIILibInfo
+= " Depex = " + LibDepex
330 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
332 FileWrite(File
, "{%s}" % LibClass
)
334 FileWrite(File
, gSubSectionEnd
)
337 # Reports dependency expression information
339 # This class reports the module dependency expression subsection in the build report file.
341 class DepexReport(object):
343 # Constructor function for class DepexReport
345 # This constructor function generates DepexReport object for
346 # a module. If the module source contains the DXS file (usually EDK
347 # style module), it uses the dependency in DXS file; otherwise,
348 # it uses the dependency expression from its own INF [Depex] section
349 # and then merges with the ones from its dependent library INF.
351 # @param self The object pointer
352 # @param M Module context information
354 def __init__(self
, M
):
356 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
357 ModuleType
= M
.ModuleType
359 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
361 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:
364 for Source
in M
.SourceFileList
:
365 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
366 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
368 self
.Depex
= Match
.group(1).strip()
372 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
373 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
374 if not self
.ModuleDepex
:
375 self
.ModuleDepex
= "(None)"
378 for Lib
in M
.DependentLibraryList
:
379 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
381 LibDepexList
.append("(" + LibDepex
+ ")")
382 self
.LibraryDepex
= " AND ".join(LibDepexList
)
383 if not self
.LibraryDepex
:
384 self
.LibraryDepex
= "(None)"
388 # Generate report for module dependency expression information
390 # This function generates report for the module dependency expression.
392 # @param self The object pointer
393 # @param File The file object for report
394 # @param GlobalDepexParser The platform global Dependency expression parser object
396 def GenerateReport(self
, File
, GlobalDepexParser
):
398 FileWrite(File
, gSubSectionStart
)
399 FileWrite(File
, TAB_DEPEX
)
400 FileWrite(File
, gSubSectionEnd
)
402 FileWrite(File
, gSubSectionStart
)
403 if os
.path
.isfile(self
._DepexFileName
):
405 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
406 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
407 for DepexStatement
in DepexStatements
:
408 FileWrite(File
, " %s" % DepexStatement
)
409 FileWrite(File
, gSubSectionSep
)
411 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
413 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
415 if self
.Source
== "INF":
416 FileWrite(File
, "%s" % self
.Depex
, True)
417 FileWrite(File
, gSubSectionSep
)
418 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
419 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
421 FileWrite(File
, "%s" % self
.Depex
)
422 FileWrite(File
, gSubSectionEnd
)
425 # Reports dependency expression information
427 # This class reports the module build flags subsection in the build report file.
429 class BuildFlagsReport(object):
431 # Constructor function for class BuildFlagsReport
433 # This constructor function generates BuildFlagsReport object for
434 # a module. It reports the build tool chain tag and all relevant
435 # build flags to build the module.
437 # @param self The object pointer
438 # @param M Module context information
440 def __init__(self
, M
):
443 # Add build flags according to source file extension so that
444 # irrelevant ones can be filtered out.
446 for Source
in M
.SourceFileList
:
447 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
448 if Ext
in [".c", ".cc", ".cpp"]:
449 BuildOptions
["CC"] = 1
450 elif Ext
in [".s", ".asm"]:
451 BuildOptions
["PP"] = 1
452 BuildOptions
["ASM"] = 1
453 elif Ext
in [".vfr"]:
454 BuildOptions
["VFRPP"] = 1
455 BuildOptions
["VFR"] = 1
456 elif Ext
in [".dxs"]:
457 BuildOptions
["APP"] = 1
458 BuildOptions
["CC"] = 1
459 elif Ext
in [".asl"]:
460 BuildOptions
["ASLPP"] = 1
461 BuildOptions
["ASL"] = 1
462 elif Ext
in [".aslc"]:
463 BuildOptions
["ASLCC"] = 1
464 BuildOptions
["ASLDLINK"] = 1
465 BuildOptions
["CC"] = 1
466 elif Ext
in [".asm16"]:
467 BuildOptions
["ASMLINK"] = 1
468 BuildOptions
["SLINK"] = 1
469 BuildOptions
["DLINK"] = 1
472 # Save module build flags.
474 self
.ToolChainTag
= M
.ToolChain
476 for Tool
in BuildOptions
:
477 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
480 # Generate report for module build flags information
482 # This function generates report for the module build flags expression.
484 # @param self The object pointer
485 # @param File The file object for report
487 def GenerateReport(self
, File
):
488 FileWrite(File
, gSubSectionStart
)
489 FileWrite(File
, "Build Flags")
490 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
491 for Tool
in self
.BuildFlags
:
492 FileWrite(File
, gSubSectionSep
)
493 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
495 FileWrite(File
, gSubSectionEnd
)
499 # Reports individual module information
501 # This class reports the module section in the build report file.
502 # It comprises of module summary, module PCD, library, dependency expression,
503 # build flags sections.
505 class ModuleReport(object):
507 # Constructor function for class ModuleReport
509 # This constructor function generates ModuleReport object for
510 # a separate module in a platform build.
512 # @param self The object pointer
513 # @param M Module context information
514 # @param ReportType The kind of report items in the final report file
516 def __init__(self
, M
, ReportType
):
517 self
.ModuleName
= M
.Module
.BaseName
518 self
.ModuleInfPath
= M
.MetaFile
.File
519 self
.FileGuid
= M
.Guid
521 self
.BuildTimeStamp
= None
524 ModuleType
= M
.ModuleType
526 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
528 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
530 if ModuleType
== "DXE_SMM_DRIVER":
531 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
532 if int(PiSpec
, 0) >= 0x0001000A:
533 ModuleType
= "SMM_DRIVER"
534 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
535 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
536 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
537 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
538 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
539 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
541 self
._BuildDir
= M
.BuildDir
542 self
.ModulePcdSet
= {}
543 if "PCD" in ReportType
:
545 # Collect all module used PCD set: module INF referenced directly or indirectly.
546 # It also saves module INF default values of them in case they exist.
548 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
549 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
551 self
.LibraryReport
= None
552 if "LIBRARY" in ReportType
:
553 self
.LibraryReport
= LibraryReport(M
)
555 self
.DepexReport
= None
556 if "DEPEX" in ReportType
:
557 self
.DepexReport
= DepexReport(M
)
559 if "BUILD_FLAGS" in ReportType
:
560 self
.BuildFlagsReport
= BuildFlagsReport(M
)
564 # Generate report for module information
566 # This function generates report for separate module expression
567 # in a platform build.
569 # @param self The object pointer
570 # @param File The file object for report
571 # @param GlobalPcdReport The platform global PCD report object
572 # @param GlobalPredictionReport The platform global Prediction report object
573 # @param GlobalDepexParser The platform global Dependency expression parser object
574 # @param ReportType The kind of report items in the final report file
576 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
577 FileWrite(File
, gSectionStart
)
579 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
580 if os
.path
.isfile(FwReportFileName
):
582 FileContents
= open(FwReportFileName
).read()
583 Match
= gModuleSizePattern
.search(FileContents
)
585 self
.Size
= int(Match
.group(1))
587 Match
= gTimeStampPattern
.search(FileContents
)
589 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
591 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
593 FileWrite(File
, "Module Summary")
594 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
595 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
596 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
598 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
599 if self
.BuildTimeStamp
:
600 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
602 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
603 if self
.UefiSpecVersion
:
604 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
605 if self
.PiSpecVersion
:
606 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
608 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
610 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
611 if self
.PciClassCode
:
612 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
614 FileWrite(File
, gSectionSep
)
616 if "PCD" in ReportType
:
617 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
619 if "LIBRARY" in ReportType
:
620 self
.LibraryReport
.GenerateReport(File
)
622 if "DEPEX" in ReportType
:
623 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
625 if "BUILD_FLAGS" in ReportType
:
626 self
.BuildFlagsReport
.GenerateReport(File
)
628 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
629 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
631 FileWrite(File
, gSectionEnd
)
634 # Reports platform and module PCD information
636 # This class reports the platform PCD section and module PCD subsection
637 # in the build report file.
639 class PcdReport(object):
641 # Constructor function for class PcdReport
643 # This constructor function generates PcdReport object a platform build.
644 # It collects the whole PCD database from platform DSC files, platform
645 # flash description file and package DEC files.
647 # @param self The object pointer
648 # @param Wa Workspace context information
650 def __init__(self
, Wa
):
654 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
658 self
.ModulePcdOverride
= {}
659 for Pa
in Wa
.AutoGenObjectList
:
661 # Collect all platform referenced PCDs and grouped them by PCD token space
664 for Pcd
in Pa
.AllPcdList
:
665 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
666 if Pcd
not in PcdList
:
668 if len(Pcd
.TokenCName
) > self
.MaxLen
:
669 self
.MaxLen
= len(Pcd
.TokenCName
)
671 for Module
in Pa
.Platform
.Modules
.values():
673 # Collect module override PCDs
675 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
676 TokenCName
= ModulePcd
.TokenCName
677 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
678 ModuleDefault
= ModulePcd
.DefaultValue
679 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
680 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
684 # Collect PCD DEC default value.
686 self
.DecPcdDefault
= {}
687 for Pa
in Wa
.AutoGenObjectList
:
688 for Package
in Pa
.PackageList
:
689 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
690 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
691 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
693 # Collect PCDs defined in DSC common section
695 self
.DscPcdDefault
= {}
696 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
697 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
698 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
700 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
703 # Generate report for PCD information
705 # This function generates report for separate module expression
706 # in a platform build.
708 # @param self The object pointer
709 # @param File The file object for report
710 # @param ModulePcdSet Set of all PCDs referenced by module or None for
711 # platform PCD report
712 # @param DscOverridePcds Module DSC override PCDs set
714 def GenerateReport(self
, File
, ModulePcdSet
):
715 if ModulePcdSet
== None:
717 # For platform global PCD section
719 FileWrite(File
, gSectionStart
)
720 FileWrite(File
, "Platform Configuration Database Report")
721 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
722 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
723 FileWrite(File
, " *M - Module scoped PCD override")
724 FileWrite(File
, gSectionSep
)
727 # For module PCD sub-section
729 FileWrite(File
, gSubSectionStart
)
730 FileWrite(File
, TAB_BRG_PCD
)
731 FileWrite(File
, gSubSectionSep
)
733 for Key
in self
.AllPcds
:
735 # Group PCD by their token space GUID C Name
738 for Type
in self
.AllPcds
[Key
]:
740 # Group PCD by their usage type
742 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
743 for Pcd
in self
.AllPcds
[Key
][Type
]:
745 # Get PCD default value and their override relationship
747 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
748 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
749 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
750 InfDefaultValue
= None
752 PcdValue
= DecDefaultValue
754 PcdValue
= DscDefaultValue
755 if ModulePcdSet
!= None:
756 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
758 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
762 if ModulePcdSet
== None:
768 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
769 PcdValueNumber
= int(PcdValue
.strip(), 0)
770 if DecDefaultValue
== None:
773 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
774 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
776 if InfDefaultValue
== None:
779 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
780 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
782 if DscDefaultValue
== None:
785 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
786 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
788 if DecDefaultValue
== None:
791 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
793 if InfDefaultValue
== None:
796 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
798 if DscDefaultValue
== None:
801 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
804 # Report PCD item according to their override relationship
806 if DecMatch
and InfMatch
:
807 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
810 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
811 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
813 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
815 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
817 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
818 for SkuInfo
in Pcd
.SkuInfoList
.values():
819 if TypeName
in ('DYNHII', 'DEXHII'):
820 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
822 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
824 if not DscMatch
and DscDefaultValue
!= None:
825 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
827 if not InfMatch
and InfDefaultValue
!= None:
828 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
830 if not DecMatch
and DecDefaultValue
!= None:
831 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
833 if ModulePcdSet
== None:
834 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
835 for ModulePath
in ModuleOverride
:
836 ModuleDefault
= ModuleOverride
[ModulePath
]
837 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
838 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
839 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
841 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
844 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
846 if ModulePcdSet
== None:
847 FileWrite(File
, gSectionEnd
)
849 FileWrite(File
, gSubSectionEnd
)
854 # Reports platform and module Prediction information
856 # This class reports the platform execution order prediction section and
857 # module load fixed address prediction subsection in the build report file.
859 class PredictionReport(object):
861 # Constructor function for class PredictionReport
863 # This constructor function generates PredictionReport object for the platform.
865 # @param self: The object pointer
866 # @param Wa Workspace context information
868 def __init__(self
, Wa
):
869 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
870 self
._MapFileParsed
= False
871 self
._EotToolInvoked
= False
872 self
._FvDir
= Wa
.FvDir
873 self
._EotDir
= Wa
.BuildDir
874 self
._FfsEntryPoint
= {}
876 self
._SourceList
= []
877 self
.FixedMapDict
= {}
882 # Collect all platform reference source files and GUID C Name
884 for Pa
in Wa
.AutoGenObjectList
:
885 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
887 # BASE typed modules are EFI agnostic, so we need not scan
888 # their source code to find PPI/Protocol produce or consume
891 if Module
.ModuleType
== "BASE":
894 # Add module referenced source files
896 self
._SourceList
.append(str(Module
))
898 for Source
in Module
.SourceFileList
:
899 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
900 self
._SourceList
.append(" " + str(Source
))
901 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
902 for IncludeFile
in IncludeList
.values():
903 self
._SourceList
.append(" " + IncludeFile
)
905 for Guid
in Module
.PpiList
:
906 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
907 for Guid
in Module
.ProtocolList
:
908 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
909 for Guid
in Module
.GuidList
:
910 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
912 if Module
.Guid
and not Module
.IsLibrary
:
913 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
914 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
915 RealEntryPoint
= "_ModuleEntryPoint"
917 RealEntryPoint
= EntryPoint
918 if EntryPoint
== "_ModuleEntryPoint":
919 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
920 Match
= gGlueLibEntryPoint
.search(CCFlags
)
922 EntryPoint
= Match
.group(1)
924 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
928 # Collect platform firmware volume list as the input of EOT.
932 for Fd
in Wa
.FdfProfile
.FdDict
:
933 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
934 if FdRegion
.RegionType
!= "FV":
936 for FvName
in FdRegion
.RegionDataList
:
937 if FvName
in self
._FvList
:
939 self
._FvList
.append(FvName
)
940 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
941 for Section
in Ffs
.SectionList
:
943 for FvSection
in Section
.SectionList
:
944 if FvSection
.FvName
in self
._FvList
:
946 self
._FvList
.append(FvSection
.FvName
)
947 except AttributeError:
952 # Parse platform fixed address map files
954 # This function parses the platform final fixed address map file to get
955 # the database of predicted fixed address for module image base, entry point
958 # @param self: The object pointer
960 def _ParseMapFile(self
):
961 if self
._MapFileParsed
:
963 self
._MapFileParsed
= True
964 if os
.path
.isfile(self
._MapFileName
):
966 FileContents
= open(self
._MapFileName
).read()
967 for Match
in gMapFileItemPattern
.finditer(FileContents
):
968 AddressType
= Match
.group(1)
969 BaseAddress
= Match
.group(2)
970 EntryPoint
= Match
.group(3)
971 Guid
= Match
.group(4).upper()
972 List
= self
.FixedMapDict
.setdefault(Guid
, [])
973 List
.append((AddressType
, BaseAddress
, "*I"))
974 List
.append((AddressType
, EntryPoint
, "*E"))
976 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
979 # Invokes EOT tool to get the predicted the execution order.
981 # This function invokes EOT tool to calculate the predicted dispatch order
983 # @param self: The object pointer
985 def _InvokeEotTool(self
):
986 if self
._EotToolInvoked
:
989 self
._EotToolInvoked
= True
991 for FvName
in self
._FvList
:
992 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
993 if os
.path
.isfile(FvFile
):
994 FvFileList
.append(FvFile
)
996 if len(FvFileList
) == 0:
999 # Write source file list and GUID file list to an intermediate file
1000 # as the input for EOT tool and dispatch List as the output file
1003 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1004 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1005 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1007 TempFile
= open(SourceList
, "w+")
1008 for Item
in self
._SourceList
:
1009 FileWrite(TempFile
, Item
)
1011 TempFile
= open(GuidList
, "w+")
1012 for Key
in self
._GuidMap
:
1013 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1017 from Eot
.Eot
import Eot
1020 # Invoke EOT tool and echo its runtime performance
1022 EotStartTime
= time
.time()
1023 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1024 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1025 EotEndTime
= time
.time()
1026 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1027 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1030 # Parse the output of EOT tool
1032 for Line
in open(DispatchList
):
1033 if len(Line
.split()) < 4:
1035 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1036 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1037 if len(Symbol
) > self
.MaxLen
:
1038 self
.MaxLen
= len(Symbol
)
1039 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1041 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1042 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1046 # Generate platform execution order report
1048 # This function generates the predicted module execution order.
1050 # @param self The object pointer
1051 # @param File The file object for report
1053 def _GenerateExecutionOrderReport(self
, File
):
1054 self
._InvokeEotTool
()
1055 if len(self
.ItemList
) == 0:
1057 FileWrite(File
, gSectionStart
)
1058 FileWrite(File
, "Execution Order Prediction")
1059 FileWrite(File
, "*P PEI phase")
1060 FileWrite(File
, "*D DXE phase")
1061 FileWrite(File
, "*E Module INF entry point name")
1062 FileWrite(File
, "*N Module notification function name")
1064 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1065 FileWrite(File
, gSectionSep
)
1066 for Item
in self
.ItemList
:
1067 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1069 FileWrite(File
, gSectionStart
)
1072 # Generate Fixed Address report.
1074 # This function generate the predicted fixed address report for a module
1075 # specified by Guid.
1077 # @param self The object pointer
1078 # @param File The file object for report
1079 # @param Guid The module Guid value.
1080 # @param NotifyList The list of all notify function in a module
1082 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1083 self
._ParseMapFile
()
1084 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1085 if not FixedAddressList
:
1088 FileWrite(File
, gSubSectionStart
)
1089 FileWrite(File
, "Fixed Address Prediction")
1090 FileWrite(File
, "*I Image Loading Address")
1091 FileWrite(File
, "*E Entry Point Address")
1092 FileWrite(File
, "*N Notification Function Address")
1093 FileWrite(File
, "*F Flash Address")
1094 FileWrite(File
, "*M Memory Address")
1095 FileWrite(File
, "*S SMM RAM Offset")
1096 FileWrite(File
, "TOM Top of Memory")
1098 FileWrite(File
, "Type Address Name")
1099 FileWrite(File
, gSubSectionSep
)
1100 for Item
in FixedAddressList
:
1105 Name
= "(Image Base)"
1106 elif Symbol
== "*E":
1107 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1108 elif Symbol
in NotifyList
:
1116 elif "Memory" in Type
:
1122 Value
= "TOM" + Value
1124 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1127 # Generate report for the prediction part
1129 # This function generate the predicted fixed address report for a module or
1130 # predicted module execution order for a platform.
1131 # If the input Guid is None, then, it generates the predicted module execution order;
1132 # otherwise it generated the module fixed loading address for the module specified by
1135 # @param self The object pointer
1136 # @param File The file object for report
1137 # @param Guid The module Guid value.
1139 def GenerateReport(self
, File
, Guid
):
1141 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1143 self
._GenerateExecutionOrderReport
(File
)
1146 # Reports FD region information
1148 # This class reports the FD subsection in the build report file.
1149 # It collects region information of platform flash device.
1150 # If the region is a firmware volume, it lists the set of modules
1151 # and its space information; otherwise, it only lists its region name,
1152 # base address and size in its sub-section header.
1153 # If there are nesting FVs, the nested FVs will list immediate after
1154 # this FD region subsection
1156 class FdRegionReport(object):
1158 # Discover all the nested FV name list.
1160 # This is an internal worker function to discover the all the nested FV information
1161 # in the parent firmware volume. It uses deep first search algorithm recursively to
1162 # find all the FV list name and append them to the list.
1164 # @param self The object pointer
1165 # @param FvName The name of current firmware file system
1166 # @param Wa Workspace context information
1168 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1169 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1170 for Section
in Ffs
.SectionList
:
1172 for FvSection
in Section
.SectionList
:
1173 if FvSection
.FvName
in self
.FvList
:
1175 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1176 self
.FvList
.append(FvSection
.FvName
)
1177 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1178 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1179 except AttributeError:
1183 # Constructor function for class FdRegionReport
1185 # This constructor function generates FdRegionReport object for a specified FdRegion.
1186 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1187 # volume list. This function also collects GUID map in order to dump module identification
1188 # in the final report.
1190 # @param self: The object pointer
1191 # @param FdRegion The current FdRegion object
1192 # @param Wa Workspace context information
1194 def __init__(self
, FdRegion
, Wa
):
1195 self
.Type
= FdRegion
.RegionType
1196 self
.BaseAddress
= FdRegion
.Offset
1197 self
.Size
= FdRegion
.Size
1201 self
._FvDir
= Wa
.FvDir
1204 # If the input FdRegion is not a firmware volume,
1207 if self
.Type
!= "FV":
1211 # Find all nested FVs in the FdRegion
1213 for FvName
in FdRegion
.RegionDataList
:
1214 if FvName
in self
.FvList
:
1216 self
.FvList
.append(FvName
)
1217 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1218 self
._DiscoverNestedFvList
(FvName
, Wa
)
1222 # Collect PCDs declared in DEC files.
1224 for Pa
in Wa
.AutoGenObjectList
:
1225 for Package
in Pa
.PackageList
:
1226 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1227 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1228 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1230 # Collect PCDs defined in DSC common section
1232 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
1233 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1234 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1235 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1238 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1240 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1241 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1243 # Add ACPI table storage file
1245 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1247 for Pa
in Wa
.AutoGenObjectList
:
1248 for ModuleKey
in Pa
.Platform
.Modules
:
1249 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1250 InfPath
= os
.path
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1251 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1254 # Collect the GUID map in the FV firmware volume
1256 for FvName
in self
.FvList
:
1257 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1260 # collect GUID map for binary EFI file in FDF file.
1262 Guid
= Ffs
.NameGuid
.upper()
1263 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1265 PcdTokenspace
= Match
.group(1)
1266 PcdToken
= Match
.group(2)
1267 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1268 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1269 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1270 for Section
in Ffs
.SectionList
:
1272 ModuleSectFile
= os
.path
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1273 self
._GuidsDb
[Guid
] = ModuleSectFile
1274 except AttributeError:
1276 except AttributeError:
1281 # Internal worker function to generate report for the FD region
1283 # This internal worker function to generate report for the FD region.
1284 # It the type is firmware volume, it lists offset and module identification.
1286 # @param self The object pointer
1287 # @param File The file object for report
1288 # @param Title The title for the FD subsection
1289 # @param BaseAddress The base address for the FD region
1290 # @param Size The size of the FD region
1291 # @param FvName The FV name if the FD region is a firmware volume
1293 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1294 FileWrite(File
, gSubSectionStart
)
1295 FileWrite(File
, Title
)
1296 FileWrite(File
, "Type: %s" % Type
)
1297 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1299 if self
.Type
== "FV":
1303 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv.txt")
1306 # Collect size info in the firmware volume.
1308 FvReport
= open(FvReportFileName
).read()
1309 Match
= gFvTotalSizePattern
.search(FvReport
)
1311 FvTotalSize
= int(Match
.group(1), 16)
1312 Match
= gFvTakenSizePattern
.search(FvReport
)
1314 FvTakenSize
= int(Match
.group(1), 16)
1315 FvFreeSize
= FvTotalSize
- FvTakenSize
1317 # Write size information to the report file.
1319 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1320 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1321 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1322 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1323 FileWrite(File
, "Offset Module")
1324 FileWrite(File
, gSubSectionSep
)
1326 # Write module offset and module identification to the report file.
1329 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1330 Guid
= Match
.group(2).upper()
1331 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1332 OffsetList
= OffsetInfo
.keys()
1334 for Offset
in OffsetList
:
1335 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1337 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1339 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1340 FileWrite(File
, gSubSectionEnd
)
1343 # Generate report for the FD region
1345 # This function generates report for the FD region.
1347 # @param self The object pointer
1348 # @param File The file object for report
1350 def GenerateReport(self
, File
):
1351 if (len(self
.FvList
) > 0):
1352 for FvItem
in self
.FvList
:
1353 Info
= self
.FvInfo
[FvItem
]
1354 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1356 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1359 # Reports FD information
1361 # This class reports the FD section in the build report file.
1362 # It collects flash device information for a platform.
1364 class FdReport(object):
1366 # Constructor function for class FdReport
1368 # This constructor function generates FdReport object for a specified
1371 # @param self The object pointer
1372 # @param Fd The current Firmware device object
1373 # @param Wa Workspace context information
1375 def __init__(self
, Fd
, Wa
):
1376 self
.FdName
= Fd
.FdUiName
1377 self
.BaseAddress
= Fd
.BaseAddress
1379 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1382 # Generate report for the firmware device.
1384 # This function generates report for the firmware device.
1386 # @param self The object pointer
1387 # @param File The file object for report
1389 def GenerateReport(self
, File
):
1390 FileWrite(File
, gSectionStart
)
1391 FileWrite(File
, "Firmware Device (FD)")
1392 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1393 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1394 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1395 if len(self
.FdRegionList
) > 0:
1396 FileWrite(File
, gSectionSep
)
1397 for FdRegionItem
in self
.FdRegionList
:
1398 FdRegionItem
.GenerateReport(File
)
1400 FileWrite(File
, gSectionEnd
)
1405 # Reports platform information
1407 # This class reports the whole platform information
1409 class PlatformReport(object):
1411 # Constructor function for class PlatformReport
1413 # This constructor function generates PlatformReport object a platform build.
1414 # It generates report for platform summary, flash, global PCDs and detailed
1415 # module information for modules involved in platform build.
1417 # @param self The object pointer
1418 # @param Wa Workspace context information
1419 # @param MaList The list of modules in the platform build
1421 def __init__(self
, Wa
, MaList
, ReportType
):
1422 self
._WorkspaceDir
= Wa
.WorkspaceDir
1423 self
.PlatformName
= Wa
.Name
1424 self
.PlatformDscPath
= Wa
.Platform
1425 self
.Architectures
= " ".join(Wa
.ArchList
)
1426 self
.ToolChain
= Wa
.ToolChain
1427 self
.Target
= Wa
.BuildTarget
1428 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1429 self
.BuildEnvironment
= platform
.platform()
1431 self
.PcdReport
= None
1432 if "PCD" in ReportType
:
1433 self
.PcdReport
= PcdReport(Wa
)
1435 self
.FdReportList
= []
1436 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1437 for Fd
in Wa
.FdfProfile
.FdDict
:
1438 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1440 self
.PredictionReport
= None
1441 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1442 self
.PredictionReport
= PredictionReport(Wa
)
1444 self
.DepexParser
= None
1445 if "DEPEX" in ReportType
:
1446 self
.DepexParser
= DepexParser(Wa
)
1448 self
.ModuleReportList
= []
1450 self
._IsModuleBuild
= True
1452 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1454 self
._IsModuleBuild
= False
1455 for Pa
in Wa
.AutoGenObjectList
:
1456 for ModuleKey
in Pa
.Platform
.Modules
:
1457 self
.ModuleReportList
.append(ModuleReport(Pa
.Platform
.Modules
[ModuleKey
].M
, ReportType
))
1462 # Generate report for the whole platform.
1464 # This function generates report for platform information.
1465 # It comprises of platform summary, global PCD, flash and
1466 # module list sections.
1468 # @param self The object pointer
1469 # @param File The file object for report
1470 # @param BuildDuration The total time to build the modules
1471 # @param ReportType The kind of report items in the final report file
1473 def GenerateReport(self
, File
, BuildDuration
, ReportType
):
1474 FileWrite(File
, "Platform Summary")
1475 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1476 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1477 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1478 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1479 FileWrite(File
, "Target: %s" % self
.Target
)
1480 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1481 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1482 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1483 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1485 if not self
._IsModuleBuild
:
1486 if "PCD" in ReportType
:
1487 self
.PcdReport
.GenerateReport(File
, None)
1489 if "FLASH" in ReportType
:
1490 for FdReportListItem
in self
.FdReportList
:
1491 FdReportListItem
.GenerateReport(File
)
1493 for ModuleReportItem
in self
.ModuleReportList
:
1494 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
1496 if not self
._IsModuleBuild
:
1497 if "EXECUTION_ORDER" in ReportType
:
1498 self
.PredictionReport
.GenerateReport(File
, None)
1500 ## BuildReport class
1502 # This base class contain the routines to collect data and then
1503 # applies certain format to the output report
1505 class BuildReport(object):
1507 # Constructor function for class BuildReport
1509 # This constructor function generates BuildReport object a platform build.
1510 # It generates report for platform summary, flash, global PCDs and detailed
1511 # module information for modules involved in platform build.
1513 # @param self The object pointer
1514 # @param ReportFile The file name to save report file
1515 # @param ReportType The kind of report items in the final report file
1517 def __init__(self
, ReportFile
, ReportType
):
1518 self
.ReportFile
= ReportFile
1520 self
.ReportList
= []
1521 self
.ReportType
= []
1523 for ReportTypeItem
in ReportType
:
1524 if ReportTypeItem
not in self
.ReportType
:
1525 self
.ReportType
.append(ReportTypeItem
)
1527 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]
1529 # Adds platform report to the list
1531 # This function adds a platform report to the final report list.
1533 # @param self The object pointer
1534 # @param Wa Workspace context information
1535 # @param MaList The list of modules in the platform build
1537 def AddPlatformReport(self
, Wa
, MaList
=None):
1539 self
.ReportList
.append((Wa
, MaList
))
1542 # Generates the final report.
1544 # This function generates platform build report. It invokes GenerateReport()
1545 # method for every platform report in the list.
1547 # @param self The object pointer
1548 # @param BuildDuration The total time to build the modules
1550 def GenerateReport(self
, BuildDuration
):
1554 for (Wa
, MaList
) in self
.ReportList
:
1555 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, self
.ReportType
)
1556 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
1557 SaveFileOnChange(self
.ReportFile
, Content
, True)
1558 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
1560 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1562 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1563 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1566 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1567 if __name__
== '__main__':