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 io
import BytesIO
32 from Common
import EdkLogger
33 from Common
.Misc
import SaveFileOnChange
34 from Common
.Misc
import GuidStructureByteArrayToGuidString
35 from Common
.Misc
import GuidStructureStringToGuidString
36 from Common
.BuildToolError
import FILE_WRITE_FAILURE
37 from Common
.BuildToolError
import CODE_ERROR
38 from Common
.BuildToolError
import COMMAND_FAILURE
39 from Common
.BuildToolError
import FORMAT_INVALID
40 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
41 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
42 import Common
.GlobalData
as GlobalData
43 from AutoGen
.AutoGen
import ModuleAutoGen
44 from Common
.Misc
import PathClass
45 from Common
.StringUtils
import NormPath
46 from Common
.DataType
import *
48 from Common
.Expression
import *
49 from GenFds
.AprioriSection
import DXE_APRIORI_GUID
, PEI_APRIORI_GUID
51 ## Pattern to extract contents in EDK DXS files
52 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
54 ## Pattern to find total FV total size, occupied size in flash report intermediate file
55 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
56 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
58 ## Pattern to find module size and time stamp in module summary report intermediate file
59 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
60 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
62 ## Pattern to find GUID value in flash description files
63 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
65 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
66 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
68 ## Pattern to find module base address and entry point in fixed flash map file
69 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
70 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
72 ## Pattern to find all module referenced header files in source files
73 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
74 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
76 ## Pattern to find the entry point for EDK module using EDKII Glue library
77 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
79 ## Tags for MaxLength of line in report
82 ## Tags for end of line in report
85 ## Tags for section start, end and separator
86 gSectionStart
= ">" + "=" * (gLineMaxLength
- 2) + "<"
87 gSectionEnd
= "<" + "=" * (gLineMaxLength
- 2) + ">" + "\n"
88 gSectionSep
= "=" * gLineMaxLength
90 ## Tags for subsection start, end and separator
91 gSubSectionStart
= ">" + "-" * (gLineMaxLength
- 2) + "<"
92 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
- 2) + ">"
93 gSubSectionSep
= "-" * gLineMaxLength
96 ## The look up table to map PCD type to pair of report display type and DEC type
98 TAB_PCDS_FIXED_AT_BUILD
: ('FIXED', TAB_PCDS_FIXED_AT_BUILD
),
99 TAB_PCDS_PATCHABLE_IN_MODULE
: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE
),
100 TAB_PCDS_FEATURE_FLAG
: ('FLAG', TAB_PCDS_FEATURE_FLAG
),
101 TAB_PCDS_DYNAMIC
: ('DYN', TAB_PCDS_DYNAMIC
),
102 TAB_PCDS_DYNAMIC_HII
: ('DYNHII', TAB_PCDS_DYNAMIC
),
103 TAB_PCDS_DYNAMIC_VPD
: ('DYNVPD', TAB_PCDS_DYNAMIC
),
104 TAB_PCDS_DYNAMIC_EX
: ('DEX', TAB_PCDS_DYNAMIC_EX
),
105 TAB_PCDS_DYNAMIC_EX_HII
: ('DEXHII', TAB_PCDS_DYNAMIC_EX
),
106 TAB_PCDS_DYNAMIC_EX_VPD
: ('DEXVPD', TAB_PCDS_DYNAMIC_EX
),
109 ## The look up table to map module type to driver type
111 SUP_MODULE_SEC
: '0x3 (SECURITY_CORE)',
112 SUP_MODULE_PEI_CORE
: '0x4 (PEI_CORE)',
113 SUP_MODULE_PEIM
: '0x6 (PEIM)',
114 SUP_MODULE_DXE_CORE
: '0x5 (DXE_CORE)',
115 SUP_MODULE_DXE_DRIVER
: '0x7 (DRIVER)',
116 SUP_MODULE_DXE_SAL_DRIVER
: '0x7 (DRIVER)',
117 SUP_MODULE_DXE_SMM_DRIVER
: '0x7 (DRIVER)',
118 SUP_MODULE_DXE_RUNTIME_DRIVER
: '0x7 (DRIVER)',
119 SUP_MODULE_UEFI_DRIVER
: '0x7 (DRIVER)',
120 SUP_MODULE_UEFI_APPLICATION
: '0x9 (APPLICATION)',
121 SUP_MODULE_SMM_CORE
: '0xD (SMM_CORE)',
122 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
123 SUP_MODULE_MM_STANDALONE
: '0xE (MM_STANDALONE)',
124 SUP_MODULE_MM_CORE_STANDALONE
: '0xF (MM_CORE_STANDALONE)'
127 ## The look up table of the supported opcode in the dependency expression binaries
128 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
134 # Writes a string to the file object.
136 # This function writes a string to the file object and a new line is appended
137 # afterwards. It may optionally wraps the string for better readability.
139 # @File The file object to write
140 # @String The string to be written to the file
141 # @Wrapper Indicates whether to wrap the string
143 def FileWrite(File
, String
, Wrapper
=False):
145 String
= textwrap
.fill(String
, 120)
146 File
.write(String
+ gEndOfLine
)
148 def ByteArrayForamt(Value
):
152 if Value
.startswith('{') and Value
.endswith('}'):
154 ValueList
= Value
.split(',')
155 if len(ValueList
) >= SplitNum
:
159 Len
= len(ValueList
)/SplitNum
160 for i
, element
in enumerate(ValueList
):
161 ValueList
[i
] = '0x%02X' % int(element
.strip(), 16)
165 End
= min(SplitNum
*(Id
+1), len(ValueList
))
166 Str
= ','.join(ValueList
[SplitNum
*Id
: End
])
167 if End
== len(ValueList
):
169 ArrayList
.append(Str
)
173 ArrayList
.append(Str
)
176 ArrayList
= [Value
+ '}']
177 return IsByteArray
, ArrayList
180 # Find all the header file that the module source directly includes.
182 # This function scans source code to find all header files the module may
183 # include. This is not accurate but very effective to find all the header
184 # file the module might include with #include statement.
186 # @Source The source file name
187 # @IncludePathList The list of include path to find the source file.
188 # @IncludeFiles The dictionary of current found include files.
190 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
191 FileContents
= open(Source
).read()
193 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
195 for Match
in gIncludePattern
.finditer(FileContents
):
196 FileName
= Match
.group(1).strip()
197 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
198 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
199 if os
.path
.exists(FullFileName
):
200 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
204 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
206 for Match
in gIncludePattern2
.finditer(FileContents
):
208 Type
= Match
.group(1)
209 if "ARCH_PROTOCOL" in Type
:
210 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
211 elif "PROTOCOL" in Type
:
212 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
214 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
215 elif TAB_GUID
in Type
:
216 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
219 for Dir
in IncludePathList
:
220 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
221 if os
.path
.exists(FullFileName
):
222 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
225 ## Split each lines in file
227 # This method is used to split the lines in file to make the length of each line
228 # less than MaxLength.
230 # @param Content The content of file
231 # @param MaxLength The Max Length of the line
233 def FileLinesSplit(Content
=None, MaxLength
=None):
234 ContentList
= Content
.split(TAB_LINE_BREAK
)
237 for Line
in ContentList
:
238 while len(Line
.rstrip()) > MaxLength
:
239 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
240 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
241 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
242 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
243 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
245 LineBreakIndex
= MaxLength
246 NewContentList
.append(Line
[:LineBreakIndex
])
247 Line
= Line
[LineBreakIndex
:]
249 NewContentList
.append(Line
)
250 for NewLine
in NewContentList
:
251 NewContent
+= NewLine
+ TAB_LINE_BREAK
253 NewContent
= NewContent
.replace(TAB_LINE_BREAK
, gEndOfLine
).replace('\r\r\n', gEndOfLine
)
259 # Parse binary dependency expression section
261 # This utility class parses the dependency expression section and translate the readable
262 # GUID name and value.
264 class DepexParser(object):
266 # Constructor function for class DepexParser
268 # This constructor function collect GUID values so that the readable
269 # GUID name can be translated.
271 # @param self The object pointer
272 # @param Wa Workspace context information
274 def __init__(self
, Wa
):
276 for Pa
in Wa
.AutoGenObjectList
:
277 for Package
in Pa
.PackageList
:
278 for Protocol
in Package
.Protocols
:
279 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
280 self
._GuidDb
[GuidValue
.upper()] = Protocol
281 for Ppi
in Package
.Ppis
:
282 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
283 self
._GuidDb
[GuidValue
.upper()] = Ppi
284 for Guid
in Package
.Guids
:
285 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
286 self
._GuidDb
[GuidValue
.upper()] = Guid
287 for Ma
in Pa
.ModuleAutoGenList
:
288 for Pcd
in Ma
.FixedVoidTypePcds
:
289 PcdValue
= Ma
.FixedVoidTypePcds
[Pcd
]
290 if len(PcdValue
.split(',')) == 16:
291 GuidValue
= GuidStructureByteArrayToGuidString(PcdValue
)
292 self
._GuidDb
[GuidValue
.upper()] = Pcd
294 # Parse the binary dependency expression files.
296 # This function parses the binary dependency expression file and translate it
297 # to the instruction list.
299 # @param self The object pointer
300 # @param DepexFileName The file name of binary dependency expression file.
302 def ParseDepexFile(self
, DepexFileName
):
303 DepexFile
= open(DepexFileName
, "rb")
305 OpCode
= DepexFile
.read(1)
307 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
308 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
309 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
310 struct
.unpack(PACK_PATTERN_GUID
, DepexFile
.read(16))
311 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
312 Statement
= "%s %s" % (Statement
, GuidString
)
313 DepexStatement
.append(Statement
)
314 OpCode
= DepexFile
.read(1)
316 return DepexStatement
319 # Reports library information
321 # This class reports the module library subsection in the build report file.
323 class LibraryReport(object):
325 # Constructor function for class LibraryReport
327 # This constructor function generates LibraryReport object for
330 # @param self The object pointer
331 # @param M Module context information
333 def __init__(self
, M
):
334 self
.LibraryList
= []
335 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
336 self
._EdkIIModule
= True
338 self
._EdkIIModule
= False
340 for Lib
in M
.DependentLibraryList
:
341 LibInfPath
= str(Lib
)
342 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
343 LibConstructorList
= Lib
.ConstructorList
344 LibDesstructorList
= Lib
.DestructorList
345 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
346 for LibAutoGen
in M
.LibraryAutoGenList
:
347 if LibInfPath
== LibAutoGen
.MetaFile
.Path
:
348 LibTime
= LibAutoGen
.BuildTime
350 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
, LibTime
))
353 # Generate report for module library information
355 # This function generates report for the module library.
356 # If the module is EDKII style one, the additional library class, library
357 # constructor/destructor and dependency expression may also be reported.
359 # @param self The object pointer
360 # @param File The file object for report
362 def GenerateReport(self
, File
):
363 if len(self
.LibraryList
) > 0:
364 FileWrite(File
, gSubSectionStart
)
365 FileWrite(File
, TAB_BRG_LIBRARY
)
366 FileWrite(File
, gSubSectionSep
)
367 for LibraryItem
in self
.LibraryList
:
368 LibInfPath
= LibraryItem
[0]
369 FileWrite(File
, LibInfPath
)
372 # Report library class, library constructor and destructor for
373 # EDKII style module.
375 if self
._EdkIIModule
:
376 LibClass
= LibraryItem
[1]
378 LibConstructor
= " ".join(LibraryItem
[2])
380 EdkIILibInfo
+= " C = " + LibConstructor
381 LibDestructor
= " ".join(LibraryItem
[3])
383 EdkIILibInfo
+= " D = " + LibDestructor
384 LibDepex
= " ".join(LibraryItem
[4])
386 EdkIILibInfo
+= " Depex = " + LibDepex
388 EdkIILibInfo
+= " Time = " + LibraryItem
[5]
390 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
392 FileWrite(File
, "{%s}" % LibClass
)
394 FileWrite(File
, gSubSectionEnd
)
397 # Reports dependency expression information
399 # This class reports the module dependency expression subsection in the build report file.
401 class DepexReport(object):
403 # Constructor function for class DepexReport
405 # This constructor function generates DepexReport object for
406 # a module. If the module source contains the DXS file (usually EDK
407 # style module), it uses the dependency in DXS file; otherwise,
408 # it uses the dependency expression from its own INF [Depex] section
409 # and then merges with the ones from its dependent library INF.
411 # @param self The object pointer
412 # @param M Module context information
414 def __init__(self
, M
):
416 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
417 ModuleType
= M
.ModuleType
419 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
421 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
]:
424 for Source
in M
.SourceFileList
:
425 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
426 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
428 self
.Depex
= Match
.group(1).strip()
432 self
.Depex
= M
.DepexExpressionDict
.get(M
.ModuleType
, "")
433 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
434 if not self
.ModuleDepex
:
435 self
.ModuleDepex
= "(None)"
438 for Lib
in M
.DependentLibraryList
:
439 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
441 LibDepexList
.append("(" + LibDepex
+ ")")
442 self
.LibraryDepex
= " AND ".join(LibDepexList
)
443 if not self
.LibraryDepex
:
444 self
.LibraryDepex
= "(None)"
448 # Generate report for module dependency expression information
450 # This function generates report for the module dependency expression.
452 # @param self The object pointer
453 # @param File The file object for report
454 # @param GlobalDepexParser The platform global Dependency expression parser object
456 def GenerateReport(self
, File
, GlobalDepexParser
):
459 FileWrite(File
, gSubSectionStart
)
460 if os
.path
.isfile(self
._DepexFileName
):
462 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
463 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
464 for DepexStatement
in DepexStatements
:
465 FileWrite(File
, " %s" % DepexStatement
)
466 FileWrite(File
, gSubSectionSep
)
468 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
470 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
472 if self
.Source
== "INF":
473 FileWrite(File
, self
.Depex
, True)
474 FileWrite(File
, gSubSectionSep
)
475 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
476 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
478 FileWrite(File
, self
.Depex
)
479 FileWrite(File
, gSubSectionEnd
)
482 # Reports dependency expression information
484 # This class reports the module build flags subsection in the build report file.
486 class BuildFlagsReport(object):
488 # Constructor function for class BuildFlagsReport
490 # This constructor function generates BuildFlagsReport object for
491 # a module. It reports the build tool chain tag and all relevant
492 # build flags to build the module.
494 # @param self The object pointer
495 # @param M Module context information
497 def __init__(self
, M
):
500 # Add build flags according to source file extension so that
501 # irrelevant ones can be filtered out.
503 for Source
in M
.SourceFileList
:
504 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
505 if Ext
in [".c", ".cc", ".cpp"]:
506 BuildOptions
["CC"] = 1
507 elif Ext
in [".s", ".asm"]:
508 BuildOptions
["PP"] = 1
509 BuildOptions
["ASM"] = 1
510 elif Ext
in [".vfr"]:
511 BuildOptions
["VFRPP"] = 1
512 BuildOptions
["VFR"] = 1
513 elif Ext
in [".dxs"]:
514 BuildOptions
["APP"] = 1
515 BuildOptions
["CC"] = 1
516 elif Ext
in [".asl"]:
517 BuildOptions
["ASLPP"] = 1
518 BuildOptions
["ASL"] = 1
519 elif Ext
in [".aslc"]:
520 BuildOptions
["ASLCC"] = 1
521 BuildOptions
["ASLDLINK"] = 1
522 BuildOptions
["CC"] = 1
523 elif Ext
in [".asm16"]:
524 BuildOptions
["ASMLINK"] = 1
525 BuildOptions
["SLINK"] = 1
526 BuildOptions
["DLINK"] = 1
529 # Save module build flags.
531 self
.ToolChainTag
= M
.ToolChain
533 for Tool
in BuildOptions
:
534 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
537 # Generate report for module build flags information
539 # This function generates report for the module build flags expression.
541 # @param self The object pointer
542 # @param File The file object for report
544 def GenerateReport(self
, File
):
545 FileWrite(File
, gSubSectionStart
)
546 FileWrite(File
, "Build Flags")
547 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
548 for Tool
in self
.BuildFlags
:
549 FileWrite(File
, gSubSectionSep
)
550 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
552 FileWrite(File
, gSubSectionEnd
)
556 # Reports individual module information
558 # This class reports the module section in the build report file.
559 # It comprises of module summary, module PCD, library, dependency expression,
560 # build flags sections.
562 class ModuleReport(object):
564 # Constructor function for class ModuleReport
566 # This constructor function generates ModuleReport object for
567 # a separate module in a platform build.
569 # @param self The object pointer
570 # @param M Module context information
571 # @param ReportType The kind of report items in the final report file
573 def __init__(self
, M
, ReportType
):
574 self
.ModuleName
= M
.Module
.BaseName
575 self
.ModuleInfPath
= M
.MetaFile
.File
576 self
.FileGuid
= M
.Guid
578 self
.BuildTimeStamp
= None
582 ModuleType
= M
.ModuleType
584 ModuleType
= COMPONENT_TO_MODULE_MAP_DICT
.get(M
.ComponentType
, "")
586 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
588 if ModuleType
== SUP_MODULE_DXE_SMM_DRIVER
:
589 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
590 if int(PiSpec
, 0) >= 0x0001000A:
591 ModuleType
= "SMM_DRIVER"
592 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
593 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
594 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
595 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
596 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
597 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
598 self
.BuildTime
= M
.BuildTime
600 self
._BuildDir
= M
.BuildDir
601 self
.ModulePcdSet
= {}
602 if "PCD" in ReportType
:
604 # Collect all module used PCD set: module INF referenced directly or indirectly.
605 # It also saves module INF default values of them in case they exist.
607 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
608 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
610 self
.LibraryReport
= None
611 if "LIBRARY" in ReportType
:
612 self
.LibraryReport
= LibraryReport(M
)
614 self
.DepexReport
= None
615 if "DEPEX" in ReportType
:
616 self
.DepexReport
= DepexReport(M
)
618 if "BUILD_FLAGS" in ReportType
:
619 self
.BuildFlagsReport
= BuildFlagsReport(M
)
623 # Generate report for module information
625 # This function generates report for separate module expression
626 # in a platform build.
628 # @param self The object pointer
629 # @param File The file object for report
630 # @param GlobalPcdReport The platform global PCD report object
631 # @param GlobalPredictionReport The platform global Prediction report object
632 # @param GlobalDepexParser The platform global Dependency expression parser object
633 # @param ReportType The kind of report items in the final report file
635 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
636 FileWrite(File
, gSectionStart
)
638 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
639 if os
.path
.isfile(FwReportFileName
):
641 FileContents
= open(FwReportFileName
).read()
642 Match
= gModuleSizePattern
.search(FileContents
)
644 self
.Size
= int(Match
.group(1))
646 Match
= gTimeStampPattern
.search(FileContents
)
648 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
650 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
652 if "HASH" in ReportType
:
653 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
654 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
655 if os
.path
.isfile(DefaultEFIfile
):
656 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
657 # rebase the efi image since its base address may not zero
658 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
660 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
661 except Exception as X
:
662 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
663 EndOfProcedure
= threading
.Event()
664 EndOfProcedure
.clear()
665 if PopenObject
.stderr
:
666 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
667 StdErrThread
.setName("STDERR-Redirector")
668 StdErrThread
.setDaemon(False)
670 # waiting for program exit
672 if PopenObject
.stderr
:
674 if PopenObject
.returncode
!= 0:
675 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
676 if os
.path
.isfile(Tempfile
):
677 self
.Hash
= hashlib
.sha1()
678 buf
= open(Tempfile
, 'rb').read()
679 if self
.Hash
.update(buf
):
680 self
.Hash
= self
.Hash
.update(buf
)
681 self
.Hash
= self
.Hash
.hexdigest()
684 FileWrite(File
, "Module Summary")
685 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
686 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
687 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
689 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
691 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
692 if self
.BuildTimeStamp
:
693 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
695 FileWrite(File
, "Module Build Time: %s" % self
.BuildTime
)
697 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
698 if self
.UefiSpecVersion
:
699 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
700 if self
.PiSpecVersion
:
701 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
703 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
705 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
706 if self
.PciClassCode
:
707 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
709 FileWrite(File
, gSectionSep
)
711 if "PCD" in ReportType
:
712 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
714 if "LIBRARY" in ReportType
:
715 self
.LibraryReport
.GenerateReport(File
)
717 if "DEPEX" in ReportType
:
718 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
720 if "BUILD_FLAGS" in ReportType
:
721 self
.BuildFlagsReport
.GenerateReport(File
)
723 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
724 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
726 FileWrite(File
, gSectionEnd
)
728 def ReadMessage(From
, To
, ExitFlag
):
730 # read one line a time
731 Line
= From
.readline()
732 # empty string means "end"
733 if Line
is not None and Line
!= "":
741 # Reports platform and module PCD information
743 # This class reports the platform PCD section and module PCD subsection
744 # in the build report file.
746 class PcdReport(object):
748 # Constructor function for class PcdReport
750 # This constructor function generates PcdReport object a platform build.
751 # It collects the whole PCD database from platform DSC files, platform
752 # flash description file and package DEC files.
754 # @param self The object pointer
755 # @param Wa Workspace context information
757 def __init__(self
, Wa
):
760 self
.ConditionalPcds
= {}
764 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
768 self
.DefaultStoreSingle
= True
769 self
.SkuSingle
= True
770 if GlobalData
.gDefaultStores
and len(GlobalData
.gDefaultStores
) > 1:
771 self
.DefaultStoreSingle
= False
772 if GlobalData
.gSkuids
and len(GlobalData
.gSkuids
) > 1:
773 self
.SkuSingle
= False
775 self
.ModulePcdOverride
= {}
776 for Pa
in Wa
.AutoGenObjectList
:
779 # Collect all platform referenced PCDs and grouped them by PCD token space
782 for Pcd
in Pa
.AllPcdList
:
783 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
784 if Pcd
not in PcdList
:
786 if len(Pcd
.TokenCName
) > self
.MaxLen
:
787 self
.MaxLen
= len(Pcd
.TokenCName
)
789 # Collect the PCD defined in DSC/FDF file, but not used in module
791 UnusedPcdFullList
= []
792 for item
in Pa
.Platform
.Pcds
:
793 Pcd
= Pa
.Platform
.Pcds
[item
]
795 # check the Pcd in FDF file, whether it is used in module first
796 for T
in PCD_TYPE_LIST
:
797 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
803 for package
in Pa
.PackageList
:
804 for T
in PCD_TYPE_LIST
:
805 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
808 if not Pcd
.DatumType
:
809 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
813 if not Pcd
.DatumType
:
815 # Try to remove Hii and Vpd suffix
816 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
817 PcdType
= TAB_PCDS_DYNAMIC_EX
818 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
819 PcdType
= TAB_PCDS_DYNAMIC
820 for package
in Pa
.PackageList
:
821 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
822 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
825 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
826 UnusedPcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
827 if Pcd
in UnusedPcdList
:
828 UnusedPcdList
.remove(Pcd
)
829 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
830 UnusedPcdFullList
.append(Pcd
)
831 if len(Pcd
.TokenCName
) > self
.MaxLen
:
832 self
.MaxLen
= len(Pcd
.TokenCName
)
834 if GlobalData
.gConditionalPcds
:
835 for PcdItem
in GlobalData
.gConditionalPcds
:
837 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
838 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
839 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
840 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
841 if Pcd
not in PcdList
:
845 if UnusedPcdFullList
:
846 for Pcd
in UnusedPcdFullList
:
847 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
849 UnusedPcdList
.append(Pcd
)
851 for Pcd
in UnusedPcdList
:
852 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
853 if Pcd
not in PcdList
:
856 for Module
in Pa
.Platform
.Modules
.values():
858 # Collect module override PCDs
860 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
861 TokenCName
= ModulePcd
.TokenCName
862 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
863 ModuleDefault
= ModulePcd
.DefaultValue
864 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
865 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
869 # Collect PCD DEC default value.
871 self
.DecPcdDefault
= {}
873 for Pa
in Wa
.AutoGenObjectList
:
874 for Package
in Pa
.PackageList
:
875 Guids
= Package
.Guids
876 self
._GuidDict
.update(Guids
)
877 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
878 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
879 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
881 # Collect PCDs defined in DSC common section
883 self
.DscPcdDefault
= {}
884 for Pa
in Wa
.AutoGenObjectList
:
885 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
886 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DscDefaultValue
888 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
890 def GenerateReport(self
, File
, ModulePcdSet
):
892 if self
.ConditionalPcds
:
893 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
896 for Token
in self
.UnusedPcds
:
897 TokenDict
= self
.UnusedPcds
[Token
]
898 for Type
in TokenDict
:
905 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
906 self
.GenerateReportDetail(File
, ModulePcdSet
)
909 # Generate report for PCD information
911 # This function generates report for separate module expression
912 # in a platform build.
914 # @param self The object pointer
915 # @param File The file object for report
916 # @param ModulePcdSet Set of all PCDs referenced by module or None for
917 # platform PCD report
918 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
919 # directives section report, 2 means Unused Pcds section report
920 # @param DscOverridePcds Module DSC override PCDs set
922 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
923 PcdDict
= self
.AllPcds
924 if ReportSubType
== 1:
925 PcdDict
= self
.ConditionalPcds
926 elif ReportSubType
== 2:
927 PcdDict
= self
.UnusedPcds
930 FileWrite(File
, gSectionStart
)
931 if ReportSubType
== 1:
932 FileWrite(File
, "Conditional Directives used by the build system")
933 elif ReportSubType
== 2:
934 FileWrite(File
, "PCDs not used by modules or in conditional directives")
936 FileWrite(File
, "Platform Configuration Database Report")
938 FileWrite(File
, " *B - PCD override in the build option")
939 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
940 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
941 if not ReportSubType
:
942 FileWrite(File
, " *M - Module scoped PCD override")
943 FileWrite(File
, gSectionSep
)
945 if not ReportSubType
and ModulePcdSet
:
947 # For module PCD sub-section
949 FileWrite(File
, gSubSectionStart
)
950 FileWrite(File
, TAB_BRG_PCD
)
951 FileWrite(File
, gSubSectionSep
)
955 for Type
in PcdDict
[Key
]:
956 for Pcd
in PcdDict
[Key
][Type
]:
957 AllPcdDict
[Key
][(Pcd
.TokenCName
, Type
)] = Pcd
958 for Key
in sorted(AllPcdDict
):
960 # Group PCD by their token space GUID C Name
963 for PcdTokenCName
, Type
in sorted(AllPcdDict
[Key
]):
965 # Group PCD by their usage type
967 Pcd
= AllPcdDict
[Key
][(PcdTokenCName
, Type
)]
968 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
970 if GlobalData
.MixedPcd
:
971 for PcdKey
in GlobalData
.MixedPcd
:
972 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
973 PcdTokenCName
= PcdKey
[0]
975 if MixedPcdFlag
and not ModulePcdSet
:
978 # Get PCD default value and their override relationship
980 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
981 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
982 DscDefaultValBak
= DscDefaultValue
984 for (CName
, Guid
, Field
) in self
.FdfPcdSet
:
985 if CName
== PcdTokenCName
and Guid
== Key
:
986 DscDefaultValue
= self
.FdfPcdSet
[(CName
, Guid
, Field
)]
988 if DscDefaultValue
!= DscDefaultValBak
:
990 DscDefaultValue
= ValueExpressionEx(DscDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
991 except BadExpression
as DscDefaultValue
:
992 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" %(DscDefaultValue
, Pcd
.DatumType
))
994 InfDefaultValue
= None
996 PcdValue
= DecDefaultValue
998 PcdValue
= DscDefaultValue
999 #The DefaultValue of StructurePcd already be the latest, no need to update.
1000 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1001 Pcd
.DefaultValue
= PcdValue
1002 if ModulePcdSet
is not None:
1003 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
1005 InfDefaultValue
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
1006 #The DefaultValue of StructurePcd already be the latest, no need to update.
1007 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1008 Pcd
.DefaultValue
= PcdValue
1011 InfDefaultValue
= ValueExpressionEx(InfDefaultValue
, Pcd
.DatumType
, self
._GuidDict
)(True)
1012 except BadExpression
as InfDefaultValue
:
1013 EdkLogger
.error('BuildReport', FORMAT_INVALID
, "PCD Value: %s, Type: %s" % (InfDefaultValue
, Pcd
.DatumType
))
1014 if InfDefaultValue
== "":
1015 InfDefaultValue
= None
1017 BuildOptionMatch
= False
1018 if GlobalData
.BuildOptionPcd
:
1019 for pcd
in GlobalData
.BuildOptionPcd
:
1020 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
1024 #The DefaultValue of StructurePcd already be the latest, no need to update.
1025 if not self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1026 Pcd
.DefaultValue
= PcdValue
1027 BuildOptionMatch
= True
1031 if ModulePcdSet
is None:
1033 FileWrite(File
, Key
)
1037 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1038 PcdValueNumber
= int(PcdValue
.strip(), 0)
1039 if DecDefaultValue
is None:
1042 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
1043 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
1045 if InfDefaultValue
is None:
1048 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
1049 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
1051 if DscDefaultValue
is None:
1054 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
1055 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
1057 if DecDefaultValue
is None:
1060 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
1062 if InfDefaultValue
is None:
1065 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
1067 if DscDefaultValue
is None:
1070 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
1073 if self
.IsStructurePcd(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
):
1075 if TypeName
in ('DYNVPD', 'DEXVPD'):
1076 SkuInfoList
= Pcd
.SkuInfoList
1077 Pcd
= GlobalData
.gStructurePcd
[self
.Arch
][(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
)]
1078 Pcd
.DatumType
= Pcd
.StructName
1079 if TypeName
in ('DYNVPD', 'DEXVPD'):
1080 Pcd
.SkuInfoList
= SkuInfoList
1081 if Pcd
.PcdValueFromComm
or Pcd
.PcdFieldValueFromComm
:
1082 BuildOptionMatch
= True
1084 elif Pcd
.PcdValueFromFdf
or Pcd
.PcdFieldValueFromFdf
:
1085 DscDefaultValue
= True
1088 elif Pcd
.SkuOverrideValues
:
1090 if Pcd
.DefaultFromDSC
:
1094 for item
in Pcd
.SkuOverrideValues
:
1095 DictLen
+= len(Pcd
.SkuOverrideValues
[item
])
1099 if not Pcd
.SkuInfoList
:
1100 OverrideValues
= Pcd
.SkuOverrideValues
1102 for Data
in OverrideValues
.values():
1103 Struct
= list(Data
.values())
1105 DscOverride
= self
.ParseStruct(Struct
[0])
1108 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1110 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1111 if TypeName
in ('DYNHII', 'DEXHII'):
1112 if SkuInfo
.DefaultStoreDict
:
1113 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1114 for DefaultStore
in DefaultStoreList
:
1115 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1116 DscOverride
= self
.ParseStruct(OverrideValues
[DefaultStore
])
1120 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1122 Keys
= list(OverrideValues
.keys())
1123 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1124 DscOverride
= self
.ParseStruct(OverrideFieldStruct
)
1128 DscDefaultValue
= True
1134 DscDefaultValue
= True
1139 # Report PCD item according to their override relationship
1141 if Pcd
.DatumType
== 'BOOLEAN':
1143 DscDefaultValue
= str(int(DscDefaultValue
, 0))
1145 DecDefaultValue
= str(int(DecDefaultValue
, 0))
1147 InfDefaultValue
= str(int(InfDefaultValue
, 0))
1148 if Pcd
.DefaultValue
:
1149 Pcd
.DefaultValue
= str(int(Pcd
.DefaultValue
, 0))
1151 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, ' ')
1152 elif InfDefaultValue
and InfMatch
:
1153 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1154 elif BuildOptionMatch
:
1155 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*B')
1157 if DscDefaultValue
and DscMatch
:
1158 if (Pcd
.TokenCName
, Key
, Field
) in self
.FdfPcdSet
:
1159 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*F')
1161 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*P')
1163 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValBak
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1165 if ModulePcdSet
is None:
1168 if not TypeName
in ('PATCH', 'FLAG', 'FIXED'):
1170 if not BuildOptionMatch
:
1171 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1172 for ModulePath
in ModuleOverride
:
1173 ModuleDefault
= ModuleOverride
[ModulePath
]
1174 if Pcd
.DatumType
in TAB_PCD_NUMERIC_TYPES
:
1175 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1176 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1177 if Pcd
.DatumType
== 'BOOLEAN':
1178 ModuleDefault
= str(ModulePcdDefaultValueNumber
)
1180 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1183 IsByteArray
, ArrayList
= ByteArrayForamt(ModuleDefault
.strip())
1185 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, '{'))
1186 for Array
in ArrayList
:
1187 FileWrite(File
, Array
)
1189 Value
= ModuleDefault
.strip()
1190 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1191 if Value
.startswith(('0x', '0X')):
1192 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1194 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1195 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 15, ModulePath
, Value
))
1197 if ModulePcdSet
is None:
1198 FileWrite(File
, gSectionEnd
)
1200 if not ReportSubType
and ModulePcdSet
:
1201 FileWrite(File
, gSubSectionEnd
)
1203 def ParseStruct(self
, struct
):
1204 HasDscOverride
= False
1206 for _
, Values
in struct
.items():
1207 if Values
[1] and Values
[1].endswith('.dsc'):
1208 HasDscOverride
= True
1210 return HasDscOverride
1212 def PrintPcdDefault(self
, File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
):
1213 if not DscMatch
and DscDefaultValue
is not None:
1214 Value
= DscDefaultValue
.strip()
1215 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1217 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', "{"))
1218 for Array
in ArrayList
:
1219 FileWrite(File
, Array
)
1221 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1222 if Value
.startswith(('0x', '0X')):
1223 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1225 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1226 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', Value
))
1227 if not InfMatch
and InfDefaultValue
is not None:
1228 Value
= InfDefaultValue
.strip()
1229 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1231 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', "{"))
1232 for Array
in ArrayList
:
1233 FileWrite(File
, Array
)
1235 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1236 if Value
.startswith(('0x', '0X')):
1237 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1239 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1240 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', Value
))
1242 if not DecMatch
and DecDefaultValue
is not None:
1243 Value
= DecDefaultValue
.strip()
1244 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1246 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', "{"))
1247 for Array
in ArrayList
:
1248 FileWrite(File
, Array
)
1250 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1251 if Value
.startswith(('0x', '0X')):
1252 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1254 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1255 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', Value
))
1257 self
.PrintStructureInfo(File
, Pcd
.DefaultValues
)
1258 if DecMatch
and IsStructure
:
1259 self
.PrintStructureInfo(File
, Pcd
.DefaultValues
)
1261 def PrintPcdValue(self
, File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, Flag
= ' '):
1262 if not Pcd
.SkuInfoList
:
1263 Value
= Pcd
.DefaultValue
1264 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1266 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1267 for Array
in ArrayList
:
1268 FileWrite(File
, Array
)
1270 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1271 if Value
.startswith(('0x', '0X')):
1272 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1274 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1275 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1277 FiledOverrideFlag
= False
1278 OverrideValues
= Pcd
.SkuOverrideValues
1280 for Data
in OverrideValues
.values():
1281 Struct
= list(Data
.values())
1283 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, Struct
[0])
1284 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1285 FiledOverrideFlag
= True
1287 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1288 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1289 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1290 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1293 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1295 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1296 SkuIdName
= SkuInfo
.SkuIdName
1297 if TypeName
in ('DYNHII', 'DEXHII'):
1298 if SkuInfo
.DefaultStoreDict
:
1299 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1300 for DefaultStore
in DefaultStoreList
:
1301 Value
= SkuInfo
.DefaultStoreDict
[DefaultStore
]
1302 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1303 if Pcd
.DatumType
== 'BOOLEAN':
1304 Value
= str(int(Value
, 0))
1308 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1309 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1310 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1311 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1312 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1313 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1315 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1316 for Array
in ArrayList
:
1317 FileWrite(File
, Array
)
1319 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1320 if Value
.startswith(('0x', '0X')):
1321 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1323 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1324 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1325 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1326 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1327 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1328 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1329 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1331 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1334 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1335 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1336 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1337 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '{'))
1338 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1339 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', '{'))
1341 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1342 for Array
in ArrayList
:
1343 FileWrite(File
, Array
)
1345 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1346 if Value
.startswith(('0x', '0X')):
1347 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1349 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1350 if self
.DefaultStoreSingle
and self
.SkuSingle
:
1351 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1352 elif self
.DefaultStoreSingle
and not self
.SkuSingle
:
1353 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1354 elif not self
.DefaultStoreSingle
and self
.SkuSingle
:
1355 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + DefaultStore
+ ')', Value
))
1357 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1358 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1360 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1361 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[DefaultStore
])
1362 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1363 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1365 Value
= SkuInfo
.DefaultValue
1366 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1367 if Pcd
.DatumType
== 'BOOLEAN':
1368 Value
= str(int(Value
, 0))
1373 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1375 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1376 for Array
in ArrayList
:
1377 FileWrite(File
, Array
)
1379 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1380 if Value
.startswith(('0x', '0X')):
1381 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1383 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1385 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1387 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1391 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', "{"))
1393 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', "{"))
1394 for Array
in ArrayList
:
1395 FileWrite(File
, Array
)
1397 if Pcd
.DatumType
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
1398 if Value
.startswith(('0x', '0X')):
1399 Value
= '{} ({:d})'.format(Value
, int(Value
, 0))
1401 Value
= "0x{:X} ({})".format(int(Value
, 0), Value
)
1403 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1405 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuIdName
+ ')', Value
))
1406 if TypeName
in ('DYNVPD', 'DEXVPD'):
1407 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1408 VPDPcdItem
= (Pcd
.TokenSpaceGuidCName
+ '.' + PcdTokenCName
, SkuIdName
, SkuInfo
.VpdOffset
, Pcd
.MaxDatumSize
, SkuInfo
.DefaultValue
)
1409 if VPDPcdItem
not in VPDPcdList
:
1410 VPDPcdList
.append(VPDPcdItem
)
1412 FiledOverrideFlag
= False
1413 OverrideValues
= Pcd
.SkuOverrideValues
[Sku
]
1415 Keys
= OverrideValues
.keys()
1416 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, OverrideValues
[Keys
[0]])
1417 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1418 FiledOverrideFlag
= True
1419 if not FiledOverrideFlag
and (Pcd
.PcdFieldValueFromComm
or Pcd
.PcdFieldValueFromFdf
):
1420 OverrideFieldStruct
= self
.OverrideFieldValue(Pcd
, {})
1421 self
.PrintStructureInfo(File
, OverrideFieldStruct
)
1422 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1424 def OverrideFieldValue(self
, Pcd
, OverrideStruct
):
1425 OverrideFieldStruct
= collections
.OrderedDict()
1427 for Key
, Values
in OverrideStruct
.items():
1428 if Values
[1] and Values
[1].endswith('.dsc'):
1429 OverrideFieldStruct
[Key
] = Values
1430 if Pcd
.PcdFieldValueFromFdf
:
1431 for Key
, Values
in Pcd
.PcdFieldValueFromFdf
.items():
1432 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1434 OverrideFieldStruct
[Key
] = Values
1435 if Pcd
.PcdFieldValueFromComm
:
1436 for Key
, Values
in Pcd
.PcdFieldValueFromComm
.items():
1437 if Key
in OverrideFieldStruct
and Values
[0] == OverrideFieldStruct
[Key
][0]:
1439 OverrideFieldStruct
[Key
] = Values
1440 return OverrideFieldStruct
1442 def PrintStructureInfo(self
, File
, Struct
):
1443 for Key
, Value
in sorted(Struct
.items(), key
=lambda x
: x
[0]):
1444 if Value
[1] and 'build command options' in Value
[1]:
1445 FileWrite(File
, ' *B %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1446 elif Value
[1] and Value
[1].endswith('.fdf'):
1447 FileWrite(File
, ' *F %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1449 FileWrite(File
, ' %-*s = %s' % (self
.MaxLen
+ 4, '.' + Key
, Value
[0]))
1451 def StrtoHex(self
, value
):
1453 value
= hex(int(value
))
1456 if value
.startswith("L\"") and value
.endswith("\""):
1458 for ch
in value
[2:-1]:
1459 valuelist
.append(hex(ord(ch
)))
1460 valuelist
.append('0x00')
1462 elif value
.startswith("\"") and value
.endswith("\""):
1463 return hex(ord(value
[1:-1]))
1464 elif value
.startswith("{") and value
.endswith("}"):
1466 if ',' not in value
:
1468 for ch
in value
[1:-1].split(','):
1470 if ch
.startswith('0x') or ch
.startswith('0X'):
1471 valuelist
.append(ch
)
1474 valuelist
.append(hex(int(ch
.strip())))
1481 def IsStructurePcd(self
, PcdToken
, PcdTokenSpaceGuid
):
1482 if GlobalData
.gStructurePcd
and (self
.Arch
in GlobalData
.gStructurePcd
) and ((PcdToken
, PcdTokenSpaceGuid
) in GlobalData
.gStructurePcd
[self
.Arch
]):
1488 # Reports platform and module Prediction information
1490 # This class reports the platform execution order prediction section and
1491 # module load fixed address prediction subsection in the build report file.
1493 class PredictionReport(object):
1495 # Constructor function for class PredictionReport
1497 # This constructor function generates PredictionReport object for the platform.
1499 # @param self: The object pointer
1500 # @param Wa Workspace context information
1502 def __init__(self
, Wa
):
1503 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1504 self
._MapFileParsed
= False
1505 self
._EotToolInvoked
= False
1506 self
._FvDir
= Wa
.FvDir
1507 self
._EotDir
= Wa
.BuildDir
1508 self
._FfsEntryPoint
= {}
1510 self
._SourceList
= []
1511 self
.FixedMapDict
= {}
1516 # Collect all platform reference source files and GUID C Name
1518 for Pa
in Wa
.AutoGenObjectList
:
1519 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1521 # BASE typed modules are EFI agnostic, so we need not scan
1522 # their source code to find PPI/Protocol produce or consume
1525 if Module
.ModuleType
== SUP_MODULE_BASE
:
1528 # Add module referenced source files
1530 self
._SourceList
.append(str(Module
))
1532 for Source
in Module
.SourceFileList
:
1533 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1534 self
._SourceList
.append(" " + str(Source
))
1535 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1536 for IncludeFile
in IncludeList
.values():
1537 self
._SourceList
.append(" " + IncludeFile
)
1539 for Guid
in Module
.PpiList
:
1540 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1541 for Guid
in Module
.ProtocolList
:
1542 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1543 for Guid
in Module
.GuidList
:
1544 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1546 if Module
.Guid
and not Module
.IsLibrary
:
1547 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1548 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
1549 RealEntryPoint
= "_ModuleEntryPoint"
1551 RealEntryPoint
= EntryPoint
1552 if EntryPoint
== "_ModuleEntryPoint":
1553 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
1554 Match
= gGlueLibEntryPoint
.search(CCFlags
)
1556 EntryPoint
= Match
.group(1)
1558 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1562 # Collect platform firmware volume list as the input of EOT.
1566 for Fd
in Wa
.FdfProfile
.FdDict
:
1567 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1568 if FdRegion
.RegionType
!= BINARY_FILE_TYPE_FV
:
1570 for FvName
in FdRegion
.RegionDataList
:
1571 if FvName
in self
._FvList
:
1573 self
._FvList
.append(FvName
)
1574 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1575 for Section
in Ffs
.SectionList
:
1577 for FvSection
in Section
.SectionList
:
1578 if FvSection
.FvName
in self
._FvList
:
1580 self
._FvList
.append(FvSection
.FvName
)
1581 except AttributeError:
1586 # Parse platform fixed address map files
1588 # This function parses the platform final fixed address map file to get
1589 # the database of predicted fixed address for module image base, entry point
1592 # @param self: The object pointer
1594 def _ParseMapFile(self
):
1595 if self
._MapFileParsed
:
1597 self
._MapFileParsed
= True
1598 if os
.path
.isfile(self
._MapFileName
):
1600 FileContents
= open(self
._MapFileName
).read()
1601 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1602 AddressType
= Match
.group(1)
1603 BaseAddress
= Match
.group(2)
1604 EntryPoint
= Match
.group(3)
1605 Guid
= Match
.group(4).upper()
1606 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1607 List
.append((AddressType
, BaseAddress
, "*I"))
1608 List
.append((AddressType
, EntryPoint
, "*E"))
1610 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1613 # Invokes EOT tool to get the predicted the execution order.
1615 # This function invokes EOT tool to calculate the predicted dispatch order
1617 # @param self: The object pointer
1619 def _InvokeEotTool(self
):
1620 if self
._EotToolInvoked
:
1623 self
._EotToolInvoked
= True
1625 for FvName
in self
._FvList
:
1626 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1627 if os
.path
.isfile(FvFile
):
1628 FvFileList
.append(FvFile
)
1630 if len(FvFileList
) == 0:
1633 # Write source file list and GUID file list to an intermediate file
1634 # as the input for EOT tool and dispatch List as the output file
1637 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1638 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1639 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1641 TempFile
= open(SourceList
, "w+")
1642 for Item
in self
._SourceList
:
1643 FileWrite(TempFile
, Item
)
1645 TempFile
= open(GuidList
, "w+")
1646 for Key
in self
._GuidMap
:
1647 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1651 from Eot
.EotMain
import Eot
1654 # Invoke EOT tool and echo its runtime performance
1656 EotStartTime
= time
.time()
1657 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1658 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1659 EotEndTime
= time
.time()
1660 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1661 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1664 # Parse the output of EOT tool
1666 for Line
in open(DispatchList
):
1667 if len(Line
.split()) < 4:
1669 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1670 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1671 if len(Symbol
) > self
.MaxLen
:
1672 self
.MaxLen
= len(Symbol
)
1673 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1675 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1676 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1680 # Generate platform execution order report
1682 # This function generates the predicted module execution order.
1684 # @param self The object pointer
1685 # @param File The file object for report
1687 def _GenerateExecutionOrderReport(self
, File
):
1688 self
._InvokeEotTool
()
1689 if len(self
.ItemList
) == 0:
1691 FileWrite(File
, gSectionStart
)
1692 FileWrite(File
, "Execution Order Prediction")
1693 FileWrite(File
, "*P PEI phase")
1694 FileWrite(File
, "*D DXE phase")
1695 FileWrite(File
, "*E Module INF entry point name")
1696 FileWrite(File
, "*N Module notification function name")
1698 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1699 FileWrite(File
, gSectionSep
)
1700 for Item
in self
.ItemList
:
1701 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1703 FileWrite(File
, gSectionStart
)
1706 # Generate Fixed Address report.
1708 # This function generate the predicted fixed address report for a module
1709 # specified by Guid.
1711 # @param self The object pointer
1712 # @param File The file object for report
1713 # @param Guid The module Guid value.
1714 # @param NotifyList The list of all notify function in a module
1716 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1717 self
._ParseMapFile
()
1718 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1719 if not FixedAddressList
:
1722 FileWrite(File
, gSubSectionStart
)
1723 FileWrite(File
, "Fixed Address Prediction")
1724 FileWrite(File
, "*I Image Loading Address")
1725 FileWrite(File
, "*E Entry Point Address")
1726 FileWrite(File
, "*N Notification Function Address")
1727 FileWrite(File
, "*F Flash Address")
1728 FileWrite(File
, "*M Memory Address")
1729 FileWrite(File
, "*S SMM RAM Offset")
1730 FileWrite(File
, "TOM Top of Memory")
1732 FileWrite(File
, "Type Address Name")
1733 FileWrite(File
, gSubSectionSep
)
1734 for Item
in FixedAddressList
:
1739 Name
= "(Image Base)"
1740 elif Symbol
== "*E":
1741 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1742 elif Symbol
in NotifyList
:
1750 elif "Memory" in Type
:
1756 Value
= "TOM" + Value
1758 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1761 # Generate report for the prediction part
1763 # This function generate the predicted fixed address report for a module or
1764 # predicted module execution order for a platform.
1765 # If the input Guid is None, then, it generates the predicted module execution order;
1766 # otherwise it generated the module fixed loading address for the module specified by
1769 # @param self The object pointer
1770 # @param File The file object for report
1771 # @param Guid The module Guid value.
1773 def GenerateReport(self
, File
, Guid
):
1775 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1777 self
._GenerateExecutionOrderReport
(File
)
1780 # Reports FD region information
1782 # This class reports the FD subsection in the build report file.
1783 # It collects region information of platform flash device.
1784 # If the region is a firmware volume, it lists the set of modules
1785 # and its space information; otherwise, it only lists its region name,
1786 # base address and size in its sub-section header.
1787 # If there are nesting FVs, the nested FVs will list immediate after
1788 # this FD region subsection
1790 class FdRegionReport(object):
1792 # Discover all the nested FV name list.
1794 # This is an internal worker function to discover the all the nested FV information
1795 # in the parent firmware volume. It uses deep first search algorithm recursively to
1796 # find all the FV list name and append them to the list.
1798 # @param self The object pointer
1799 # @param FvName The name of current firmware file system
1800 # @param Wa Workspace context information
1802 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1803 FvDictKey
=FvName
.upper()
1804 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1805 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1806 for Section
in Ffs
.SectionList
:
1808 for FvSection
in Section
.SectionList
:
1809 if FvSection
.FvName
in self
.FvList
:
1811 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1812 self
.FvList
.append(FvSection
.FvName
)
1813 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1814 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1815 except AttributeError:
1819 # Constructor function for class FdRegionReport
1821 # This constructor function generates FdRegionReport object for a specified FdRegion.
1822 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1823 # volume list. This function also collects GUID map in order to dump module identification
1824 # in the final report.
1826 # @param self: The object pointer
1827 # @param FdRegion The current FdRegion object
1828 # @param Wa Workspace context information
1830 def __init__(self
, FdRegion
, Wa
):
1831 self
.Type
= FdRegion
.RegionType
1832 self
.BaseAddress
= FdRegion
.Offset
1833 self
.Size
= FdRegion
.Size
1837 self
._FvDir
= Wa
.FvDir
1838 self
._WorkspaceDir
= Wa
.WorkspaceDir
1841 # If the input FdRegion is not a firmware volume,
1844 if self
.Type
!= BINARY_FILE_TYPE_FV
:
1848 # Find all nested FVs in the FdRegion
1850 for FvName
in FdRegion
.RegionDataList
:
1851 if FvName
in self
.FvList
:
1853 self
.FvList
.append(FvName
)
1854 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1855 self
._DiscoverNestedFvList
(FvName
, Wa
)
1859 # Collect PCDs declared in DEC files.
1861 for Pa
in Wa
.AutoGenObjectList
:
1862 for Package
in Pa
.PackageList
:
1863 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1864 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1865 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1867 # Collect PCDs defined in DSC file
1869 for Pa
in Wa
.AutoGenObjectList
:
1870 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
1871 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1872 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1875 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1877 self
._GuidsDb
[PEI_APRIORI_GUID
] = "PEI Apriori"
1878 self
._GuidsDb
[DXE_APRIORI_GUID
] = "DXE Apriori"
1880 # Add ACPI table storage file
1882 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1884 for Pa
in Wa
.AutoGenObjectList
:
1885 for ModuleKey
in Pa
.Platform
.Modules
:
1886 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1887 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1888 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1891 # Collect the GUID map in the FV firmware volume
1893 for FvName
in self
.FvList
:
1894 FvDictKey
=FvName
.upper()
1895 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1896 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1899 # collect GUID map for binary EFI file in FDF file.
1901 Guid
= Ffs
.NameGuid
.upper()
1902 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1904 PcdTokenspace
= Match
.group(1)
1905 PcdToken
= Match
.group(2)
1906 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1907 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1908 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1909 for Section
in Ffs
.SectionList
:
1911 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1912 self
._GuidsDb
[Guid
] = ModuleSectFile
1913 except AttributeError:
1915 except AttributeError:
1920 # Internal worker function to generate report for the FD region
1922 # This internal worker function to generate report for the FD region.
1923 # It the type is firmware volume, it lists offset and module identification.
1925 # @param self The object pointer
1926 # @param File The file object for report
1927 # @param Title The title for the FD subsection
1928 # @param BaseAddress The base address for the FD region
1929 # @param Size The size of the FD region
1930 # @param FvName The FV name if the FD region is a firmware volume
1932 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1933 FileWrite(File
, gSubSectionStart
)
1934 FileWrite(File
, Title
)
1935 FileWrite(File
, "Type: %s" % Type
)
1936 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1938 if self
.Type
== BINARY_FILE_TYPE_FV
:
1942 if FvName
.upper().endswith('.FV'):
1943 FileExt
= FvName
+ ".txt"
1945 FileExt
= FvName
+ ".Fv.txt"
1947 if not os
.path
.isfile(FileExt
):
1948 FvReportFileName
= mws
.join(self
._WorkspaceDir
, FileExt
)
1949 if not os
.path
.isfile(FvReportFileName
):
1950 FvReportFileName
= os
.path
.join(self
._FvDir
, FileExt
)
1953 # Collect size info in the firmware volume.
1955 FvReport
= open(FvReportFileName
).read()
1956 Match
= gFvTotalSizePattern
.search(FvReport
)
1958 FvTotalSize
= int(Match
.group(1), 16)
1959 Match
= gFvTakenSizePattern
.search(FvReport
)
1961 FvTakenSize
= int(Match
.group(1), 16)
1962 FvFreeSize
= FvTotalSize
- FvTakenSize
1964 # Write size information to the report file.
1966 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1967 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1968 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1969 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1970 FileWrite(File
, "Offset Module")
1971 FileWrite(File
, gSubSectionSep
)
1973 # Write module offset and module identification to the report file.
1976 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1977 Guid
= Match
.group(2).upper()
1978 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1979 OffsetList
= sorted(OffsetInfo
.keys())
1980 for Offset
in OffsetList
:
1981 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1983 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1985 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1986 FileWrite(File
, gSubSectionEnd
)
1989 # Generate report for the FD region
1991 # This function generates report for the FD region.
1993 # @param self The object pointer
1994 # @param File The file object for report
1996 def GenerateReport(self
, File
):
1997 if (len(self
.FvList
) > 0):
1998 for FvItem
in self
.FvList
:
1999 Info
= self
.FvInfo
[FvItem
]
2000 self
._GenerateReport
(File
, Info
[0], TAB_FV_DIRECTORY
, Info
[1], Info
[2], FvItem
)
2002 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
2005 # Reports FD information
2007 # This class reports the FD section in the build report file.
2008 # It collects flash device information for a platform.
2010 class FdReport(object):
2012 # Constructor function for class FdReport
2014 # This constructor function generates FdReport object for a specified
2017 # @param self The object pointer
2018 # @param Fd The current Firmware device object
2019 # @param Wa Workspace context information
2021 def __init__(self
, Fd
, Wa
):
2022 self
.FdName
= Fd
.FdUiName
2023 self
.BaseAddress
= Fd
.BaseAddress
2025 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
2026 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, TAB_FV_DIRECTORY
)
2027 self
.VPDBaseAddress
= 0
2029 for index
, FdRegion
in enumerate(Fd
.RegionList
):
2030 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
2031 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
2032 self
.VPDSize
= self
.FdRegionList
[index
].Size
2036 # Generate report for the firmware device.
2038 # This function generates report for the firmware device.
2040 # @param self The object pointer
2041 # @param File The file object for report
2043 def GenerateReport(self
, File
):
2044 FileWrite(File
, gSectionStart
)
2045 FileWrite(File
, "Firmware Device (FD)")
2046 FileWrite(File
, "FD Name: %s" % self
.FdName
)
2047 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
2048 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
2049 if len(self
.FdRegionList
) > 0:
2050 FileWrite(File
, gSectionSep
)
2051 for FdRegionItem
in self
.FdRegionList
:
2052 FdRegionItem
.GenerateReport(File
)
2055 VPDPcdList
.sort(key
=lambda x
: int(x
[2], 0))
2056 FileWrite(File
, gSubSectionStart
)
2057 FileWrite(File
, "FD VPD Region")
2058 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
2059 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
2060 FileWrite(File
, gSubSectionSep
)
2061 for item
in VPDPcdList
:
2062 # Add BaseAddress for offset
2063 Offset
= '0x%08X' % (int(item
[2], 16) + self
.VPDBaseAddress
)
2064 IsByteArray
, ArrayList
= ByteArrayForamt(item
[-1])
2066 if len(GlobalData
.gSkuids
) == 1 :
2067 Skuinfo
= GlobalData
.gSkuids
[0]
2069 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], '{'))
2070 for Array
in ArrayList
:
2071 FileWrite(File
, Array
)
2073 FileWrite(File
, "%s | %s | %s | %s | %s" % (item
[0], Skuinfo
, Offset
, item
[3], item
[-1]))
2074 FileWrite(File
, gSubSectionEnd
)
2075 FileWrite(File
, gSectionEnd
)
2080 # Reports platform information
2082 # This class reports the whole platform information
2084 class PlatformReport(object):
2086 # Constructor function for class PlatformReport
2088 # This constructor function generates PlatformReport object a platform build.
2089 # It generates report for platform summary, flash, global PCDs and detailed
2090 # module information for modules involved in platform build.
2092 # @param self The object pointer
2093 # @param Wa Workspace context information
2094 # @param MaList The list of modules in the platform build
2096 def __init__(self
, Wa
, MaList
, ReportType
):
2097 self
._WorkspaceDir
= Wa
.WorkspaceDir
2098 self
.PlatformName
= Wa
.Name
2099 self
.PlatformDscPath
= Wa
.Platform
2100 self
.Architectures
= " ".join(Wa
.ArchList
)
2101 self
.ToolChain
= Wa
.ToolChain
2102 self
.Target
= Wa
.BuildTarget
2103 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
2104 self
.BuildEnvironment
= platform
.platform()
2106 self
.PcdReport
= None
2107 if "PCD" in ReportType
:
2108 self
.PcdReport
= PcdReport(Wa
)
2110 self
.FdReportList
= []
2111 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
is None:
2112 for Fd
in Wa
.FdfProfile
.FdDict
:
2113 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
2115 self
.PredictionReport
= None
2116 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
2117 self
.PredictionReport
= PredictionReport(Wa
)
2119 self
.DepexParser
= None
2120 if "DEPEX" in ReportType
:
2121 self
.DepexParser
= DepexParser(Wa
)
2123 self
.ModuleReportList
= []
2124 if MaList
is not None:
2125 self
._IsModuleBuild
= True
2127 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
2129 self
._IsModuleBuild
= False
2130 for Pa
in Wa
.AutoGenObjectList
:
2131 ModuleAutoGenList
= []
2132 for ModuleKey
in Pa
.Platform
.Modules
:
2133 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
2134 if GlobalData
.gFdfParser
is not None:
2135 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
2136 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
2137 for InfName
in INFList
:
2138 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
2139 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
)
2142 if Ma
not in ModuleAutoGenList
:
2143 ModuleAutoGenList
.append(Ma
)
2144 for MGen
in ModuleAutoGenList
:
2145 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
2150 # Generate report for the whole platform.
2152 # This function generates report for platform information.
2153 # It comprises of platform summary, global PCD, flash and
2154 # module list sections.
2156 # @param self The object pointer
2157 # @param File The file object for report
2158 # @param BuildDuration The total time to build the modules
2159 # @param AutoGenTime The total time of AutoGen Phase
2160 # @param MakeTime The total time of Make Phase
2161 # @param GenFdsTime The total time of GenFds Phase
2162 # @param ReportType The kind of report items in the final report file
2164 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
2165 FileWrite(File
, "Platform Summary")
2166 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
2167 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
2168 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
2169 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
2170 FileWrite(File
, "Target: %s" % self
.Target
)
2171 if GlobalData
.gSkuids
:
2172 FileWrite(File
, "SKUID: %s" % " ".join(GlobalData
.gSkuids
))
2173 if GlobalData
.gDefaultStores
:
2174 FileWrite(File
, "DefaultStore: %s" % " ".join(GlobalData
.gDefaultStores
))
2175 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
2176 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
2177 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
2179 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
2181 FileWrite(File
, "Make Duration: %s" % MakeTime
)
2183 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
2184 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
2186 if GlobalData
.MixedPcd
:
2187 FileWrite(File
, gSectionStart
)
2188 FileWrite(File
, "The following PCDs use different access methods:")
2189 FileWrite(File
, gSectionSep
)
2190 for PcdItem
in GlobalData
.MixedPcd
:
2191 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
2192 FileWrite(File
, gSectionEnd
)
2194 if not self
._IsModuleBuild
:
2195 if "PCD" in ReportType
:
2196 self
.PcdReport
.GenerateReport(File
, None)
2198 if "FLASH" in ReportType
:
2199 for FdReportListItem
in self
.FdReportList
:
2200 FdReportListItem
.GenerateReport(File
)
2202 for ModuleReportItem
in self
.ModuleReportList
:
2203 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
2205 if not self
._IsModuleBuild
:
2206 if "EXECUTION_ORDER" in ReportType
:
2207 self
.PredictionReport
.GenerateReport(File
, None)
2209 ## BuildReport class
2211 # This base class contain the routines to collect data and then
2212 # applies certain format to the output report
2214 class BuildReport(object):
2216 # Constructor function for class BuildReport
2218 # This constructor function generates BuildReport object a platform build.
2219 # It generates report for platform summary, flash, global PCDs and detailed
2220 # module information for modules involved in platform build.
2222 # @param self The object pointer
2223 # @param ReportFile The file name to save report file
2224 # @param ReportType The kind of report items in the final report file
2226 def __init__(self
, ReportFile
, ReportType
):
2227 self
.ReportFile
= ReportFile
2229 self
.ReportList
= []
2230 self
.ReportType
= []
2232 for ReportTypeItem
in ReportType
:
2233 if ReportTypeItem
not in self
.ReportType
:
2234 self
.ReportType
.append(ReportTypeItem
)
2236 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2238 # Adds platform report to the list
2240 # This function adds a platform report to the final report list.
2242 # @param self The object pointer
2243 # @param Wa Workspace context information
2244 # @param MaList The list of modules in the platform build
2246 def AddPlatformReport(self
, Wa
, MaList
=None):
2248 self
.ReportList
.append((Wa
, MaList
))
2251 # Generates the final report.
2253 # This function generates platform build report. It invokes GenerateReport()
2254 # method for every platform report in the list.
2256 # @param self The object pointer
2257 # @param BuildDuration The total time to build the modules
2258 # @param AutoGenTime The total time of AutoGen phase
2259 # @param MakeTime The total time of Make phase
2260 # @param GenFdsTime The total time of GenFds phase
2262 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
2266 for (Wa
, MaList
) in self
.ReportList
:
2267 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
2268 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
2269 SaveFileOnChange(self
.ReportFile
, Content
, True)
2270 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
2272 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
2274 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
2275 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
2278 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2279 if __name__
== '__main__':