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 # SPDX-License-Identifier: BSD-2-Clause-Patent
13 import Common
.LongFilePathOs
as os
24 from datetime
import datetime
25 from io
import BytesIO
26 from Common
import EdkLogger
27 from Common
.Misc
import SaveFileOnChange
28 from Common
.Misc
import GuidStructureByteArrayToGuidString
29 from Common
.Misc
import GuidStructureStringToGuidString
30 from Common
.BuildToolError
import FILE_WRITE_FAILURE
31 from Common
.BuildToolError
import CODE_ERROR
32 from Common
.BuildToolError
import COMMAND_FAILURE
33 from Common
.BuildToolError
import FORMAT_INVALID
34 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
35 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
36 import Common
.GlobalData
as GlobalData
37 from AutoGen
.ModuleAutoGen
import ModuleAutoGen
38 from Common
.Misc
import PathClass
39 from Common
.StringUtils
import NormPath
40 from Common
.DataType
import *
42 from Common
.Expression
import *
43 from GenFds
.AprioriSection
import DXE_APRIORI_GUID
, PEI_APRIORI_GUID
45 ## Pattern to extract contents in EDK DXS files
46 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
48 ## Pattern to find total FV total size, occupied size in flash report intermediate file
49 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
50 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
52 ## Pattern to find module size and time stamp in module summary report intermediate file
53 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
54 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
56 ## Pattern to find GUID value in flash description files
57 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
59 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
60 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
62 ## Pattern to find module base address and entry point in fixed flash map file
63 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
64 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
66 ## Pattern to find all module referenced header files in source files
67 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
68 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
70 ## Pattern to find the entry point for EDK module using EDKII Glue library
71 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
73 ## Tags for MaxLength of line in report
76 ## Tags for end of line in report
79 ## Tags for section start, end and separator
80 gSectionStart
= ">" + "=" * (gLineMaxLength
- 2) + "<"
81 gSectionEnd
= "<" + "=" * (gLineMaxLength
- 2) + ">" + "\n"
82 gSectionSep
= "=" * gLineMaxLength
84 ## Tags for subsection start, end and separator
85 gSubSectionStart
= ">" + "-" * (gLineMaxLength
- 2) + "<"
86 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
- 2) + ">"
87 gSubSectionSep
= "-" * gLineMaxLength
90 ## The look up table to map PCD type to pair of report display type and DEC type
92 TAB_PCDS_FIXED_AT_BUILD
: ('FIXED', TAB_PCDS_FIXED_AT_BUILD
),
93 TAB_PCDS_PATCHABLE_IN_MODULE
: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE
),
94 TAB_PCDS_FEATURE_FLAG
: ('FLAG', TAB_PCDS_FEATURE_FLAG
),
95 TAB_PCDS_DYNAMIC
: ('DYN', TAB_PCDS_DYNAMIC
),
96 TAB_PCDS_DYNAMIC_HII
: ('DYNHII', TAB_PCDS_DYNAMIC
),
97 TAB_PCDS_DYNAMIC_VPD
: ('DYNVPD', TAB_PCDS_DYNAMIC
),
98 TAB_PCDS_DYNAMIC_EX
: ('DEX', TAB_PCDS_DYNAMIC_EX
),
99 TAB_PCDS_DYNAMIC_EX_HII
: ('DEXHII', TAB_PCDS_DYNAMIC_EX
),
100 TAB_PCDS_DYNAMIC_EX_VPD
: ('DEXVPD', TAB_PCDS_DYNAMIC_EX
),
103 ## The look up table to map module type to driver type
105 SUP_MODULE_SEC
: '0x3 (SECURITY_CORE)',
106 SUP_MODULE_PEI_CORE
: '0x4 (PEI_CORE)',
107 SUP_MODULE_PEIM
: '0x6 (PEIM)',
108 SUP_MODULE_DXE_CORE
: '0x5 (DXE_CORE)',
109 SUP_MODULE_DXE_DRIVER
: '0x7 (DRIVER)',
110 SUP_MODULE_DXE_SAL_DRIVER
: '0x7 (DRIVER)',
111 SUP_MODULE_DXE_SMM_DRIVER
: '0x7 (DRIVER)',
112 SUP_MODULE_DXE_RUNTIME_DRIVER
: '0x7 (DRIVER)',
113 SUP_MODULE_UEFI_DRIVER
: '0x7 (DRIVER)',
114 SUP_MODULE_UEFI_APPLICATION
: '0x9 (APPLICATION)',
115 SUP_MODULE_SMM_CORE
: '0xD (SMM_CORE)',
116 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
117 SUP_MODULE_MM_STANDALONE
: '0xE (MM_STANDALONE)',
118 SUP_MODULE_MM_CORE_STANDALONE
: '0xF (MM_CORE_STANDALONE)'
121 ## The look up table of the supported opcode in the dependency expression binaries
122 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
128 # Writes a string to the file object.
130 # This function writes a string to the file object and a new line is appended
131 # afterwards. It may optionally wraps the string for better readability.
133 # @File The file object to write
134 # @String The string to be written to the file
135 # @Wrapper Indicates whether to wrap the string
137 def FileWrite(File
, String
, Wrapper
=False):
139 String
= textwrap
.fill(String
, 120)
140 File
.append(String
+ gEndOfLine
)
142 def ByteArrayForamt(Value
):
146 if Value
.startswith('{') and Value
.endswith('}') and not Value
.startswith("{CODE("):
148 ValueList
= Value
.split(',')
149 if len(ValueList
) >= SplitNum
:
153 Len
= len(ValueList
)/SplitNum
154 for i
, element
in enumerate(ValueList
):
155 ValueList
[i
] = '0x%02X' % int(element
.strip(), 16)
159 End
= min(SplitNum
*(Id
+1), len(ValueList
))
160 Str
= ','.join(ValueList
[SplitNum
*Id
: End
])
161 if End
== len(ValueList
):
163 ArrayList
.append(Str
)
167 ArrayList
.append(Str
)
170 ArrayList
= [Value
+ '}']
171 return IsByteArray
, ArrayList
174 # Find all the header file that the module source directly includes.
176 # This function scans source code to find all header files the module may
177 # include. This is not accurate but very effective to find all the header
178 # file the module might include with #include statement.
180 # @Source The source file name
181 # @IncludePathList The list of include path to find the source file.
182 # @IncludeFiles The dictionary of current found include files.
184 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
185 FileContents
= open(Source
).read()
187 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
189 for Match
in gIncludePattern
.finditer(FileContents
):
190 FileName
= Match
.group(1).strip()
191 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
192 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
193 if os
.path
.exists(FullFileName
):
194 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
198 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
200 for Match
in gIncludePattern2
.finditer(FileContents
):
202 Type
= Match
.group(1)
203 if "ARCH_PROTOCOL" in Type
:
204 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
205 elif "PROTOCOL" in Type
:
206 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
208 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
209 elif TAB_GUID
in Type
:
210 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
213 for Dir
in IncludePathList
:
214 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
215 if os
.path
.exists(FullFileName
):
216 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
219 ## Split each lines in file
221 # This method is used to split the lines in file to make the length of each line
222 # less than MaxLength.
224 # @param Content The content of file
225 # @param MaxLength The Max Length of the line
227 def FileLinesSplit(Content
=None, MaxLength
=None):
228 ContentList
= Content
.split(TAB_LINE_BREAK
)
231 for Line
in ContentList
:
232 while len(Line
.rstrip()) > MaxLength
:
233 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
234 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
235 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
236 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
237 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
239 LineBreakIndex
= MaxLength
240 NewContentList
.append(Line
[:LineBreakIndex
])
241 Line
= Line
[LineBreakIndex
:]
243 NewContentList
.append(Line
)
244 for NewLine
in NewContentList
:
245 NewContent
+= NewLine
+ TAB_LINE_BREAK
247 NewContent
= NewContent
.replace(gEndOfLine
, TAB_LINE_BREAK
).replace('\r\r\n', gEndOfLine
)
253 # Parse binary dependency expression section
255 # This utility class parses the dependency expression section and translate the readable
256 # GUID name and value.
258 class DepexParser(object):
260 # Constructor function for class DepexParser
262 # This constructor function collect GUID values so that the readable
263 # GUID name can be translated.
265 # @param self The object pointer
266 # @param Wa Workspace context information
268 def __init__(self
, Wa
):
270 for Pa
in Wa
.AutoGenObjectList
:
271 for Package
in Pa
.PackageList
:
272 for Protocol
in Package
.Protocols
:
273 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
274 self
._GuidDb
[GuidValue
.upper()] = Protocol
275 for Ppi
in Package
.Ppis
:
276 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
277 self
._GuidDb
[GuidValue
.upper()] = Ppi
278 for Guid
in Package
.Guids
:
279 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
280 self
._GuidDb
[GuidValue
.upper()] = Guid
281 for Ma
in Pa
.ModuleAutoGenList
:
282 for Pcd
in Ma
.FixedVoidTypePcds
:
283 PcdValue
= Ma
.FixedVoidTypePcds
[Pcd
]
284 if len(PcdValue
.split(',')) == 16:
285 GuidValue
= GuidStructureByteArrayToGuidString(PcdValue
)
286 self
._GuidDb
[GuidValue
.upper()] = Pcd
288 # Parse the binary dependency expression files.
290 # This function parses the binary dependency expression file and translate it
291 # to the instruction list.
293 # @param self The object pointer
294 # @param DepexFileName The file name of binary dependency expression file.
296 def ParseDepexFile(self
, DepexFileName
):
297 DepexFile
= open(DepexFileName
, "rb")
299 OpCode
= DepexFile
.read(1)
301 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
302 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
303 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
304 struct
.unpack(PACK_PATTERN_GUID
, DepexFile
.read(16))
305 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
306 Statement
= "%s %s" % (Statement
, GuidString
)
307 DepexStatement
.append(Statement
)
308 OpCode
= DepexFile
.read(1)
310 return DepexStatement
313 # Reports library information
315 # This class reports the module library subsection in the build report file.
317 class LibraryReport(object):
319 # Constructor function for class LibraryReport
321 # This constructor function generates LibraryReport object for
324 # @param self The object pointer
325 # @param M Module context information
327 def __init__(self
, M
):
328 self
.LibraryList
= []
330 for Lib
in M
.DependentLibraryList
:
331 LibInfPath
= str(Lib
)
332 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
333 LibConstructorList
= Lib
.ConstructorList
334 LibDesstructorList
= Lib
.DestructorList
335 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
336 for LibAutoGen
in M
.LibraryAutoGenList
:
337 if LibInfPath
== LibAutoGen
.MetaFile
.Path
:
338 LibTime
= LibAutoGen
.BuildTime
340 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
, LibTime
))
343 # Generate report for module library information
345 # This function generates report for the module library.
346 # If the module is EDKII style one, the additional library class, library
347 # constructor/destructor and dependency expression may also be reported.
349 # @param self The object pointer
350 # @param File The file object for report
352 def GenerateReport(self
, File
):
353 if len(self
.LibraryList
) > 0:
354 FileWrite(File
, gSubSectionStart
)
355 FileWrite(File
, TAB_BRG_LIBRARY
)
356 FileWrite(File
, gSubSectionSep
)
357 for LibraryItem
in self
.LibraryList
:
358 LibInfPath
= LibraryItem
[0]
359 FileWrite(File
, LibInfPath
)
361 LibClass
= LibraryItem
[1]
363 LibConstructor
= " ".join(LibraryItem
[2])
365 EdkIILibInfo
+= " C = " + LibConstructor
366 LibDestructor
= " ".join(LibraryItem
[3])
368 EdkIILibInfo
+= " D = " + LibDestructor
369 LibDepex
= " ".join(LibraryItem
[4])
371 EdkIILibInfo
+= " Depex = " + LibDepex
373 EdkIILibInfo
+= " Time = " + LibraryItem
[5]
375 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
377 FileWrite(File
, "{%s}" % LibClass
)
379 FileWrite(File
, gSubSectionEnd
)
382 # Reports dependency expression information
384 # This class reports the module dependency expression subsection in the build report file.
386 class DepexReport(object):
388 # Constructor function for class DepexReport
390 # This constructor function generates DepexReport object for
391 # a module. If the module source contains the DXS file (usually EDK
392 # style module), it uses the dependency in DXS file; otherwise,
393 # it uses the dependency expression from its own INF [Depex] section
394 # and then merges with the ones from its dependent library INF.
396 # @param self The object pointer
397 # @param M Module context information
399 def __init__(self
, M
):
401 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
402 ModuleType
= M
.ModuleType
404 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
406 if ModuleType
in [SUP_MODULE_SEC
, SUP_MODULE_PEI_CORE
, SUP_MODULE_DXE_CORE
, SUP_MODULE_SMM_CORE
, SUP_MODULE_MM_CORE_STANDALONE
, SUP_MODULE_UEFI_APPLICATION
]:
409 for Source
in M
.SourceFileList
:
410 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
411 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
413 self
.Depex
= Match
.group(1).strip()
417 self
.Depex
= M
.DepexExpressionDict
.get(M
.ModuleType
, "")
418 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
419 if not self
.ModuleDepex
:
420 self
.ModuleDepex
= "(None)"
423 for Lib
in M
.DependentLibraryList
:
424 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
426 LibDepexList
.append("(" + LibDepex
+ ")")
427 self
.LibraryDepex
= " AND ".join(LibDepexList
)
428 if not self
.LibraryDepex
:
429 self
.LibraryDepex
= "(None)"
433 # Generate report for module dependency expression information
435 # This function generates report for the module dependency expression.
437 # @param self The object pointer
438 # @param File The file object for report
439 # @param GlobalDepexParser The platform global Dependency expression parser object
441 def GenerateReport(self
, File
, GlobalDepexParser
):
444 FileWrite(File
, gSubSectionStart
)
445 if os
.path
.isfile(self
._DepexFileName
):
447 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
448 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
449 for DepexStatement
in DepexStatements
:
450 FileWrite(File
, " %s" % DepexStatement
)
451 FileWrite(File
, gSubSectionSep
)
453 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
455 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
457 if self
.Source
== "INF":
458 FileWrite(File
, self
.Depex
, True)
459 FileWrite(File
, gSubSectionSep
)
460 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
461 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
463 FileWrite(File
, self
.Depex
)
464 FileWrite(File
, gSubSectionEnd
)
467 # Reports dependency expression information
469 # This class reports the module build flags subsection in the build report file.
471 class BuildFlagsReport(object):
473 # Constructor function for class BuildFlagsReport
475 # This constructor function generates BuildFlagsReport object for
476 # a module. It reports the build tool chain tag and all relevant
477 # build flags to build the module.
479 # @param self The object pointer
480 # @param M Module context information
482 def __init__(self
, M
):
485 # Add build flags according to source file extension so that
486 # irrelevant ones can be filtered out.
488 for Source
in M
.SourceFileList
:
489 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
490 if Ext
in [".c", ".cc", ".cpp"]:
491 BuildOptions
["CC"] = 1
492 elif Ext
in [".s", ".asm"]:
493 BuildOptions
["PP"] = 1
494 BuildOptions
["ASM"] = 1
495 elif Ext
in [".vfr"]:
496 BuildOptions
["VFRPP"] = 1
497 BuildOptions
["VFR"] = 1
498 elif Ext
in [".dxs"]:
499 BuildOptions
["APP"] = 1
500 BuildOptions
["CC"] = 1
501 elif Ext
in [".asl"]:
502 BuildOptions
["ASLPP"] = 1
503 BuildOptions
["ASL"] = 1
504 elif Ext
in [".aslc"]:
505 BuildOptions
["ASLCC"] = 1
506 BuildOptions
["ASLDLINK"] = 1
507 BuildOptions
["CC"] = 1
508 elif Ext
in [".asm16"]:
509 BuildOptions
["ASMLINK"] = 1
510 BuildOptions
["SLINK"] = 1
511 BuildOptions
["DLINK"] = 1
514 # Save module build flags.
516 self
.ToolChainTag
= M
.ToolChain
518 for Tool
in BuildOptions
:
519 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
522 # Generate report for module build flags information
524 # This function generates report for the module build flags expression.
526 # @param self The object pointer
527 # @param File The file object for report
529 def GenerateReport(self
, File
):
530 FileWrite(File
, gSubSectionStart
)
531 FileWrite(File
, "Build Flags")
532 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
533 for Tool
in self
.BuildFlags
:
534 FileWrite(File
, gSubSectionSep
)
535 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
537 FileWrite(File
, gSubSectionEnd
)
541 # Reports individual module information
543 # This class reports the module section in the build report file.
544 # It comprises of module summary, module PCD, library, dependency expression,
545 # build flags sections.
547 class ModuleReport(object):
549 # Constructor function for class ModuleReport
551 # This constructor function generates ModuleReport object for
552 # a separate module in a platform build.
554 # @param self The object pointer
555 # @param M Module context information
556 # @param ReportType The kind of report items in the final report file
558 def __init__(self
, M
, ReportType
):
559 self
.ModuleName
= M
.Module
.BaseName
560 self
.ModuleInfPath
= M
.MetaFile
.File
561 self
.ModuleArch
= M
.Arch
562 self
.FileGuid
= M
.Guid
564 self
.BuildTimeStamp
= None
568 ModuleType
= M
.ModuleType
570 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
572 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
574 if ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
575 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
576 if int(PiSpec
, 0) >= 0x0001000A:
577 ModuleType
= "SMM_DRIVER"
578 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
579 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
580 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
581 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
582 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
583 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
584 self
.BuildTime
= M
.BuildTime
586 self
._BuildDir
= M
.BuildDir
587 self
.ModulePcdSet
= {}
588 if "PCD" in ReportType
:
590 # Collect all module used PCD set: module INF referenced directly or indirectly.
591 # It also saves module INF default values of them in case they exist.
593 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
594 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
596 self
.LibraryReport
= None
597 if "LIBRARY" in ReportType
:
598 self
.LibraryReport
= LibraryReport(M
)
600 self
.DepexReport
= None
601 if "DEPEX" in ReportType
:
602 self
.DepexReport
= DepexReport(M
)
604 if "BUILD_FLAGS" in ReportType
:
605 self
.BuildFlagsReport
= BuildFlagsReport(M
)
609 # Generate report for module information
611 # This function generates report for separate module expression
612 # in a platform build.
614 # @param self The object pointer
615 # @param File The file object for report
616 # @param GlobalPcdReport The platform global PCD report object
617 # @param GlobalPredictionReport The platform global Prediction report object
618 # @param GlobalDepexParser The platform global Dependency expression parser object
619 # @param ReportType The kind of report items in the final report file
621 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
622 FileWrite(File
, gSectionStart
)
624 FwReportFileName
= os
.path
.join(self
._BuildDir
, "OUTPUT", self
.ModuleName
+ ".txt")
625 if os
.path
.isfile(FwReportFileName
):
627 FileContents
= open(FwReportFileName
).read()
628 Match
= gModuleSizePattern
.search(FileContents
)
630 self
.Size
= int(Match
.group(1))
632 Match
= gTimeStampPattern
.search(FileContents
)
634 self
.BuildTimeStamp
= datetime
.utcfromtimestamp(int(Match
.group(1)))
636 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
638 if "HASH" in ReportType
:
639 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
640 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
641 if os
.path
.isfile(DefaultEFIfile
):
642 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
643 # rebase the efi image since its base address may not zero
644 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
646 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
647 except Exception as X
:
648 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
649 EndOfProcedure
= threading
.Event()
650 EndOfProcedure
.clear()
651 if PopenObject
.stderr
:
652 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
653 StdErrThread
.setName("STDERR-Redirector")
654 StdErrThread
.setDaemon(False)
656 # waiting for program exit
658 if PopenObject
.stderr
:
660 if PopenObject
.returncode
!= 0:
661 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
662 if os
.path
.isfile(Tempfile
):
663 self
.Hash
= hashlib
.sha1()
664 buf
= open(Tempfile
, 'rb').read()
665 if self
.Hash
.update(buf
):
666 self
.Hash
= self
.Hash
.update(buf
)
667 self
.Hash
= self
.Hash
.hexdigest()
670 FileWrite(File
, "Module Summary")
671 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
672 FileWrite(File
, "Module Arch: %s" % self
.ModuleArch
)
673 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
674 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
676 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
678 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
679 if self
.BuildTimeStamp
:
680 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
682 FileWrite(File
, "Module Build Time: %s" % self
.BuildTime
)
684 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
685 if self
.UefiSpecVersion
:
686 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
687 if self
.PiSpecVersion
:
688 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
690 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
692 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
693 if self
.PciClassCode
:
694 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
696 FileWrite(File
, gSectionSep
)
698 if "PCD" in ReportType
:
699 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
701 if "LIBRARY" in ReportType
:
702 self
.LibraryReport
.GenerateReport(File
)
704 if "DEPEX" in ReportType
:
705 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
707 if "BUILD_FLAGS" in ReportType
:
708 self
.BuildFlagsReport
.GenerateReport(File
)
710 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
711 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
713 FileWrite(File
, gSectionEnd
)
715 def ReadMessage(From
, To
, ExitFlag
):
717 # read one line a time
718 Line
= From
.readline()
719 # empty string means "end"
720 if Line
is not None and Line
!= b
"":
721 To(Line
.rstrip().decode(encoding
='utf-8', errors
='ignore'))
728 # Reports platform and module PCD information
730 # This class reports the platform PCD section and module PCD subsection
731 # in the build report file.
733 class PcdReport(object):
735 # Constructor function for class PcdReport
737 # This constructor function generates PcdReport object a platform build.
738 # It collects the whole PCD database from platform DSC files, platform
739 # flash description file and package DEC files.
741 # @param self The object pointer
742 # @param Wa Workspace context information
744 def __init__(self
, Wa
):
747 self
.ConditionalPcds
= {}
751 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
755 self
.DefaultStoreSingle
= True
756 self
.SkuSingle
= True
757 if GlobalData
.gDefaultStores
and len(GlobalData
.gDefaultStores
) > 1:
758 self
.DefaultStoreSingle
= False
759 if GlobalData
.gSkuids
and len(GlobalData
.gSkuids
) > 1:
760 self
.SkuSingle
= False
762 self
.ModulePcdOverride
= {}
763 for Pa
in Wa
.AutoGenObjectList
:
766 # Collect all platform referenced PCDs and grouped them by PCD token space
769 for Pcd
in Pa
.AllPcdList
:
770 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
771 if Pcd
not in PcdList
:
773 if len(Pcd
.TokenCName
) > self
.MaxLen
:
774 self
.MaxLen
= len(Pcd
.TokenCName
)
776 # Collect the PCD defined in DSC/FDF file, but not used in module
778 UnusedPcdFullList
= []
779 StructPcdDict
= GlobalData
.gStructurePcd
.get(self
.Arch
, collections
.OrderedDict())
780 for Name
, Guid
in StructPcdDict
:
781 if (Name
, Guid
) not in Pa
.Platform
.Pcds
:
782 Pcd
= StructPcdDict
[(Name
, Guid
)]
783 PcdList
= self
.AllPcds
.setdefault(Guid
, {}).setdefault(Pcd
.Type
, [])
784 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
785 UnusedPcdFullList
.append(Pcd
)
786 for item
in Pa
.Platform
.Pcds
:
787 Pcd
= Pa
.Platform
.Pcds
[item
]
789 # check the Pcd in FDF file, whether it is used in module first
790 for T
in PCD_TYPE_LIST
:
791 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
797 for package
in Pa
.PackageList
:
798 for T
in PCD_TYPE_LIST
:
799 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
802 if not Pcd
.DatumType
:
803 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
807 if not Pcd
.DatumType
:
809 # Try to remove Hii and Vpd suffix
810 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
811 PcdType
= TAB_PCDS_DYNAMIC_EX
812 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
813 PcdType
= TAB_PCDS_DYNAMIC
814 for package
in Pa
.PackageList
:
815 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
816 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
819 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
820 UnusedPcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
821 if Pcd
in UnusedPcdList
:
822 UnusedPcdList
.remove(Pcd
)
823 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
824 UnusedPcdFullList
.append(Pcd
)
825 if len(Pcd
.TokenCName
) > self
.MaxLen
:
826 self
.MaxLen
= len(Pcd
.TokenCName
)
828 if GlobalData
.gConditionalPcds
:
829 for PcdItem
in GlobalData
.gConditionalPcds
:
831 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
832 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
833 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
834 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
835 if Pcd
not in PcdList
:
839 if UnusedPcdFullList
:
840 for Pcd
in UnusedPcdFullList
:
841 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
843 UnusedPcdList
.append(Pcd
)
845 for Pcd
in UnusedPcdList
:
846 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
847 if Pcd
not in PcdList
:
850 for Module
in Pa
.Platform
.Modules
.values():
852 # Collect module override PCDs
854 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
855 TokenCName
= ModulePcd
.TokenCName
856 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
857 ModuleDefault
= ModulePcd
.DefaultValue
858 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
859 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
863 # Collect PCD DEC default value.
865 self
.DecPcdDefault
= {}
867 for Pa
in Wa
.AutoGenObjectList
:
868 for Package
in Pa
.PackageList
:
869 Guids
= Package
.Guids
870 self
._GuidDict
.update(Guids
)
871 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
872 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
873 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
875 # Collect PCDs defined in DSC common section
877 self
.DscPcdDefault
= {}
878 for Pa
in Wa
.AutoGenObjectList
:
879 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
880 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DscDefaultValue
882 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
884 def GenerateReport(self
, File
, ModulePcdSet
):
886 if self
.ConditionalPcds
:
887 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
890 for Token
in self
.UnusedPcds
:
891 TokenDict
= self
.UnusedPcds
[Token
]
892 for Type
in TokenDict
:
899 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
900 self
.GenerateReportDetail(File
, ModulePcdSet
)
903 # Generate report for PCD information
905 # This function generates report for separate module expression
906 # in a platform build.
908 # @param self The object pointer
909 # @param File The file object for report
910 # @param ModulePcdSet Set of all PCDs referenced by module or None for
911 # platform PCD report
912 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
913 # directives section report, 2 means Unused Pcds section report
914 # @param DscOverridePcds Module DSC override PCDs set
916 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
917 PcdDict
= self
.AllPcds
918 if ReportSubType
== 1:
919 PcdDict
= self
.ConditionalPcds
920 elif ReportSubType
== 2:
921 PcdDict
= self
.UnusedPcds
924 FileWrite(File
, gSectionStart
)
925 if ReportSubType
== 1:
926 FileWrite(File
, "Conditional Directives used by the build system")
927 elif ReportSubType
== 2:
928 FileWrite(File
, "PCDs not used by modules or in conditional directives")
930 FileWrite(File
, "Platform Configuration Database Report")
932 FileWrite(File
, " *B - PCD override in the build option")
933 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
934 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
935 if not ReportSubType
:
936 FileWrite(File
, " *M - Module scoped PCD override")
937 FileWrite(File
, gSectionSep
)
939 if not ReportSubType
and ModulePcdSet
:
941 # For module PCD sub-section
943 FileWrite(File
, gSubSectionStart
)
944 FileWrite(File
, TAB_BRG_PCD
)
945 FileWrite(File
, gSubSectionSep
)
949 for Type
in PcdDict
[Key
]:
950 for Pcd
in PcdDict
[Key
][Type
]:
951 AllPcdDict
[Key
][(Pcd
.TokenCName
, Type
)] = Pcd
952 for Key
in sorted(AllPcdDict
):
954 # Group PCD by their token space GUID C Name
957 for PcdTokenCName
, Type
in sorted(AllPcdDict
[Key
]):
959 # Group PCD by their usage type
961 Pcd
= AllPcdDict
[Key
][(PcdTokenCName
, Type
)]
962 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
964 if GlobalData
.MixedPcd
:
965 for PcdKey
in GlobalData
.MixedPcd
:
966 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
967 PcdTokenCName
= PcdKey
[0]
969 if MixedPcdFlag
and not ModulePcdSet
:
972 # Get PCD default value and their override relationship
974 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
975 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
976 DscDefaultValBak
= DscDefaultValue
978 for (CName
, Guid
, Field
) in self
.FdfPcdSet
:
979 if CName
== PcdTokenCName
and Guid
== Key
:
980 DscDefaultValue
= self
.FdfPcdSet
[(CName
, Guid
, Field
)]
982 if DscDefaultValue
!= DscDefaultValBak
:
984 DscDefaultValue
= ValueExpressionEx(DscDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
985 except BadExpression
as DscDefaultValue
:
986 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" %(DscDefaultValue
, Pcd
.DatumType
))
988 InfDefaultValue
= None
990 PcdValue
= DecDefaultValue
992 PcdValue
= DscDefaultValue
993 #The DefaultValue of StructurePcd already be the latest, no need to update.
994 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
995 Pcd
.DefaultValue
= PcdValue
996 if ModulePcdSet
is not None:
997 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
999 InfDefaultValue
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
1000 #The DefaultValue of StructurePcd already be the latest, no need to update.
1001 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1002 Pcd
.DefaultValue
= PcdValue
1005 InfDefaultValue
= ValueExpressionEx(InfDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
1006 except BadExpression
as InfDefaultValue
:
1007 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" % (InfDefaultValue
, Pcd
.DatumType
))
1008 if InfDefaultValue
== "":
1009 InfDefaultValue
= None
1011 BuildOptionMatch
= False
1012 if GlobalData
.BuildOptionPcd
:
1013 for pcd
in GlobalData
.BuildOptionPcd
:
1014 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
1018 #The DefaultValue of StructurePcd already be the latest, no need to update.
1019 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1020 Pcd
.DefaultValue
= PcdValue
1021 BuildOptionMatch
= True
1025 if ModulePcdSet
is None:
1027 FileWrite(File
, Key
)
1031 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1032 if PcdValue
.startswith('0') and not PcdValue
.lower().startswith('0x') and \
1033 len(PcdValue
) > 1 and PcdValue
.lstrip('0'):
1034 PcdValue
= PcdValue
.lstrip('0')
1035 PcdValueNumber
= int(PcdValue
.strip(), 0)
1036 if DecDefaultValue
is None:
1039 if DecDefaultValue
.startswith('0') and not DecDefaultValue
.lower().startswith('0x') and \
1040 len(DecDefaultValue
) > 1 and DecDefaultValue
.lstrip('0'):
1041 DecDefaultValue
= DecDefaultValue
.lstrip('0')
1042 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
1043 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
1045 if InfDefaultValue
is None:
1048 if InfDefaultValue
.startswith('0') and not InfDefaultValue
.lower().startswith('0x') and \
1049 len(InfDefaultValue
) > 1 and InfDefaultValue
.lstrip('0'):
1050 InfDefaultValue
= InfDefaultValue
.lstrip('0')
1051 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
1052 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
1054 if DscDefaultValue
is None:
1057 if DscDefaultValue
.startswith('0') and not DscDefaultValue
.lower().startswith('0x') and \
1058 len(DscDefaultValue
) > 1 and DscDefaultValue
.lstrip('0'):
1059 DscDefaultValue
= DscDefaultValue
.lstrip('0')
1060 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
1061 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
1063 if DecDefaultValue
is None:
1066 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
1068 if InfDefaultValue
is None:
1071 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
1073 if DscDefaultValue
is None:
1076 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
1079 if self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1081 if TypeName
in ('DYNVPD', 'DEXVPD'):
1082 SkuInfoList
= Pcd
.SkuInfoList
1083 Pcd
= GlobalData
.gStructurePcd
[self
.Arch
][(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
)]
1084 Pcd
.DatumType
= Pcd
.StructName
1085 if TypeName
in ('DYNVPD', 'DEXVPD'):
1086 Pcd
.SkuInfoList
= SkuInfoList
1087 if Pcd
.PcdValueFromComm
or Pcd
.PcdFieldValueFromComm
:
1088 BuildOptionMatch
= True
1090 elif Pcd
.PcdValueFromFdf
or Pcd
.PcdFieldValueFromFdf
:
1091 DscDefaultValue
= True
1094 elif Pcd
.SkuOverrideValues
:
1096 if Pcd
.DefaultFromDSC
:
1100 for item
in Pcd
.SkuOverrideValues
:
1101 DictLen
+= len(Pcd
.SkuOverrideValues
[item
])
1105 if not Pcd
.SkuInfoList
:
1106 OverrideValues
= Pcd
.SkuOverrideValues
1108 for Data
in OverrideValues
.values():
1109 Struct
= list(Data
.values())
1111 DscOverride
= self
.ParseStruct(Struct
[0])
1114 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1116 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1117 if SkuInfo
.DefaultStoreDict
:
1118 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1119 for DefaultStore
in DefaultStoreList
:
1120 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1121 DscOverride
= self
.ParseStruct(OverrideValues
[DefaultStore
])
1127 DscDefaultValue
= True
1133 DscDefaultValue
= True
1138 # Report PCD item according to their override relationship
1140 if Pcd
.DatumType
== 'BOOLEAN':
1142 DscDefaultValue
= str(int(DscDefaultValue
, 0))
1144 DecDefaultValue
= str(int(DecDefaultValue
, 0))
1146 InfDefaultValue
= str(int(InfDefaultValue
, 0))
1147 if Pcd
.DefaultValue
:
1148 Pcd
.DefaultValue
= str(int(Pcd
.DefaultValue
, 0))
1150 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, ' ')
1151 elif InfDefaultValue
and InfMatch
:
1152 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1153 elif BuildOptionMatch
:
1154 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*B')
1156 if DscDefaultValue
and DscMatch
:
1157 if (Pcd
.TokenCName
, Key
, Field
) in self
.FdfPcdSet
:
1158 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*F')
1160 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*P')
1162 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1164 if ModulePcdSet
is None:
1167 if not TypeName
in ('PATCH', 'FLAG', 'FIXED'):
1169 if not BuildOptionMatch
:
1170 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1171 for ModulePath
in ModuleOverride
:
1172 ModuleDefault
= ModuleOverride
[ModulePath
]
1173 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1174 if ModuleDefault
.startswith('0') and not ModuleDefault
.lower().startswith('0x') and \
1175 len(ModuleDefault
) > 1 and ModuleDefault
.lstrip('0'):
1176 ModuleDefault
= ModuleDefault
.lstrip('0')
1177 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1178 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1179 if Pcd
.DatumType
== 'BOOLEAN':
1180 ModuleDefault
= str(ModulePcdDefaultValueNumber
)
1182 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1185 IsByteArray
, ArrayList
= ByteArrayForamt(ModuleDefault
.strip())
1187 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, '{'))
1188 for Array
in ArrayList
:
1189 FileWrite(File
, Array
)
1191 Value
= ModuleDefault
.strip()
1192 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1193 if Value
.startswith(('0x', '0X')):
1194 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1196 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1197 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, Value
))
1199 if ModulePcdSet
is None:
1200 FileWrite(File
, gSectionEnd
)
1202 if not ReportSubType
and ModulePcdSet
:
1203 FileWrite(File
, gSubSectionEnd
)
1205 def ParseStruct(self
, struct
):
1206 HasDscOverride
= False
1208 for _
, Values
in list(struct
.items()):
1209 for Key
, value
in Values
.items():
1210 if value
[1] and value
[1].endswith('.dsc'):
1211 HasDscOverride
= True
1213 if HasDscOverride
== True:
1215 return HasDscOverride
1217 def PrintPcdDefault(self
, File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
):
1218 if not DscMatch
and DscDefaultValue
is not None:
1219 Value
= DscDefaultValue
.strip()
1220 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1222 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', "{"))
1223 for Array
in ArrayList
:
1224 FileWrite(File
, Array
)
1226 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1227 if Value
.startswith(('0x', '0X')):
1228 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1230 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1231 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', Value
))
1232 if not InfMatch
and InfDefaultValue
is not None:
1233 Value
= InfDefaultValue
.strip()
1234 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1236 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', "{"))
1237 for Array
in ArrayList
:
1238 FileWrite(File
, Array
)
1240 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1241 if Value
.startswith(('0x', '0X')):
1242 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1244 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1245 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', Value
))
1247 if not DecMatch
and DecDefaultValue
is not None:
1248 Value
= DecDefaultValue
.strip()
1249 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1251 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', "{"))
1252 for Array
in ArrayList
:
1253 FileWrite(File
, Array
)
1255 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1256 if Value
.startswith(('0x', '0X')):
1257 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1259 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1260 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', Value
))
1262 for filedvalues
in Pcd
.DefaultValues
.values():
1263 self
.PrintStructureInfo(File
, filedvalues
)
1264 if DecMatch
and IsStructure
:
1265 for filedvalues
in Pcd
.DefaultValues
.values():
1266 self
.PrintStructureInfo(File
, filedvalues
)
1268 def PrintPcdValue(self
, File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, Flag
= ' '):
1269 if not Pcd
.SkuInfoList
:
1270 Value
= Pcd
.DefaultValue
1271 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1273 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1274 for Array
in ArrayList
:
1275 FileWrite(File
, Array
)
1277 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1278 if Value
.startswith('0') and not Value
.lower().startswith('0x') and len(Value
) > 1 and Value
.lstrip('0'):
1279 Value
= Value
.lstrip('0')
1280 if Value
.startswith(('0x', '0X')):
1281 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1283 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1284 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1286 FiledOverrideFlag
= False
1287 if (Pcd
.TokenCName
,Pcd
.TokenSpaceGuidCName
) in GlobalData
.gPcdSkuOverrides
:
1288 OverrideValues
= GlobalData
.gPcdSkuOverrides
[(Pcd
.TokenCName
,Pcd
.TokenSpaceGuidCName
)]
1290 OverrideValues
= Pcd
.SkuOverrideValues
1292 for Data
in OverrideValues
.values():
1293 Struct
= list(Data
.values())
1295 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, Struct
[0])
1296 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1297 FiledOverrideFlag
= True
1299 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1300 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1301 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1302 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1305 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1307 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1308 SkuIdName
= SkuInfo
.SkuIdName
1309 if TypeName
in ('DYNHII', 'DEXHII'):
1310 if SkuInfo
.DefaultStoreDict
:
1311 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1312 for DefaultStore
in DefaultStoreList
:
1313 Value
= SkuInfo
.DefaultStoreDict
[DefaultStore
]
1314 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1315 if Pcd
.DatumType
== 'BOOLEAN':
1316 Value
= str(int(Value
, 0))
1320 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1321 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1322 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1323 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1324 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1325 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1327 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1328 for Array
in ArrayList
:
1329 FileWrite(File
, Array
)
1331 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1332 if Value
.startswith(('0x', '0X')):
1333 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1335 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1336 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1337 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1338 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1339 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1340 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1341 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1343 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1346 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1347 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1348 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1349 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1350 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1351 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1353 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1354 for Array
in ArrayList
:
1355 FileWrite(File
, Array
)
1357 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1358 if Value
.startswith(('0x', '0X')):
1359 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1361 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1362 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1363 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1364 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1365 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1366 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1367 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1369 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1370 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1372 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1373 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[DefaultStore
])
1374 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1375 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1377 Value
= SkuInfo
.DefaultValue
1378 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1379 if Pcd
.DatumType
== 'BOOLEAN':
1380 Value
= str(int(Value
, 0))
1385 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1387 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1388 for Array
in ArrayList
:
1389 FileWrite(File
, Array
)
1391 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1392 if Value
.startswith(('0x', '0X')):
1393 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1395 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1397 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1399 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1403 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1405 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1406 for Array
in ArrayList
:
1407 FileWrite(File
, Array
)
1409 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1410 if Value
.startswith(('0x', '0X')):
1411 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1413 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1415 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1417 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1418 if TypeName
in ('DYNVPD', 'DEXVPD'):
1419 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1420 VPDPcdItem
= (Pcd
.TokenSpaceGuidCName
+ '.' + PcdTokenCName
, SkuIdName
, SkuInfo
.VpdOffset
, Pcd
.MaxDatumSize
, SkuInfo
.DefaultValue
)
1421 if VPDPcdItem
not in VPDPcdList
:
1422 PcdGuidList
= self
.UnusedPcds
.get(Pcd
.TokenSpaceGuidCName
)
1424 PcdList
= PcdGuidList
.get(Pcd
.Type
)
1426 VPDPcdList
.append(VPDPcdItem
)
1427 for VpdPcd
in PcdList
:
1428 if PcdTokenCName
== VpdPcd
.TokenCName
:
1431 VPDPcdList
.append(VPDPcdItem
)
1433 FiledOverrideFlag
= False
1434 OverrideValues
= Pcd
.SkuOverrideValues
.get(Sku
)
1436 Keys
= list(OverrideValues
.keys())
1437 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1438 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1439 FiledOverrideFlag
= True
1440 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1441 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1442 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1443 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1445 def OverrideFieldValue(self
, Pcd
, OverrideStruct
):
1446 OverrideFieldStruct
= collections
.OrderedDict()
1448 for _
, Values
in OverrideStruct
.items():
1449 for Key
,value
in Values
.items():
1450 if value
[1] and value
[1].endswith('.dsc'):
1451 OverrideFieldStruct
[Key
] = value
1452 if Pcd
.PcdFieldValueFromFdf
:
1453 for Key
, Values
in Pcd
.PcdFieldValueFromFdf
.items():
1454 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1456 OverrideFieldStruct
[Key
] = Values
1457 if Pcd
.PcdFieldValueFromComm
:
1458 for Key
, Values
in Pcd
.PcdFieldValueFromComm
.items():
1459 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1461 OverrideFieldStruct
[Key
] = Values
1462 return OverrideFieldStruct
1464 def PrintStructureInfo(self
, File
, Struct
):
1465 for Key
, Value
in sorted(Struct
.items(), key
=lambda x
: x
[0]):
1466 if Value
[1] and 'build command options' in Value
[1]:
1467 FileWrite(File
, ' *B %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1468 elif Value
[1] and Value
[1].endswith('.fdf'):
1469 FileWrite(File
, ' *F %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1471 FileWrite(File
, ' %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1473 def StrtoHex(self
, value
):
1475 value
= hex(int(value
))
1478 if value
.startswith("L\"") and value
.endswith("\""):
1480 for ch
in value
[2:-1]:
1481 valuelist
.append(hex(ord(ch
)))
1482 valuelist
.append('0x00')
1484 elif value
.startswith("\"") and value
.endswith("\""):
1485 return hex(ord(value
[1:-1]))
1486 elif value
.startswith("{") and value
.endswith("}"):
1488 if ',' not in value
:
1490 for ch
in value
[1:-1].split(','):
1492 if ch
.startswith('0x') or ch
.startswith('0X'):
1493 valuelist
.append(ch
)
1496 valuelist
.append(hex(int(ch
.strip())))
1503 def IsStructurePcd(self
, PcdToken
, PcdTokenSpaceGuid
):
1504 if GlobalData
.gStructurePcd
and (self
.Arch
in GlobalData
.gStructurePcd
) and ((PcdToken
, PcdTokenSpaceGuid
) in GlobalData
.gStructurePcd
[self
.Arch
]):
1510 # Reports platform and module Prediction information
1512 # This class reports the platform execution order prediction section and
1513 # module load fixed address prediction subsection in the build report file.
1515 class PredictionReport(object):
1517 # Constructor function for class PredictionReport
1519 # This constructor function generates PredictionReport object for the platform.
1521 # @param self: The object pointer
1522 # @param Wa Workspace context information
1524 def __init__(self
, Wa
):
1525 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1526 self
._MapFileParsed
= False
1527 self
._EotToolInvoked
= False
1528 self
._FvDir
= Wa
.FvDir
1529 self
._EotDir
= Wa
.BuildDir
1530 self
._FfsEntryPoint
= {}
1532 self
._SourceList
= []
1533 self
.FixedMapDict
= {}
1538 # Collect all platform reference source files and GUID C Name
1540 for Pa
in Wa
.AutoGenObjectList
:
1541 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1543 # BASE typed modules are EFI agnostic, so we need not scan
1544 # their source code to find PPI/Protocol produce or consume
1547 if Module
.ModuleType
== SUP_MODULE_BASE
:
1550 # Add module referenced source files
1552 self
._SourceList
.append(str(Module
))
1554 for Source
in Module
.SourceFileList
:
1555 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1556 self
._SourceList
.append(" " + str(Source
))
1557 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1558 for IncludeFile
in IncludeList
.values():
1559 self
._SourceList
.append(" " + IncludeFile
)
1561 for Guid
in Module
.PpiList
:
1562 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1563 for Guid
in Module
.ProtocolList
:
1564 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1565 for Guid
in Module
.GuidList
:
1566 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1568 if Module
.Guid
and not Module
.IsLibrary
:
1569 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1571 RealEntryPoint
= "_ModuleEntryPoint"
1573 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1577 # Collect platform firmware volume list as the input of EOT.
1581 for Fd
in Wa
.FdfProfile
.FdDict
:
1582 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1583 if FdRegion
.RegionType
!= BINARY_FILE_TYPE_FV
:
1585 for FvName
in FdRegion
.RegionDataList
:
1586 if FvName
in self
._FvList
:
1588 self
._FvList
.append(FvName
)
1589 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1590 for Section
in Ffs
.SectionList
:
1592 for FvSection
in Section
.SectionList
:
1593 if FvSection
.FvName
in self
._FvList
:
1595 self
._FvList
.append(FvSection
.FvName
)
1596 except AttributeError:
1601 # Parse platform fixed address map files
1603 # This function parses the platform final fixed address map file to get
1604 # the database of predicted fixed address for module image base, entry point
1607 # @param self: The object pointer
1609 def _ParseMapFile(self
):
1610 if self
._MapFileParsed
:
1612 self
._MapFileParsed
= True
1613 if os
.path
.isfile(self
._MapFileName
):
1615 FileContents
= open(self
._MapFileName
).read()
1616 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1617 AddressType
= Match
.group(1)
1618 BaseAddress
= Match
.group(2)
1619 EntryPoint
= Match
.group(3)
1620 Guid
= Match
.group(4).upper()
1621 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1622 List
.append((AddressType
, BaseAddress
, "*I"))
1623 List
.append((AddressType
, EntryPoint
, "*E"))
1625 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1628 # Invokes EOT tool to get the predicted the execution order.
1630 # This function invokes EOT tool to calculate the predicted dispatch order
1632 # @param self: The object pointer
1634 def _InvokeEotTool(self
):
1635 if self
._EotToolInvoked
:
1638 self
._EotToolInvoked
= True
1640 for FvName
in self
._FvList
:
1641 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1642 if os
.path
.isfile(FvFile
):
1643 FvFileList
.append(FvFile
)
1645 if len(FvFileList
) == 0:
1648 # Write source file list and GUID file list to an intermediate file
1649 # as the input for EOT tool and dispatch List as the output file
1652 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1653 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1654 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1657 for Item
in self
._SourceList
:
1658 FileWrite(TempFile
, Item
)
1659 SaveFileOnChange(SourceList
, "".join(TempFile
), False)
1661 for Key
in self
._GuidMap
:
1662 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1663 SaveFileOnChange(GuidList
, "".join(TempFile
), False)
1666 from Eot
.EotMain
import Eot
1669 # Invoke EOT tool and echo its runtime performance
1671 EotStartTime
= time
.time()
1672 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1673 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1674 EotEndTime
= time
.time()
1675 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1676 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1679 # Parse the output of EOT tool
1681 for Line
in open(DispatchList
):
1682 if len(Line
.split()) < 4:
1684 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1685 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1686 if len(Symbol
) > self
.MaxLen
:
1687 self
.MaxLen
= len(Symbol
)
1688 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1690 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1691 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1695 # Generate platform execution order report
1697 # This function generates the predicted module execution order.
1699 # @param self The object pointer
1700 # @param File The file object for report
1702 def _GenerateExecutionOrderReport(self
, File
):
1703 self
._InvokeEotTool
()
1704 if len(self
.ItemList
) == 0:
1706 FileWrite(File
, gSectionStart
)
1707 FileWrite(File
, "Execution Order Prediction")
1708 FileWrite(File
, "*P PEI phase")
1709 FileWrite(File
, "*D DXE phase")
1710 FileWrite(File
, "*E Module INF entry point name")
1711 FileWrite(File
, "*N Module notification function name")
1713 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1714 FileWrite(File
, gSectionSep
)
1715 for Item
in self
.ItemList
:
1716 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1718 FileWrite(File
, gSectionStart
)
1721 # Generate Fixed Address report.
1723 # This function generate the predicted fixed address report for a module
1724 # specified by Guid.
1726 # @param self The object pointer
1727 # @param File The file object for report
1728 # @param Guid The module Guid value.
1729 # @param NotifyList The list of all notify function in a module
1731 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1732 self
._ParseMapFile
()
1733 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1734 if not FixedAddressList
:
1737 FileWrite(File
, gSubSectionStart
)
1738 FileWrite(File
, "Fixed Address Prediction")
1739 FileWrite(File
, "*I Image Loading Address")
1740 FileWrite(File
, "*E Entry Point Address")
1741 FileWrite(File
, "*N Notification Function Address")
1742 FileWrite(File
, "*F Flash Address")
1743 FileWrite(File
, "*M Memory Address")
1744 FileWrite(File
, "*S SMM RAM Offset")
1745 FileWrite(File
, "TOM Top of Memory")
1747 FileWrite(File
, "Type Address Name")
1748 FileWrite(File
, gSubSectionSep
)
1749 for Item
in FixedAddressList
:
1754 Name
= "(Image Base)"
1755 elif Symbol
== "*E":
1756 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1757 elif Symbol
in NotifyList
:
1765 elif "Memory" in Type
:
1771 Value
= "TOM" + Value
1773 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1776 # Generate report for the prediction part
1778 # This function generate the predicted fixed address report for a module or
1779 # predicted module execution order for a platform.
1780 # If the input Guid is None, then, it generates the predicted module execution order;
1781 # otherwise it generated the module fixed loading address for the module specified by
1784 # @param self The object pointer
1785 # @param File The file object for report
1786 # @param Guid The module Guid value.
1788 def GenerateReport(self
, File
, Guid
):
1790 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1792 self
._GenerateExecutionOrderReport
(File
)
1795 # Reports FD region information
1797 # This class reports the FD subsection in the build report file.
1798 # It collects region information of platform flash device.
1799 # If the region is a firmware volume, it lists the set of modules
1800 # and its space information; otherwise, it only lists its region name,
1801 # base address and size in its sub-section header.
1802 # If there are nesting FVs, the nested FVs will list immediate after
1803 # this FD region subsection
1805 class FdRegionReport(object):
1807 # Discover all the nested FV name list.
1809 # This is an internal worker function to discover the all the nested FV information
1810 # in the parent firmware volume. It uses deep first search algorithm recursively to
1811 # find all the FV list name and append them to the list.
1813 # @param self The object pointer
1814 # @param FvName The name of current firmware file system
1815 # @param Wa Workspace context information
1817 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1818 FvDictKey
=FvName
.upper()
1819 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1820 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1821 for Section
in Ffs
.SectionList
:
1823 for FvSection
in Section
.SectionList
:
1824 if FvSection
.FvName
in self
.FvList
:
1826 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1827 self
.FvList
.append(FvSection
.FvName
)
1828 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1829 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1830 except AttributeError:
1834 # Constructor function for class FdRegionReport
1836 # This constructor function generates FdRegionReport object for a specified FdRegion.
1837 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1838 # volume list. This function also collects GUID map in order to dump module identification
1839 # in the final report.
1841 # @param self: The object pointer
1842 # @param FdRegion The current FdRegion object
1843 # @param Wa Workspace context information
1845 def __init__(self
, FdRegion
, Wa
):
1846 self
.Type
= FdRegion
.RegionType
1847 self
.BaseAddress
= FdRegion
.Offset
1848 self
.Size
= FdRegion
.Size
1852 self
._FvDir
= Wa
.FvDir
1853 self
._WorkspaceDir
= Wa
.WorkspaceDir
1856 # If the input FdRegion is not a firmware volume,
1859 if self
.Type
!= BINARY_FILE_TYPE_FV
:
1863 # Find all nested FVs in the FdRegion
1865 for FvName
in FdRegion
.RegionDataList
:
1866 if FvName
in self
.FvList
:
1868 self
.FvList
.append(FvName
)
1869 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1870 self
._DiscoverNestedFvList
(FvName
, Wa
)
1874 # Collect PCDs declared in DEC files.
1876 for Pa
in Wa
.AutoGenObjectList
:
1877 for Package
in Pa
.PackageList
:
1878 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1879 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1880 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1882 # Collect PCDs defined in DSC file
1884 for Pa
in Wa
.AutoGenObjectList
:
1885 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
1886 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1887 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1890 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1892 self
._GuidsDb
[PEI_APRIORI_GUID
] = "PEI Apriori"
1893 self
._GuidsDb
[DXE_APRIORI_GUID
] = "DXE Apriori"
1895 # Add ACPI table storage file
1897 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1899 for Pa
in Wa
.AutoGenObjectList
:
1900 for ModuleKey
in Pa
.Platform
.Modules
:
1901 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1902 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1903 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1906 # Collect the GUID map in the FV firmware volume
1908 for FvName
in self
.FvList
:
1909 FvDictKey
=FvName
.upper()
1910 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1911 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1914 # collect GUID map for binary EFI file in FDF file.
1916 Guid
= Ffs
.NameGuid
.upper()
1917 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1919 PcdTokenspace
= Match
.group(1)
1920 PcdToken
= Match
.group(2)
1921 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1922 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1923 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1924 for Section
in Ffs
.SectionList
:
1926 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1927 self
._GuidsDb
[Guid
] = ModuleSectFile
1928 except AttributeError:
1930 except AttributeError:
1935 # Internal worker function to generate report for the FD region
1937 # This internal worker function to generate report for the FD region.
1938 # It the type is firmware volume, it lists offset and module identification.
1940 # @param self The object pointer
1941 # @param File The file object for report
1942 # @param Title The title for the FD subsection
1943 # @param BaseAddress The base address for the FD region
1944 # @param Size The size of the FD region
1945 # @param FvName The FV name if the FD region is a firmware volume
1947 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1948 FileWrite(File
, gSubSectionStart
)
1949 FileWrite(File
, Title
)
1950 FileWrite(File
, "Type: %s" % Type
)
1951 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1953 if self
.Type
== BINARY_FILE_TYPE_FV
:
1957 if FvName
.upper().endswith('.FV'):
1958 FileExt
= FvName
+ ".txt"
1960 FileExt
= FvName
+ ".Fv.txt"
1962 if not os
.path
.isfile(FileExt
):
1963 FvReportFileName
= mws
.join(self
._WorkspaceDir
, FileExt
)
1964 if not os
.path
.isfile(FvReportFileName
):
1965 FvReportFileName
= os
.path
.join(self
._FvDir
, FileExt
)
1968 # Collect size info in the firmware volume.
1970 FvReport
= open(FvReportFileName
).read()
1971 Match
= gFvTotalSizePattern
.search(FvReport
)
1973 FvTotalSize
= int(Match
.group(1), 16)
1974 Match
= gFvTakenSizePattern
.search(FvReport
)
1976 FvTakenSize
= int(Match
.group(1), 16)
1977 FvFreeSize
= FvTotalSize
- FvTakenSize
1979 # Write size information to the report file.
1981 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1982 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1983 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1984 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1985 FileWrite(File
, "Offset Module")
1986 FileWrite(File
, gSubSectionSep
)
1988 # Write module offset and module identification to the report file.
1991 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1992 Guid
= Match
.group(2).upper()
1993 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1994 OffsetList
= sorted(OffsetInfo
.keys())
1995 for Offset
in OffsetList
:
1996 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1998 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
2000 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
2001 FileWrite(File
, gSubSectionEnd
)
2004 # Generate report for the FD region
2006 # This function generates report for the FD region.
2008 # @param self The object pointer
2009 # @param File The file object for report
2011 def GenerateReport(self
, File
):
2012 if (len(self
.FvList
) > 0):
2013 for FvItem
in self
.FvList
:
2014 Info
= self
.FvInfo
[FvItem
]
2015 self
._GenerateReport
(File
, Info
[0], TAB_FV_DIRECTORY
, Info
[1], Info
[2], FvItem
)
2017 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
2020 # Reports FD information
2022 # This class reports the FD section in the build report file.
2023 # It collects flash device information for a platform.
2025 class FdReport(object):
2027 # Constructor function for class FdReport
2029 # This constructor function generates FdReport object for a specified
2032 # @param self The object pointer
2033 # @param Fd The current Firmware device object
2034 # @param Wa Workspace context information
2036 def __init__(self
, Fd
, Wa
):
2037 self
.FdName
= Fd
.FdUiName
2038 self
.BaseAddress
= Fd
.BaseAddress
2040 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
2041 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, TAB_FV_DIRECTORY
)
2042 self
.VPDBaseAddress
= 0
2044 for index
, FdRegion
in enumerate(Fd
.RegionList
):
2045 if str(FdRegion
.RegionType
) == 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2046 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
2047 self
.VPDSize
= self
.FdRegionList
[index
].Size
2051 # Generate report for the firmware device.
2053 # This function generates report for the firmware device.
2055 # @param self The object pointer
2056 # @param File The file object for report
2058 def GenerateReport(self
, File
):
2059 FileWrite(File
, gSectionStart
)
2060 FileWrite(File
, "Firmware Device (FD)")
2061 FileWrite(File
, "FD Name: %s" % self
.FdName
)
2062 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
2063 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
2064 if len(self
.FdRegionList
) > 0:
2065 FileWrite(File
, gSectionSep
)
2066 for FdRegionItem
in self
.FdRegionList
:
2067 FdRegionItem
.GenerateReport(File
)
2070 VPDPcdList
.sort(key
=lambda x
: int(x
[2], 0))
2071 FileWrite(File
, gSubSectionStart
)
2072 FileWrite(File
, "FD VPD Region")
2073 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
2074 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
2075 FileWrite(File
, gSubSectionSep
)
2076 for item
in VPDPcdList
:
2077 # Add BaseAddress for offset
2078 Offset
= '0x%08X' % (int(item
[2], 16) + self
.VPDBaseAddress
)
2079 IsByteArray
, ArrayList
= ByteArrayForamt(item
[-1])
2081 if len(GlobalData
.gSkuids
) == 1 :
2082 Skuinfo
= GlobalData
.gSkuids
[0]
2084 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], '{'))
2085 for Array
in ArrayList
:
2086 FileWrite(File
, Array
)
2088 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], item
[-1]))
2089 FileWrite(File
, gSubSectionEnd
)
2090 FileWrite(File
, gSectionEnd
)
2095 # Reports platform information
2097 # This class reports the whole platform information
2099 class PlatformReport(object):
2101 # Constructor function for class PlatformReport
2103 # This constructor function generates PlatformReport object a platform build.
2104 # It generates report for platform summary, flash, global PCDs and detailed
2105 # module information for modules involved in platform build.
2107 # @param self The object pointer
2108 # @param Wa Workspace context information
2109 # @param MaList The list of modules in the platform build
2111 def __init__(self
, Wa
, MaList
, ReportType
):
2112 self
._WorkspaceDir
= Wa
.WorkspaceDir
2113 self
.PlatformName
= Wa
.Name
2114 self
.PlatformDscPath
= Wa
.Platform
2115 self
.Architectures
= " ".join(Wa
.ArchList
)
2116 self
.ToolChain
= Wa
.ToolChain
2117 self
.Target
= Wa
.BuildTarget
2118 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
2119 self
.BuildEnvironment
= platform
.platform()
2121 self
.PcdReport
= None
2122 if "PCD" in ReportType
:
2123 self
.PcdReport
= PcdReport(Wa
)
2125 self
.FdReportList
= []
2126 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
is None:
2127 for Fd
in Wa
.FdfProfile
.FdDict
:
2128 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
2130 self
.PredictionReport
= None
2131 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
2132 self
.PredictionReport
= PredictionReport(Wa
)
2134 self
.DepexParser
= None
2135 if "DEPEX" in ReportType
:
2136 self
.DepexParser
= DepexParser(Wa
)
2138 self
.ModuleReportList
= []
2139 if MaList
is not None:
2140 self
._IsModuleBuild
= True
2142 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
2144 self
._IsModuleBuild
= False
2145 for Pa
in Wa
.AutoGenObjectList
:
2146 ModuleAutoGenList
= []
2147 for ModuleKey
in Pa
.Platform
.Modules
:
2148 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
2149 if GlobalData
.gFdfParser
is not None:
2150 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
2151 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
2152 for InfName
in INFList
:
2153 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
2154 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
, Pa
.DataPipe
)
2157 if Ma
not in ModuleAutoGenList
:
2158 ModuleAutoGenList
.append(Ma
)
2159 for MGen
in ModuleAutoGenList
:
2160 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
2165 # Generate report for the whole platform.
2167 # This function generates report for platform information.
2168 # It comprises of platform summary, global PCD, flash and
2169 # module list sections.
2171 # @param self The object pointer
2172 # @param File The file object for report
2173 # @param BuildDuration The total time to build the modules
2174 # @param AutoGenTime The total time of AutoGen Phase
2175 # @param MakeTime The total time of Make Phase
2176 # @param GenFdsTime The total time of GenFds Phase
2177 # @param ReportType The kind of report items in the final report file
2179 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
2180 FileWrite(File
, "Platform Summary")
2181 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
2182 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
2183 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
2184 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
2185 FileWrite(File
, "Target: %s" % self
.Target
)
2186 if GlobalData
.gSkuids
:
2187 FileWrite(File
, "SKUID: %s" % " ".join(GlobalData
.gSkuids
))
2188 if GlobalData
.gDefaultStores
:
2189 FileWrite(File
, "DefaultStore: %s" % " ".join(GlobalData
.gDefaultStores
))
2190 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
2191 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
2192 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
2194 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
2196 FileWrite(File
, "Make Duration: %s" % MakeTime
)
2198 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
2199 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
2201 if GlobalData
.MixedPcd
:
2202 FileWrite(File
, gSectionStart
)
2203 FileWrite(File
, "The following PCDs use different access methods:")
2204 FileWrite(File
, gSectionSep
)
2205 for PcdItem
in GlobalData
.MixedPcd
:
2206 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
2207 FileWrite(File
, gSectionEnd
)
2209 if not self
._IsModuleBuild
:
2210 if "PCD" in ReportType
:
2211 self
.PcdReport
.GenerateReport(File
, None)
2213 if "FLASH" in ReportType
:
2214 for FdReportListItem
in self
.FdReportList
:
2215 FdReportListItem
.GenerateReport(File
)
2217 for ModuleReportItem
in self
.ModuleReportList
:
2218 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
2220 if not self
._IsModuleBuild
:
2221 if "EXECUTION_ORDER" in ReportType
:
2222 self
.PredictionReport
.GenerateReport(File
, None)
2224 ## BuildReport class
2226 # This base class contain the routines to collect data and then
2227 # applies certain format to the output report
2229 class BuildReport(object):
2231 # Constructor function for class BuildReport
2233 # This constructor function generates BuildReport object a platform build.
2234 # It generates report for platform summary, flash, global PCDs and detailed
2235 # module information for modules involved in platform build.
2237 # @param self The object pointer
2238 # @param ReportFile The file name to save report file
2239 # @param ReportType The kind of report items in the final report file
2241 def __init__(self
, ReportFile
, ReportType
):
2242 self
.ReportFile
= ReportFile
2244 self
.ReportList
= []
2245 self
.ReportType
= []
2247 for ReportTypeItem
in ReportType
:
2248 if ReportTypeItem
not in self
.ReportType
:
2249 self
.ReportType
.append(ReportTypeItem
)
2251 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2253 # Adds platform report to the list
2255 # This function adds a platform report to the final report list.
2257 # @param self The object pointer
2258 # @param Wa Workspace context information
2259 # @param MaList The list of modules in the platform build
2261 def AddPlatformReport(self
, Wa
, MaList
=None):
2263 self
.ReportList
.append((Wa
, MaList
))
2266 # Generates the final report.
2268 # This function generates platform build report. It invokes GenerateReport()
2269 # method for every platform report in the list.
2271 # @param self The object pointer
2272 # @param BuildDuration The total time to build the modules
2273 # @param AutoGenTime The total time of AutoGen phase
2274 # @param MakeTime The total time of Make phase
2275 # @param GenFdsTime The total time of GenFds phase
2277 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
2281 for (Wa
, MaList
) in self
.ReportList
:
2282 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
2283 Content
= FileLinesSplit(''.join(File
), gLineMaxLength
)
2284 SaveFileOnChange(self
.ReportFile
, Content
, False)
2285 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
2287 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
2289 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
2290 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
2292 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2293 if __name__
== '__main__':