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 - 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
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.
19 import Common
.LongFilePathOs
as os
30 from datetime
import datetime
31 from StringIO
import StringIO
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
.String
import NormPath
46 from Common
.DataType
import *
48 from Common
.Expression
import *
50 gComponentType2ModuleType
= {
52 "SECURITY_CORE" : "SEC",
53 "PEI_CORE" : "PEI_CORE",
54 "COMBINED_PEIM_DRIVER" : "PEIM",
56 "RELOCATABLE_PEIM" : "PEIM",
58 "BS_DRIVER" : "DXE_DRIVER",
59 "RT_DRIVER" : "DXE_RUNTIME_DRIVER",
60 "SAL_RT_DRIVER" : "DXE_SAL_DRIVER",
61 "APPLICATION" : "UEFI_APPLICATION",
65 ## Pattern to extract contents in EDK DXS files
66 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
68 ## Pattern to find total FV total size, occupied size in flash report intermediate file
69 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
70 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
72 ## Pattern to find module size and time stamp in module summary report intermediate file
73 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
74 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
76 ## Pattern to find GUID value in flash description files
77 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
79 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
80 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
82 ## Pattern to find module base address and entry point in fixed flash map file
83 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
84 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
86 ## Pattern to find all module referenced header files in source files
87 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
88 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
90 ## Pattern to find the entry point for EDK module using EDKII Glue library
91 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
93 ## Tags for MaxLength of line in report
96 ## Tags for end of line in report
99 ## Tags for section start, end and separator
100 gSectionStart
= ">" + "=" * (gLineMaxLength
- 2) + "<"
101 gSectionEnd
= "<" + "=" * (gLineMaxLength
- 2) + ">" + "\n"
102 gSectionSep
= "=" * gLineMaxLength
104 ## Tags for subsection start, end and separator
105 gSubSectionStart
= ">" + "-" * (gLineMaxLength
- 2) + "<"
106 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
- 2) + ">"
107 gSubSectionSep
= "-" * gLineMaxLength
110 ## The look up table to map PCD type to pair of report display type and DEC type
112 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
113 'PatchableInModule': ('PATCH', 'PatchableInModule'),
114 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
115 'Dynamic' : ('DYN', 'Dynamic'),
116 'DynamicHii' : ('DYNHII', 'Dynamic'),
117 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
118 'DynamicEx' : ('DEX', 'DynamicEx'),
119 'DynamicExHii' : ('DEXHII', 'DynamicEx'),
120 'DynamicExVpd' : ('DEXVPD', 'DynamicEx'),
123 ## The look up table to map module type to driver type
125 'SEC' : '0x3 (SECURITY_CORE)',
126 'PEI_CORE' : '0x4 (PEI_CORE)',
127 'PEIM' : '0x6 (PEIM)',
128 'DXE_CORE' : '0x5 (DXE_CORE)',
129 'DXE_DRIVER' : '0x7 (DRIVER)',
130 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
131 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
132 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
133 'UEFI_DRIVER' : '0x7 (DRIVER)',
134 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
135 'SMM_CORE' : '0xD (SMM_CORE)',
136 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
137 'MM_STANDALONE' : '0xE (MM_STANDALONE)',
138 'MM_CORE_STANDALONE' : '0xF (MM_CORE_STANDALONE)'
141 ## The look up table of the supported opcode in the dependency expression binaries
142 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
145 # Writes a string to the file object.
147 # This function writes a string to the file object and a new line is appended
148 # afterwards. It may optionally wraps the string for better readability.
150 # @File The file object to write
151 # @String The string to be written to the file
152 # @Wrapper Indicates whether to wrap the string
154 def FileWrite(File
, String
, Wrapper
=False):
156 String
= textwrap
.fill(String
, 120)
157 File
.write(String
+ gEndOfLine
)
159 def ByteArrayForamt(Value
):
163 if Value
.startswith('{') and Value
.endswith('}'):
165 ValueList
= Value
.split(',')
166 if len(ValueList
) >= SplitNum
:
170 Len
= len(ValueList
)/SplitNum
171 for i
, element
in enumerate(ValueList
):
172 ValueList
[i
] = '0x%02X' % int(element
.strip(), 16)
176 End
= min(SplitNum
*(Id
+1), len(ValueList
))
177 Str
= ','.join(ValueList
[SplitNum
*Id
: End
])
178 if End
== len(ValueList
):
180 ArrayList
.append(Str
)
184 ArrayList
.append(Str
)
187 ArrayList
= [Value
+ '}']
188 return IsByteArray
, ArrayList
191 # Find all the header file that the module source directly includes.
193 # This function scans source code to find all header files the module may
194 # include. This is not accurate but very effective to find all the header
195 # file the module might include with #include statement.
197 # @Source The source file name
198 # @IncludePathList The list of include path to find the source file.
199 # @IncludeFiles The dictionary of current found include files.
201 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
202 FileContents
= open(Source
).read()
204 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
206 for Match
in gIncludePattern
.finditer(FileContents
):
207 FileName
= Match
.group(1).strip()
208 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
209 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
210 if os
.path
.exists(FullFileName
):
211 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
215 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
217 for Match
in gIncludePattern2
.finditer(FileContents
):
219 Type
= Match
.group(1)
220 if "ARCH_PROTOCOL" in Type
:
221 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
222 elif "PROTOCOL" in Type
:
223 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
225 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
227 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
230 for Dir
in IncludePathList
:
231 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
232 if os
.path
.exists(FullFileName
):
233 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
236 ## Split each lines in file
238 # This method is used to split the lines in file to make the length of each line
239 # less than MaxLength.
241 # @param Content The content of file
242 # @param MaxLength The Max Length of the line
244 def FileLinesSplit(Content
=None, MaxLength
=None):
245 ContentList
= Content
.split(TAB_LINE_BREAK
)
248 for Line
in ContentList
:
249 while len(Line
.rstrip()) > MaxLength
:
250 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
251 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
252 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
253 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
254 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
256 LineBreakIndex
= MaxLength
257 NewContentList
.append(Line
[:LineBreakIndex
])
258 Line
= Line
[LineBreakIndex
:]
260 NewContentList
.append(Line
)
261 for NewLine
in NewContentList
:
262 NewContent
+= NewLine
+ TAB_LINE_BREAK
264 NewContent
= NewContent
.replace(TAB_LINE_BREAK
, gEndOfLine
).replace('\r\r\n', gEndOfLine
)
270 # Parse binary dependency expression section
272 # This utility class parses the dependency expression section and translate the readable
273 # GUID name and value.
275 class DepexParser(object):
277 # Constructor function for class DepexParser
279 # This constructor function collect GUID values so that the readable
280 # GUID name can be translated.
282 # @param self The object pointer
283 # @param Wa Workspace context information
285 def __init__(self
, Wa
):
287 for Pa
in Wa
.AutoGenObjectList
:
288 for Package
in Pa
.PackageList
:
289 for Protocol
in Package
.Protocols
:
290 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
291 self
._GuidDb
[GuidValue
.upper()] = Protocol
292 for Ppi
in Package
.Ppis
:
293 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
294 self
._GuidDb
[GuidValue
.upper()] = Ppi
295 for Guid
in Package
.Guids
:
296 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
297 self
._GuidDb
[GuidValue
.upper()] = Guid
300 # Parse the binary dependency expression files.
302 # This function parses the binary dependency expression file and translate it
303 # to the instruction list.
305 # @param self The object pointer
306 # @param DepexFileName The file name of binary dependency expression file.
308 def ParseDepexFile(self
, DepexFileName
):
309 DepexFile
= open(DepexFileName
, "rb")
311 OpCode
= DepexFile
.read(1)
313 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
314 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
315 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
316 struct
.unpack("=LHHBBBBBBBB", DepexFile
.read(16))
317 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
318 Statement
= "%s %s" % (Statement
, GuidString
)
319 DepexStatement
.append(Statement
)
320 OpCode
= DepexFile
.read(1)
322 return DepexStatement
325 # Reports library information
327 # This class reports the module library subsection in the build report file.
329 class LibraryReport(object):
331 # Constructor function for class LibraryReport
333 # This constructor function generates LibraryReport object for
336 # @param self The object pointer
337 # @param M Module context information
339 def __init__(self
, M
):
340 self
.LibraryList
= []
341 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
342 self
._EdkIIModule
= True
344 self
._EdkIIModule
= False
346 for Lib
in M
.DependentLibraryList
:
347 LibInfPath
= str(Lib
)
348 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
349 LibConstructorList
= Lib
.ConstructorList
350 LibDesstructorList
= Lib
.DestructorList
351 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
352 for LibAutoGen
in M
.LibraryAutoGenList
:
353 if LibInfPath
== LibAutoGen
.MetaFile
.Path
:
354 LibTime
= LibAutoGen
.BuildTime
356 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
, LibTime
))
359 # Generate report for module library information
361 # This function generates report for the module library.
362 # If the module is EDKII style one, the additional library class, library
363 # constructor/destructor and dependency expression may also be reported.
365 # @param self The object pointer
366 # @param File The file object for report
368 def GenerateReport(self
, File
):
369 if len(self
.LibraryList
) > 0:
370 FileWrite(File
, gSubSectionStart
)
371 FileWrite(File
, TAB_BRG_LIBRARY
)
372 FileWrite(File
, gSubSectionSep
)
373 for LibraryItem
in self
.LibraryList
:
374 LibInfPath
= LibraryItem
[0]
375 FileWrite(File
, LibInfPath
)
378 # Report library class, library constructor and destructor for
379 # EDKII style module.
381 if self
._EdkIIModule
:
382 LibClass
= LibraryItem
[1]
384 LibConstructor
= " ".join(LibraryItem
[2])
386 EdkIILibInfo
+= " C = " + LibConstructor
387 LibDestructor
= " ".join(LibraryItem
[3])
389 EdkIILibInfo
+= " D = " + LibDestructor
390 LibDepex
= " ".join(LibraryItem
[4])
392 EdkIILibInfo
+= " Depex = " + LibDepex
394 EdkIILibInfo
+= " Time = " + LibraryItem
[5]
396 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
398 FileWrite(File
, "{%s}" % LibClass
)
400 FileWrite(File
, gSubSectionEnd
)
403 # Reports dependency expression information
405 # This class reports the module dependency expression subsection in the build report file.
407 class DepexReport(object):
409 # Constructor function for class DepexReport
411 # This constructor function generates DepexReport object for
412 # a module. If the module source contains the DXS file (usually EDK
413 # style module), it uses the dependency in DXS file; otherwise,
414 # it uses the dependency expression from its own INF [Depex] section
415 # and then merges with the ones from its dependent library INF.
417 # @param self The object pointer
418 # @param M Module context information
420 def __init__(self
, M
):
422 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
423 ModuleType
= M
.ModuleType
425 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
427 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "MM_CORE_STANDALONE", "UEFI_APPLICATION"]:
430 for Source
in M
.SourceFileList
:
431 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
432 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
434 self
.Depex
= Match
.group(1).strip()
438 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
439 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
440 if not self
.ModuleDepex
:
441 self
.ModuleDepex
= "(None)"
444 for Lib
in M
.DependentLibraryList
:
445 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
447 LibDepexList
.append("(" + LibDepex
+ ")")
448 self
.LibraryDepex
= " AND ".join(LibDepexList
)
449 if not self
.LibraryDepex
:
450 self
.LibraryDepex
= "(None)"
454 # Generate report for module dependency expression information
456 # This function generates report for the module dependency expression.
458 # @param self The object pointer
459 # @param File The file object for report
460 # @param GlobalDepexParser The platform global Dependency expression parser object
462 def GenerateReport(self
, File
, GlobalDepexParser
):
465 FileWrite(File
, gSubSectionStart
)
466 if os
.path
.isfile(self
._DepexFileName
):
468 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
469 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
470 for DepexStatement
in DepexStatements
:
471 FileWrite(File
, " %s" % DepexStatement
)
472 FileWrite(File
, gSubSectionSep
)
474 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
476 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
478 if self
.Source
== "INF":
479 FileWrite(File
, "%s" % self
.Depex
, True)
480 FileWrite(File
, gSubSectionSep
)
481 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
482 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
484 FileWrite(File
, "%s" % self
.Depex
)
485 FileWrite(File
, gSubSectionEnd
)
488 # Reports dependency expression information
490 # This class reports the module build flags subsection in the build report file.
492 class BuildFlagsReport(object):
494 # Constructor function for class BuildFlagsReport
496 # This constructor function generates BuildFlagsReport object for
497 # a module. It reports the build tool chain tag and all relevant
498 # build flags to build the module.
500 # @param self The object pointer
501 # @param M Module context information
503 def __init__(self
, M
):
506 # Add build flags according to source file extension so that
507 # irrelevant ones can be filtered out.
509 for Source
in M
.SourceFileList
:
510 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
511 if Ext
in [".c", ".cc", ".cpp"]:
512 BuildOptions
["CC"] = 1
513 elif Ext
in [".s", ".asm"]:
514 BuildOptions
["PP"] = 1
515 BuildOptions
["ASM"] = 1
516 elif Ext
in [".vfr"]:
517 BuildOptions
["VFRPP"] = 1
518 BuildOptions
["VFR"] = 1
519 elif Ext
in [".dxs"]:
520 BuildOptions
["APP"] = 1
521 BuildOptions
["CC"] = 1
522 elif Ext
in [".asl"]:
523 BuildOptions
["ASLPP"] = 1
524 BuildOptions
["ASL"] = 1
525 elif Ext
in [".aslc"]:
526 BuildOptions
["ASLCC"] = 1
527 BuildOptions
["ASLDLINK"] = 1
528 BuildOptions
["CC"] = 1
529 elif Ext
in [".asm16"]:
530 BuildOptions
["ASMLINK"] = 1
531 BuildOptions
["SLINK"] = 1
532 BuildOptions
["DLINK"] = 1
535 # Save module build flags.
537 self
.ToolChainTag
= M
.ToolChain
539 for Tool
in BuildOptions
:
540 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
543 # Generate report for module build flags information
545 # This function generates report for the module build flags expression.
547 # @param self The object pointer
548 # @param File The file object for report
550 def GenerateReport(self
, File
):
551 FileWrite(File
, gSubSectionStart
)
552 FileWrite(File
, "Build Flags")
553 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
554 for Tool
in self
.BuildFlags
:
555 FileWrite(File
, gSubSectionSep
)
556 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
558 FileWrite(File
, gSubSectionEnd
)
562 # Reports individual module information
564 # This class reports the module section in the build report file.
565 # It comprises of module summary, module PCD, library, dependency expression,
566 # build flags sections.
568 class ModuleReport(object):
570 # Constructor function for class ModuleReport
572 # This constructor function generates ModuleReport object for
573 # a separate module in a platform build.
575 # @param self The object pointer
576 # @param M Module context information
577 # @param ReportType The kind of report items in the final report file
579 def __init__(self
, M
, ReportType
):
580 self
.ModuleName
= M
.Module
.BaseName
581 self
.ModuleInfPath
= M
.MetaFile
.File
582 self
.FileGuid
= M
.Guid
584 self
.BuildTimeStamp
= None
588 ModuleType
= M
.ModuleType
590 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
592 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
594 if ModuleType
== "DXE_SMM_DRIVER":
595 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
596 if int(PiSpec
, 0) >= 0x0001000A:
597 ModuleType
= "SMM_DRIVER"
598 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
599 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
600 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
601 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
602 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
603 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
604 self
.BuildTime
= M
.BuildTime
606 self
._BuildDir
= M
.BuildDir
607 self
.ModulePcdSet
= {}
608 if "PCD" in ReportType
:
610 # Collect all module used PCD set: module INF referenced directly or indirectly.
611 # It also saves module INF default values of them in case they exist.
613 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
614 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
616 self
.LibraryReport
= None
617 if "LIBRARY" in ReportType
:
618 self
.LibraryReport
= LibraryReport(M
)
620 self
.DepexReport
= None
621 if "DEPEX" in ReportType
:
622 self
.DepexReport
= DepexReport(M
)
624 if "BUILD_FLAGS" in ReportType
:
625 self
.BuildFlagsReport
= BuildFlagsReport(M
)
629 # Generate report for module information
631 # This function generates report for separate module expression
632 # in a platform build.
634 # @param self The object pointer
635 # @param File The file object for report
636 # @param GlobalPcdReport The platform global PCD report object
637 # @param GlobalPredictionReport The platform global Prediction report object
638 # @param GlobalDepexParser The platform global Dependency expression parser object
639 # @param ReportType The kind of report items in the final report file
641 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
642 FileWrite(File
, gSectionStart
)
644 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
645 if os
.path
.isfile(FwReportFileName
):
647 FileContents
= open(FwReportFileName
).read()
648 Match
= gModuleSizePattern
.search(FileContents
)
650 self
.Size
= int(Match
.group(1))
652 Match
= gTimeStampPattern
.search(FileContents
)
654 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
656 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
658 if "HASH" in ReportType
:
659 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
660 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
661 if os
.path
.isfile(DefaultEFIfile
):
662 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
663 # rebase the efi image since its base address may not zero
664 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
666 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
668 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
669 EndOfProcedure
= threading
.Event()
670 EndOfProcedure
.clear()
671 if PopenObject
.stderr
:
672 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
673 StdErrThread
.setName("STDERR-Redirector")
674 StdErrThread
.setDaemon(False)
676 # waiting for program exit
678 if PopenObject
.stderr
:
680 if PopenObject
.returncode
!= 0:
681 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
682 if os
.path
.isfile(Tempfile
):
683 self
.Hash
= hashlib
.sha1()
684 buf
= open(Tempfile
, 'rb').read()
685 if self
.Hash
.update(buf
):
686 self
.Hash
= self
.Hash
.update(buf
)
687 self
.Hash
= self
.Hash
.hexdigest()
690 FileWrite(File
, "Module Summary")
691 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
692 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
693 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
695 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
697 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
698 if self
.BuildTimeStamp
:
699 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
701 FileWrite(File
, "Module Build Time: %s" % self
.BuildTime
)
703 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
704 if self
.UefiSpecVersion
:
705 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
706 if self
.PiSpecVersion
:
707 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
709 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
711 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
712 if self
.PciClassCode
:
713 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
715 FileWrite(File
, gSectionSep
)
717 if "PCD" in ReportType
:
718 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
720 if "LIBRARY" in ReportType
:
721 self
.LibraryReport
.GenerateReport(File
)
723 if "DEPEX" in ReportType
:
724 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
726 if "BUILD_FLAGS" in ReportType
:
727 self
.BuildFlagsReport
.GenerateReport(File
)
729 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
730 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
732 FileWrite(File
, gSectionEnd
)
734 def ReadMessage(From
, To
, ExitFlag
):
736 # read one line a time
737 Line
= From
.readline()
738 # empty string means "end"
739 if Line
is not None and Line
!= "":
747 # Reports platform and module PCD information
749 # This class reports the platform PCD section and module PCD subsection
750 # in the build report file.
752 class PcdReport(object):
754 # Constructor function for class PcdReport
756 # This constructor function generates PcdReport object a platform build.
757 # It collects the whole PCD database from platform DSC files, platform
758 # flash description file and package DEC files.
760 # @param self The object pointer
761 # @param Wa Workspace context information
763 def __init__(self
, Wa
):
766 self
.ConditionalPcds
= {}
770 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
774 self
.DefaultStoreSingle
= True
775 self
.SkuSingle
= True
776 if GlobalData
.gDefaultStores
and len(GlobalData
.gDefaultStores
) > 1:
777 self
.DefaultStoreSingle
= False
778 if GlobalData
.gSkuids
and len(GlobalData
.gSkuids
) > 1:
779 self
.SkuSingle
= False
781 self
.ModulePcdOverride
= {}
782 for Pa
in Wa
.AutoGenObjectList
:
785 # Collect all platform referenced PCDs and grouped them by PCD token space
788 for Pcd
in Pa
.AllPcdList
:
789 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
790 if Pcd
not in PcdList
:
792 if len(Pcd
.TokenCName
) > self
.MaxLen
:
793 self
.MaxLen
= len(Pcd
.TokenCName
)
795 # Collect the PCD defined in DSC/FDF file, but not used in module
797 UnusedPcdFullList
= []
798 for item
in Pa
.Platform
.Pcds
:
799 Pcd
= Pa
.Platform
.Pcds
[item
]
801 # check the Pcd in FDF file, whether it is used in module first
802 for T
in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:
803 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
809 for package
in Pa
.PackageList
:
810 for T
in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:
811 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
814 if not Pcd
.DatumType
:
815 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
819 if not Pcd
.DatumType
:
821 # Try to remove Hii and Vpd suffix
822 if PcdType
.startswith("DynamicEx"):
823 PcdType
= "DynamicEx"
824 elif PcdType
.startswith("Dynamic"):
826 for package
in Pa
.PackageList
:
827 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
828 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
831 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
832 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
833 UnusedPcdFullList
.append(Pcd
)
834 if len(Pcd
.TokenCName
) > self
.MaxLen
:
835 self
.MaxLen
= len(Pcd
.TokenCName
)
837 if GlobalData
.gConditionalPcds
:
838 for PcdItem
in GlobalData
.gConditionalPcds
:
840 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
841 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
.keys():
842 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
843 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
844 if Pcd
not in PcdList
:
848 if UnusedPcdFullList
:
849 for Pcd
in UnusedPcdFullList
:
850 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
852 UnusedPcdList
.append(Pcd
)
854 for Pcd
in UnusedPcdList
:
855 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
856 if Pcd
not in PcdList
:
859 for Module
in Pa
.Platform
.Modules
.values():
861 # Collect module override PCDs
863 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
864 TokenCName
= ModulePcd
.TokenCName
865 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
866 ModuleDefault
= ModulePcd
.DefaultValue
867 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
868 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
872 # Collect PCD DEC default value.
874 self
.DecPcdDefault
= {}
876 for Pa
in Wa
.AutoGenObjectList
:
877 for Package
in Pa
.PackageList
:
878 Guids
= Package
.Guids
879 self
._GuidDict
.update(Guids
)
880 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
881 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
882 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
884 # Collect PCDs defined in DSC common section
886 self
.DscPcdDefault
= {}
887 for Pa
in Wa
.AutoGenObjectList
:
888 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
889 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DscDefaultValue
891 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
893 def GenerateReport(self
, File
, ModulePcdSet
):
895 if self
.ConditionalPcds
:
896 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
898 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
899 self
.GenerateReportDetail(File
, ModulePcdSet
)
902 # Generate report for PCD information
904 # This function generates report for separate module expression
905 # in a platform build.
907 # @param self The object pointer
908 # @param File The file object for report
909 # @param ModulePcdSet Set of all PCDs referenced by module or None for
910 # platform PCD report
911 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
912 # directives section report, 2 means Unused Pcds section report
913 # @param DscOverridePcds Module DSC override PCDs set
915 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
916 PcdDict
= self
.AllPcds
917 if ReportSubType
== 1:
918 PcdDict
= self
.ConditionalPcds
919 elif ReportSubType
== 2:
920 PcdDict
= self
.UnusedPcds
923 FileWrite(File
, gSectionStart
)
924 if ReportSubType
== 1:
925 FileWrite(File
, "Conditional Directives used by the build system")
926 elif ReportSubType
== 2:
927 FileWrite(File
, "PCDs not used by modules or in conditional directives")
929 FileWrite(File
, "Platform Configuration Database Report")
931 FileWrite(File
, " *B - PCD override in the build option")
932 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
933 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
934 if not ReportSubType
:
935 FileWrite(File
, " *M - Module scoped PCD override")
936 FileWrite(File
, gSectionSep
)
938 if not ReportSubType
and ModulePcdSet
:
940 # For module PCD sub-section
942 FileWrite(File
, gSubSectionStart
)
943 FileWrite(File
, TAB_BRG_PCD
)
944 FileWrite(File
, gSubSectionSep
)
948 # Group PCD by their token space GUID C Name
951 for Type
in PcdDict
[Key
]:
953 # Group PCD by their usage type
955 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
956 for Pcd
in PcdDict
[Key
][Type
]:
957 PcdTokenCName
= Pcd
.TokenCName
959 if GlobalData
.MixedPcd
:
960 for PcdKey
in GlobalData
.MixedPcd
:
961 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
962 PcdTokenCName
= PcdKey
[0]
964 if MixedPcdFlag
and not ModulePcdSet
:
967 # Get PCD default value and their override relationship
969 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
970 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
971 DscDefaultValBak
= DscDefaultValue
972 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
973 if DscDefaultValue
!= DscDefaultValBak
:
975 DscDefaultValue
= ValueExpressionEx(DscDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
976 except BadExpression
, DscDefaultValue
:
977 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" %(DscDefaultValue
, Pcd
.DatumType
))
979 InfDefaultValue
= None
981 PcdValue
= DecDefaultValue
983 PcdValue
= DscDefaultValue
984 if ModulePcdSet
is not None:
985 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
987 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
988 Pcd
.DefaultValue
= PcdValue
992 BuildOptionMatch
= False
993 if GlobalData
.BuildOptionPcd
:
994 for pcd
in GlobalData
.BuildOptionPcd
:
995 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
999 Pcd
.DefaultValue
= PcdValue
1000 BuildOptionMatch
= True
1004 if ModulePcdSet
is None:
1006 FileWrite(File
, Key
)
1010 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
1011 PcdValueNumber
= int(PcdValue
.strip(), 0)
1012 if DecDefaultValue
is None:
1015 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
1016 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
1018 if InfDefaultValue
is None:
1021 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
1022 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
1024 if DscDefaultValue
is None:
1027 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
1028 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
1030 if DecDefaultValue
is None:
1033 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
1035 if InfDefaultValue
is None:
1038 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
1040 if DscDefaultValue
is None:
1043 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
1046 if GlobalData
.gStructurePcd
and (self
.Arch
in GlobalData
.gStructurePcd
.keys()) and ((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.gStructurePcd
[self
.Arch
]):
1048 if TypeName
in ('DYNVPD', 'DEXVPD'):
1049 SkuInfoList
= Pcd
.SkuInfoList
1050 Pcd
= GlobalData
.gStructurePcd
[self
.Arch
][(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
)]
1051 Pcd
.DatumType
= Pcd
.StructName
1052 if TypeName
in ('DYNVPD', 'DEXVPD'):
1053 Pcd
.SkuInfoList
= SkuInfoList
1054 if Pcd
.PcdFieldValueFromComm
:
1055 BuildOptionMatch
= True
1057 elif Pcd
.SkuOverrideValues
:
1059 if not Pcd
.SkuInfoList
:
1060 OverrideValues
= Pcd
.SkuOverrideValues
1062 Keys
= OverrideValues
.keys()
1063 Data
= OverrideValues
[Keys
[0]]
1064 Struct
= Data
.values()[0]
1065 DscOverride
= self
.ParseStruct(Struct
)
1067 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1069 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1070 if TypeName
in ('DYNHII', 'DEXHII'):
1071 if SkuInfo
.DefaultStoreDict
:
1072 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1073 for DefaultStore
in DefaultStoreList
:
1074 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1075 DscOverride
= self
.ParseStruct(OverrideValues
[DefaultStore
])
1079 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1081 Keys
= OverrideValues
.keys()
1082 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1083 DscOverride
= self
.ParseStruct(OverrideFieldStruct
)
1091 # Report PCD item according to their override relationship
1093 if DecMatch
and InfMatch
:
1094 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, ' ')
1095 elif BuildOptionMatch
:
1096 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*B')
1099 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
1100 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*F')
1102 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*P')
1104 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1106 if ModulePcdSet
is None:
1109 if not TypeName
in ('PATCH', 'FLAG', 'FIXED'):
1111 if not BuildOptionMatch
:
1112 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1113 for ModulePath
in ModuleOverride
:
1114 ModuleDefault
= ModuleOverride
[ModulePath
]
1115 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
1116 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1117 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1119 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1122 IsByteArray
, ArrayList
= ByteArrayForamt(ModuleDefault
.strip())
1124 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, '{'))
1125 for Array
in ArrayList
:
1126 FileWrite(File
, '%s' % (Array
))
1128 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
1130 if ModulePcdSet
is None:
1131 FileWrite(File
, gSectionEnd
)
1133 if not ReportSubType
and ModulePcdSet
:
1134 FileWrite(File
, gSubSectionEnd
)
1136 def ParseStruct(self
, struct
):
1137 HasDscOverride
= False
1139 for _
, Values
in struct
.items():
1140 if Values
[1] and Values
[1].endswith('.dsc'):
1141 HasDscOverride
= True
1143 return HasDscOverride
1145 def PrintPcdDefault(self
, File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
):
1146 if not DscMatch
and DscDefaultValue
is not None:
1147 Value
= DscDefaultValue
.strip()
1148 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1150 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', "{"))
1151 for Array
in ArrayList
:
1152 FileWrite(File
, '%s' % (Array
))
1154 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', Value
))
1155 if not InfMatch
and InfDefaultValue
is not None:
1156 Value
= InfDefaultValue
.strip()
1157 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1159 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', "{"))
1160 for Array
in ArrayList
:
1161 FileWrite(File
, '%s' % (Array
))
1163 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', Value
))
1165 if not DecMatch
and DecDefaultValue
is not None:
1166 Value
= DecDefaultValue
.strip()
1167 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1169 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', "{"))
1170 for Array
in ArrayList
:
1171 FileWrite(File
, '%s' % (Array
))
1173 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', Value
))
1175 self
.PrintStructureInfo(File
, Pcd
.DefaultValues
)
1176 if DecMatch
and IsStructure
:
1177 self
.PrintStructureInfo(File
, Pcd
.DefaultValues
)
1179 def PrintPcdValue(self
, File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, Flag
= ' '):
1180 if not Pcd
.SkuInfoList
:
1181 Value
= Pcd
.DefaultValue
1182 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1184 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1185 for Array
in ArrayList
:
1186 FileWrite(File
, '%s' % (Array
))
1188 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1190 OverrideValues
= Pcd
.SkuOverrideValues
1192 Keys
= OverrideValues
.keys()
1193 Data
= OverrideValues
[Keys
[0]]
1194 Struct
= Data
.values()[0]
1195 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, Struct
)
1196 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1197 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1200 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1202 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1203 SkuIdName
= SkuInfo
.SkuIdName
1204 if TypeName
in ('DYNHII', 'DEXHII'):
1205 if SkuInfo
.DefaultStoreDict
:
1206 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1207 for DefaultStore
in DefaultStoreList
:
1208 Value
= SkuInfo
.DefaultStoreDict
[DefaultStore
]
1209 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1213 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1214 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1215 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1216 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1217 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1218 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1220 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1221 for Array
in ArrayList
:
1222 FileWrite(File
, '%s' % (Array
))
1224 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1225 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1226 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1227 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1228 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1229 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1231 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1234 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1235 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1236 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1237 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1238 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1239 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1241 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1242 for Array
in ArrayList
:
1243 FileWrite(File
, '%s' % (Array
))
1245 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1246 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1247 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1248 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1249 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1250 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1252 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1253 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1255 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1256 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[DefaultStore
])
1257 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1258 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1260 Value
= SkuInfo
.DefaultValue
1261 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1266 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1268 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1269 for Array
in ArrayList
:
1270 FileWrite(File
, '%s' % (Array
))
1273 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1275 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1279 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ' , TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1281 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ' , TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1282 for Array
in ArrayList
:
1283 FileWrite(File
, '%s' % (Array
))
1286 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ' , TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1288 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ' , TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1289 if TypeName
in ('DYNVPD', 'DEXVPD'):
1290 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1292 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1294 Keys
= OverrideValues
.keys()
1295 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1296 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1297 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1299 def OverrideFieldValue(self
, Pcd
, OverrideStruct
):
1300 OverrideFieldStruct
= collections
.OrderedDict()
1302 for Key
, Values
in OverrideStruct
.items():
1303 if Values
[1] and Values
[1].endswith('.dsc'):
1304 OverrideFieldStruct
[Key
] = Values
1305 if Pcd
.PcdFieldValueFromComm
:
1306 for Key
, Values
in Pcd
.PcdFieldValueFromComm
.items():
1307 OverrideFieldStruct
[Key
] = Values
1308 return OverrideFieldStruct
1310 def PrintStructureInfo(self
, File
, Struct
):
1311 for Key
, Value
in Struct
.items():
1312 if Value
[1] and 'build command options' in Value
[1]:
1313 FileWrite(File
, ' *B %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1315 FileWrite(File
, ' %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1317 def StrtoHex(self
, value
):
1319 value
= hex(int(value
))
1322 if value
.startswith("L\"") and value
.endswith("\""):
1324 for ch
in value
[2:-1]:
1325 valuelist
.append(hex(ord(ch
)))
1326 valuelist
.append('0x00')
1328 elif value
.startswith("\"") and value
.endswith("\""):
1329 return hex(ord(value
[1:-1]))
1330 elif value
.startswith("{") and value
.endswith("}"):
1332 if ',' not in value
:
1334 for ch
in value
[1:-1].split(','):
1336 if ch
.startswith('0x') or ch
.startswith('0X'):
1337 valuelist
.append(ch
)
1340 valuelist
.append(hex(int(ch
.strip())))
1348 # Reports platform and module Prediction information
1350 # This class reports the platform execution order prediction section and
1351 # module load fixed address prediction subsection in the build report file.
1353 class PredictionReport(object):
1355 # Constructor function for class PredictionReport
1357 # This constructor function generates PredictionReport object for the platform.
1359 # @param self: The object pointer
1360 # @param Wa Workspace context information
1362 def __init__(self
, Wa
):
1363 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1364 self
._MapFileParsed
= False
1365 self
._EotToolInvoked
= False
1366 self
._FvDir
= Wa
.FvDir
1367 self
._EotDir
= Wa
.BuildDir
1368 self
._FfsEntryPoint
= {}
1370 self
._SourceList
= []
1371 self
.FixedMapDict
= {}
1376 # Collect all platform reference source files and GUID C Name
1378 for Pa
in Wa
.AutoGenObjectList
:
1379 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1381 # BASE typed modules are EFI agnostic, so we need not scan
1382 # their source code to find PPI/Protocol produce or consume
1385 if Module
.ModuleType
== "BASE":
1388 # Add module referenced source files
1390 self
._SourceList
.append(str(Module
))
1392 for Source
in Module
.SourceFileList
:
1393 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1394 self
._SourceList
.append(" " + str(Source
))
1395 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1396 for IncludeFile
in IncludeList
.values():
1397 self
._SourceList
.append(" " + IncludeFile
)
1399 for Guid
in Module
.PpiList
:
1400 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1401 for Guid
in Module
.ProtocolList
:
1402 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1403 for Guid
in Module
.GuidList
:
1404 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1406 if Module
.Guid
and not Module
.IsLibrary
:
1407 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1408 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
1409 RealEntryPoint
= "_ModuleEntryPoint"
1411 RealEntryPoint
= EntryPoint
1412 if EntryPoint
== "_ModuleEntryPoint":
1413 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
1414 Match
= gGlueLibEntryPoint
.search(CCFlags
)
1416 EntryPoint
= Match
.group(1)
1418 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1422 # Collect platform firmware volume list as the input of EOT.
1426 for Fd
in Wa
.FdfProfile
.FdDict
:
1427 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1428 if FdRegion
.RegionType
!= "FV":
1430 for FvName
in FdRegion
.RegionDataList
:
1431 if FvName
in self
._FvList
:
1433 self
._FvList
.append(FvName
)
1434 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1435 for Section
in Ffs
.SectionList
:
1437 for FvSection
in Section
.SectionList
:
1438 if FvSection
.FvName
in self
._FvList
:
1440 self
._FvList
.append(FvSection
.FvName
)
1441 except AttributeError:
1446 # Parse platform fixed address map files
1448 # This function parses the platform final fixed address map file to get
1449 # the database of predicted fixed address for module image base, entry point
1452 # @param self: The object pointer
1454 def _ParseMapFile(self
):
1455 if self
._MapFileParsed
:
1457 self
._MapFileParsed
= True
1458 if os
.path
.isfile(self
._MapFileName
):
1460 FileContents
= open(self
._MapFileName
).read()
1461 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1462 AddressType
= Match
.group(1)
1463 BaseAddress
= Match
.group(2)
1464 EntryPoint
= Match
.group(3)
1465 Guid
= Match
.group(4).upper()
1466 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1467 List
.append((AddressType
, BaseAddress
, "*I"))
1468 List
.append((AddressType
, EntryPoint
, "*E"))
1470 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1473 # Invokes EOT tool to get the predicted the execution order.
1475 # This function invokes EOT tool to calculate the predicted dispatch order
1477 # @param self: The object pointer
1479 def _InvokeEotTool(self
):
1480 if self
._EotToolInvoked
:
1483 self
._EotToolInvoked
= True
1485 for FvName
in self
._FvList
:
1486 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1487 if os
.path
.isfile(FvFile
):
1488 FvFileList
.append(FvFile
)
1490 if len(FvFileList
) == 0:
1493 # Write source file list and GUID file list to an intermediate file
1494 # as the input for EOT tool and dispatch List as the output file
1497 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1498 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1499 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1501 TempFile
= open(SourceList
, "w+")
1502 for Item
in self
._SourceList
:
1503 FileWrite(TempFile
, Item
)
1505 TempFile
= open(GuidList
, "w+")
1506 for Key
in self
._GuidMap
:
1507 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1511 from Eot
.Eot
import Eot
1514 # Invoke EOT tool and echo its runtime performance
1516 EotStartTime
= time
.time()
1517 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1518 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1519 EotEndTime
= time
.time()
1520 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1521 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1524 # Parse the output of EOT tool
1526 for Line
in open(DispatchList
):
1527 if len(Line
.split()) < 4:
1529 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1530 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1531 if len(Symbol
) > self
.MaxLen
:
1532 self
.MaxLen
= len(Symbol
)
1533 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1535 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1536 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1540 # Generate platform execution order report
1542 # This function generates the predicted module execution order.
1544 # @param self The object pointer
1545 # @param File The file object for report
1547 def _GenerateExecutionOrderReport(self
, File
):
1548 self
._InvokeEotTool
()
1549 if len(self
.ItemList
) == 0:
1551 FileWrite(File
, gSectionStart
)
1552 FileWrite(File
, "Execution Order Prediction")
1553 FileWrite(File
, "*P PEI phase")
1554 FileWrite(File
, "*D DXE phase")
1555 FileWrite(File
, "*E Module INF entry point name")
1556 FileWrite(File
, "*N Module notification function name")
1558 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1559 FileWrite(File
, gSectionSep
)
1560 for Item
in self
.ItemList
:
1561 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1563 FileWrite(File
, gSectionStart
)
1566 # Generate Fixed Address report.
1568 # This function generate the predicted fixed address report for a module
1569 # specified by Guid.
1571 # @param self The object pointer
1572 # @param File The file object for report
1573 # @param Guid The module Guid value.
1574 # @param NotifyList The list of all notify function in a module
1576 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1577 self
._ParseMapFile
()
1578 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1579 if not FixedAddressList
:
1582 FileWrite(File
, gSubSectionStart
)
1583 FileWrite(File
, "Fixed Address Prediction")
1584 FileWrite(File
, "*I Image Loading Address")
1585 FileWrite(File
, "*E Entry Point Address")
1586 FileWrite(File
, "*N Notification Function Address")
1587 FileWrite(File
, "*F Flash Address")
1588 FileWrite(File
, "*M Memory Address")
1589 FileWrite(File
, "*S SMM RAM Offset")
1590 FileWrite(File
, "TOM Top of Memory")
1592 FileWrite(File
, "Type Address Name")
1593 FileWrite(File
, gSubSectionSep
)
1594 for Item
in FixedAddressList
:
1599 Name
= "(Image Base)"
1600 elif Symbol
== "*E":
1601 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1602 elif Symbol
in NotifyList
:
1610 elif "Memory" in Type
:
1616 Value
= "TOM" + Value
1618 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1621 # Generate report for the prediction part
1623 # This function generate the predicted fixed address report for a module or
1624 # predicted module execution order for a platform.
1625 # If the input Guid is None, then, it generates the predicted module execution order;
1626 # otherwise it generated the module fixed loading address for the module specified by
1629 # @param self The object pointer
1630 # @param File The file object for report
1631 # @param Guid The module Guid value.
1633 def GenerateReport(self
, File
, Guid
):
1635 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1637 self
._GenerateExecutionOrderReport
(File
)
1640 # Reports FD region information
1642 # This class reports the FD subsection in the build report file.
1643 # It collects region information of platform flash device.
1644 # If the region is a firmware volume, it lists the set of modules
1645 # and its space information; otherwise, it only lists its region name,
1646 # base address and size in its sub-section header.
1647 # If there are nesting FVs, the nested FVs will list immediate after
1648 # this FD region subsection
1650 class FdRegionReport(object):
1652 # Discover all the nested FV name list.
1654 # This is an internal worker function to discover the all the nested FV information
1655 # in the parent firmware volume. It uses deep first search algorithm recursively to
1656 # find all the FV list name and append them to the list.
1658 # @param self The object pointer
1659 # @param FvName The name of current firmware file system
1660 # @param Wa Workspace context information
1662 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1663 FvDictKey
=FvName
.upper()
1664 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1665 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1666 for Section
in Ffs
.SectionList
:
1668 for FvSection
in Section
.SectionList
:
1669 if FvSection
.FvName
in self
.FvList
:
1671 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1672 self
.FvList
.append(FvSection
.FvName
)
1673 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1674 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1675 except AttributeError:
1679 # Constructor function for class FdRegionReport
1681 # This constructor function generates FdRegionReport object for a specified FdRegion.
1682 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1683 # volume list. This function also collects GUID map in order to dump module identification
1684 # in the final report.
1686 # @param self: The object pointer
1687 # @param FdRegion The current FdRegion object
1688 # @param Wa Workspace context information
1690 def __init__(self
, FdRegion
, Wa
):
1691 self
.Type
= FdRegion
.RegionType
1692 self
.BaseAddress
= FdRegion
.Offset
1693 self
.Size
= FdRegion
.Size
1697 self
._FvDir
= Wa
.FvDir
1698 self
._WorkspaceDir
= Wa
.WorkspaceDir
1701 # If the input FdRegion is not a firmware volume,
1704 if self
.Type
!= "FV":
1708 # Find all nested FVs in the FdRegion
1710 for FvName
in FdRegion
.RegionDataList
:
1711 if FvName
in self
.FvList
:
1713 self
.FvList
.append(FvName
)
1714 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1715 self
._DiscoverNestedFvList
(FvName
, Wa
)
1719 # Collect PCDs declared in DEC files.
1721 for Pa
in Wa
.AutoGenObjectList
:
1722 for Package
in Pa
.PackageList
:
1723 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1724 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1725 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1727 # Collect PCDs defined in DSC file
1729 for Pa
in Wa
.AutoGenObjectList
:
1730 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
1731 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1732 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1735 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1737 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1738 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1740 # Add ACPI table storage file
1742 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1744 for Pa
in Wa
.AutoGenObjectList
:
1745 for ModuleKey
in Pa
.Platform
.Modules
:
1746 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1747 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1748 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1751 # Collect the GUID map in the FV firmware volume
1753 for FvName
in self
.FvList
:
1754 FvDictKey
=FvName
.upper()
1755 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1756 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1759 # collect GUID map for binary EFI file in FDF file.
1761 Guid
= Ffs
.NameGuid
.upper()
1762 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1764 PcdTokenspace
= Match
.group(1)
1765 PcdToken
= Match
.group(2)
1766 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1767 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1768 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1769 for Section
in Ffs
.SectionList
:
1771 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1772 self
._GuidsDb
[Guid
] = ModuleSectFile
1773 except AttributeError:
1775 except AttributeError:
1780 # Internal worker function to generate report for the FD region
1782 # This internal worker function to generate report for the FD region.
1783 # It the type is firmware volume, it lists offset and module identification.
1785 # @param self The object pointer
1786 # @param File The file object for report
1787 # @param Title The title for the FD subsection
1788 # @param BaseAddress The base address for the FD region
1789 # @param Size The size of the FD region
1790 # @param FvName The FV name if the FD region is a firmware volume
1792 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1793 FileWrite(File
, gSubSectionStart
)
1794 FileWrite(File
, Title
)
1795 FileWrite(File
, "Type: %s" % Type
)
1796 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1798 if self
.Type
== "FV":
1802 if FvName
.upper().endswith('.FV'):
1803 FileExt
= FvName
+ ".txt"
1805 FileExt
= FvName
+ ".Fv.txt"
1807 if not os
.path
.isfile(FileExt
):
1808 FvReportFileName
= mws
.join(self
._WorkspaceDir
, FileExt
)
1809 if not os
.path
.isfile(FvReportFileName
):
1810 FvReportFileName
= os
.path
.join(self
._FvDir
, FileExt
)
1813 # Collect size info in the firmware volume.
1815 FvReport
= open(FvReportFileName
).read()
1816 Match
= gFvTotalSizePattern
.search(FvReport
)
1818 FvTotalSize
= int(Match
.group(1), 16)
1819 Match
= gFvTakenSizePattern
.search(FvReport
)
1821 FvTakenSize
= int(Match
.group(1), 16)
1822 FvFreeSize
= FvTotalSize
- FvTakenSize
1824 # Write size information to the report file.
1826 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1827 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1828 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1829 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1830 FileWrite(File
, "Offset Module")
1831 FileWrite(File
, gSubSectionSep
)
1833 # Write module offset and module identification to the report file.
1836 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1837 Guid
= Match
.group(2).upper()
1838 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1839 OffsetList
= OffsetInfo
.keys()
1841 for Offset
in OffsetList
:
1842 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1844 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1846 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1847 FileWrite(File
, gSubSectionEnd
)
1850 # Generate report for the FD region
1852 # This function generates report for the FD region.
1854 # @param self The object pointer
1855 # @param File The file object for report
1857 def GenerateReport(self
, File
):
1858 if (len(self
.FvList
) > 0):
1859 for FvItem
in self
.FvList
:
1860 Info
= self
.FvInfo
[FvItem
]
1861 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1863 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1866 # Reports FD information
1868 # This class reports the FD section in the build report file.
1869 # It collects flash device information for a platform.
1871 class FdReport(object):
1873 # Constructor function for class FdReport
1875 # This constructor function generates FdReport object for a specified
1878 # @param self The object pointer
1879 # @param Fd The current Firmware device object
1880 # @param Wa Workspace context information
1882 def __init__(self
, Fd
, Wa
):
1883 self
.FdName
= Fd
.FdUiName
1884 self
.BaseAddress
= Fd
.BaseAddress
1886 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1887 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, "FV")
1888 self
.VpdFilePath
= os
.path
.join(self
.FvPath
, "%s.map" % Wa
.Platform
.VpdToolGuid
)
1889 self
.VPDBaseAddress
= 0
1891 self
.VPDInfoList
= []
1892 for index
, FdRegion
in enumerate(Fd
.RegionList
):
1893 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
1894 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
1895 self
.VPDSize
= self
.FdRegionList
[index
].Size
1898 if os
.path
.isfile(self
.VpdFilePath
):
1899 fd
= open(self
.VpdFilePath
, "r")
1900 Lines
= fd
.readlines()
1903 if len(Line
) == 0 or Line
.startswith("#"):
1906 PcdName
, SkuId
, Offset
, Size
, Value
= Line
.split("#")[0].split("|")
1907 PcdName
, SkuId
, Offset
, Size
, Value
= PcdName
.strip(), SkuId
.strip(), Offset
.strip(), Size
.strip(), Value
.strip()
1908 if Offset
.lower().startswith('0x'):
1909 Offset
= '0x%08X' % (int(Offset
, 16) + self
.VPDBaseAddress
)
1911 Offset
= '0x%08X' % (int(Offset
, 10) + self
.VPDBaseAddress
)
1912 self
.VPDInfoList
.append("%s | %s | %s | %s | %s" % (PcdName
, SkuId
, Offset
, Size
, Value
))
1914 EdkLogger
.error("BuildReport", CODE_ERROR
, "Fail to parse VPD information file %s" % self
.VpdFilePath
)
1918 # Generate report for the firmware device.
1920 # This function generates report for the firmware device.
1922 # @param self The object pointer
1923 # @param File The file object for report
1925 def GenerateReport(self
, File
):
1926 FileWrite(File
, gSectionStart
)
1927 FileWrite(File
, "Firmware Device (FD)")
1928 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1929 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1930 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1931 if len(self
.FdRegionList
) > 0:
1932 FileWrite(File
, gSectionSep
)
1933 for FdRegionItem
in self
.FdRegionList
:
1934 FdRegionItem
.GenerateReport(File
)
1936 if len(self
.VPDInfoList
) > 0:
1937 FileWrite(File
, gSubSectionStart
)
1938 FileWrite(File
, "FD VPD Region")
1939 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
1940 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
1941 FileWrite(File
, gSubSectionSep
)
1942 for item
in self
.VPDInfoList
:
1943 ValueList
= item
.split('|')
1944 Value
= ValueList
[-1].strip()
1945 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1947 ValueList
[-1] = ' {'
1948 FileWrite(File
, '|'.join(ValueList
))
1949 for Array
in ArrayList
:
1950 FileWrite(File
, '%s' % (Array
))
1952 FileWrite(File
, item
)
1953 FileWrite(File
, gSubSectionEnd
)
1954 FileWrite(File
, gSectionEnd
)
1959 # Reports platform information
1961 # This class reports the whole platform information
1963 class PlatformReport(object):
1965 # Constructor function for class PlatformReport
1967 # This constructor function generates PlatformReport object a platform build.
1968 # It generates report for platform summary, flash, global PCDs and detailed
1969 # module information for modules involved in platform build.
1971 # @param self The object pointer
1972 # @param Wa Workspace context information
1973 # @param MaList The list of modules in the platform build
1975 def __init__(self
, Wa
, MaList
, ReportType
):
1976 self
._WorkspaceDir
= Wa
.WorkspaceDir
1977 self
.PlatformName
= Wa
.Name
1978 self
.PlatformDscPath
= Wa
.Platform
1979 self
.Architectures
= " ".join(Wa
.ArchList
)
1980 self
.ToolChain
= Wa
.ToolChain
1981 self
.Target
= Wa
.BuildTarget
1982 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1983 self
.BuildEnvironment
= platform
.platform()
1985 self
.PcdReport
= None
1986 if "PCD" in ReportType
:
1987 self
.PcdReport
= PcdReport(Wa
)
1989 self
.FdReportList
= []
1990 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
is None:
1991 for Fd
in Wa
.FdfProfile
.FdDict
:
1992 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1994 self
.PredictionReport
= None
1995 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1996 self
.PredictionReport
= PredictionReport(Wa
)
1998 self
.DepexParser
= None
1999 if "DEPEX" in ReportType
:
2000 self
.DepexParser
= DepexParser(Wa
)
2002 self
.ModuleReportList
= []
2003 if MaList
is not None:
2004 self
._IsModuleBuild
= True
2006 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
2008 self
._IsModuleBuild
= False
2009 for Pa
in Wa
.AutoGenObjectList
:
2010 ModuleAutoGenList
= []
2011 for ModuleKey
in Pa
.Platform
.Modules
:
2012 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
2013 if GlobalData
.gFdfParser
is not None:
2014 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
2015 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
2016 for InfName
in INFList
:
2017 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
2018 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
)
2021 if Ma
not in ModuleAutoGenList
:
2022 ModuleAutoGenList
.append(Ma
)
2023 for MGen
in ModuleAutoGenList
:
2024 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
2029 # Generate report for the whole platform.
2031 # This function generates report for platform information.
2032 # It comprises of platform summary, global PCD, flash and
2033 # module list sections.
2035 # @param self The object pointer
2036 # @param File The file object for report
2037 # @param BuildDuration The total time to build the modules
2038 # @param AutoGenTime The total time of AutoGen Phase
2039 # @param MakeTime The total time of Make Phase
2040 # @param GenFdsTime The total time of GenFds Phase
2041 # @param ReportType The kind of report items in the final report file
2043 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
2044 FileWrite(File
, "Platform Summary")
2045 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
2046 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
2047 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
2048 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
2049 FileWrite(File
, "Target: %s" % self
.Target
)
2050 if GlobalData
.gSkuids
:
2051 FileWrite(File
, "SKUID: %s" % " ".join(GlobalData
.gSkuids
))
2052 if GlobalData
.gDefaultStores
:
2053 FileWrite(File
, "DefaultStore: %s" % " ".join(GlobalData
.gDefaultStores
))
2054 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
2055 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
2056 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
2058 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
2060 FileWrite(File
, "Make Duration: %s" % MakeTime
)
2062 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
2063 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
2065 if GlobalData
.MixedPcd
:
2066 FileWrite(File
, gSectionStart
)
2067 FileWrite(File
, "The following PCDs use different access methods:")
2068 FileWrite(File
, gSectionSep
)
2069 for PcdItem
in GlobalData
.MixedPcd
:
2070 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
2071 FileWrite(File
, gSectionEnd
)
2073 if not self
._IsModuleBuild
:
2074 if "PCD" in ReportType
:
2075 self
.PcdReport
.GenerateReport(File
, None)
2077 if "FLASH" in ReportType
:
2078 for FdReportListItem
in self
.FdReportList
:
2079 FdReportListItem
.GenerateReport(File
)
2081 for ModuleReportItem
in self
.ModuleReportList
:
2082 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
2084 if not self
._IsModuleBuild
:
2085 if "EXECUTION_ORDER" in ReportType
:
2086 self
.PredictionReport
.GenerateReport(File
, None)
2088 ## BuildReport class
2090 # This base class contain the routines to collect data and then
2091 # applies certain format to the output report
2093 class BuildReport(object):
2095 # Constructor function for class BuildReport
2097 # This constructor function generates BuildReport object a platform build.
2098 # It generates report for platform summary, flash, global PCDs and detailed
2099 # module information for modules involved in platform build.
2101 # @param self The object pointer
2102 # @param ReportFile The file name to save report file
2103 # @param ReportType The kind of report items in the final report file
2105 def __init__(self
, ReportFile
, ReportType
):
2106 self
.ReportFile
= ReportFile
2108 self
.ReportList
= []
2109 self
.ReportType
= []
2111 for ReportTypeItem
in ReportType
:
2112 if ReportTypeItem
not in self
.ReportType
:
2113 self
.ReportType
.append(ReportTypeItem
)
2115 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2117 # Adds platform report to the list
2119 # This function adds a platform report to the final report list.
2121 # @param self The object pointer
2122 # @param Wa Workspace context information
2123 # @param MaList The list of modules in the platform build
2125 def AddPlatformReport(self
, Wa
, MaList
=None):
2127 self
.ReportList
.append((Wa
, MaList
))
2130 # Generates the final report.
2132 # This function generates platform build report. It invokes GenerateReport()
2133 # method for every platform report in the list.
2135 # @param self The object pointer
2136 # @param BuildDuration The total time to build the modules
2137 # @param AutoGenTime The total time of AutoGen phase
2138 # @param MakeTime The total time of Make phase
2139 # @param GenFdsTime The total time of GenFds phase
2141 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
2145 for (Wa
, MaList
) in self
.ReportList
:
2146 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
2147 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
2148 SaveFileOnChange(self
.ReportFile
, Content
, True)
2149 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
2151 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
2153 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
2154 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
2157 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2158 if __name__
== '__main__':