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 - 2017, Intel Corporation. All rights reserved.<BR>
8 # This program and the accompanying materials
9 # are licensed and made available under the terms and conditions of the BSD License
10 # which accompanies this distribution. The full text of the license may be found at
11 # http://opensource.org/licenses/bsd-license.php
13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 import Common
.LongFilePathOs
as os
30 from datetime
import datetime
31 from StringIO
import StringIO
32 from Common
import EdkLogger
33 from Common
.Misc
import SaveFileOnChange
34 from Common
.Misc
import GuidStructureByteArrayToGuidString
35 from Common
.Misc
import GuidStructureStringToGuidString
36 from Common
.InfClassObject
import gComponentType2ModuleType
37 from Common
.BuildToolError
import FILE_WRITE_FAILURE
38 from Common
.BuildToolError
import CODE_ERROR
39 from Common
.BuildToolError
import COMMAND_FAILURE
40 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
41 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
42 import Common
.GlobalData
as GlobalData
43 from AutoGen
.AutoGen
import ModuleAutoGen
44 from Common
.Misc
import PathClass
45 from Common
.String
import NormPath
46 from Common
.DataType
import *
49 ## Pattern to extract contents in EDK DXS files
50 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
52 ## Pattern to find total FV total size, occupied size in flash report intermediate file
53 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
54 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
56 ## Pattern to find module size and time stamp in module summary report intermediate file
57 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
58 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
60 ## Pattern to find GUID value in flash description files
61 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
63 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
64 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
66 ## Pattern to find module base address and entry point in fixed flash map file
67 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
68 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
70 ## Pattern to find all module referenced header files in source files
71 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
72 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
74 ## Pattern to find the entry point for EDK module using EDKII Glue library
75 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
77 ## Tags for MaxLength of line in report
80 ## Tags for end of line in report
83 ## Tags for section start, end and separator
84 gSectionStart
= ">" + "=" * (gLineMaxLength
- 2) + "<"
85 gSectionEnd
= "<" + "=" * (gLineMaxLength
- 2) + ">" + "\n"
86 gSectionSep
= "=" * gLineMaxLength
88 ## Tags for subsection start, end and separator
89 gSubSectionStart
= ">" + "-" * (gLineMaxLength
- 2) + "<"
90 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
- 2) + ">"
91 gSubSectionSep
= "-" * gLineMaxLength
94 ## The look up table to map PCD type to pair of report display type and DEC type
96 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
97 'PatchableInModule': ('PATCH', 'PatchableInModule'),
98 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
99 'Dynamic' : ('DYN', 'Dynamic'),
100 'DynamicHii' : ('DYNHII', 'Dynamic'),
101 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
102 'DynamicEx' : ('DEX', 'DynamicEx'),
103 'DynamicExHii' : ('DEXHII', 'DynamicEx'),
104 'DynamicExVpd' : ('DEXVPD', 'DynamicEx'),
107 ## The look up table to map module type to driver type
109 'SEC' : '0x3 (SECURITY_CORE)',
110 'PEI_CORE' : '0x4 (PEI_CORE)',
111 'PEIM' : '0x6 (PEIM)',
112 'DXE_CORE' : '0x5 (DXE_CORE)',
113 'DXE_DRIVER' : '0x7 (DRIVER)',
114 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
115 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
116 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
117 'UEFI_DRIVER' : '0x7 (DRIVER)',
118 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
119 'SMM_CORE' : '0xD (SMM_CORE)',
120 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
121 'MM_STANDALONE' : '0xE (MM_STANDALONE)',
122 'MM_CORE_STANDALONE' : '0xF (MM_CORE_STANDALONE)'
125 ## The look up table of the supported opcode in the dependency expression binaries
126 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
129 # Writes a string to the file object.
131 # This function writes a string to the file object and a new line is appended
132 # afterwards. It may optionally wraps the string for better readability.
134 # @File The file object to write
135 # @String The string to be written to the file
136 # @Wrapper Indicates whether to wrap the string
138 def FileWrite(File
, String
, Wrapper
=False):
140 String
= textwrap
.fill(String
, 120)
141 File
.write(String
+ gEndOfLine
)
143 def ByteArrayForamt(Value
):
147 if Value
.startswith('{') and Value
.endswith('}'):
149 ValueList
= Value
.split(',')
150 if len(ValueList
) >= SplitNum
:
154 Len
= len(ValueList
)/SplitNum
155 for i
, element
in enumerate(ValueList
):
156 ValueList
[i
] = '0x%02X' % int(element
.strip(), 16)
160 End
= min(SplitNum
*(Id
+1), len(ValueList
))
161 Str
= ','.join(ValueList
[SplitNum
*Id
: End
])
162 if End
== len(ValueList
):
164 ArrayList
.append(Str
)
168 ArrayList
.append(Str
)
171 ArrayList
= [Value
+ '}']
172 return IsByteArray
, ArrayList
175 # Find all the header file that the module source directly includes.
177 # This function scans source code to find all header files the module may
178 # include. This is not accurate but very effective to find all the header
179 # file the module might include with #include statement.
181 # @Source The source file name
182 # @IncludePathList The list of include path to find the source file.
183 # @IncludeFiles The dictionary of current found include files.
185 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
186 FileContents
= open(Source
).read()
188 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
190 for Match
in gIncludePattern
.finditer(FileContents
):
191 FileName
= Match
.group(1).strip()
192 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
193 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
194 if os
.path
.exists(FullFileName
):
195 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
199 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
201 for Match
in gIncludePattern2
.finditer(FileContents
):
203 Type
= Match
.group(1)
204 if "ARCH_PROTOCOL" in Type
:
205 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
206 elif "PROTOCOL" in Type
:
207 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
209 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
211 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
214 for Dir
in IncludePathList
:
215 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
216 if os
.path
.exists(FullFileName
):
217 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
220 ## Split each lines in file
222 # This method is used to split the lines in file to make the length of each line
223 # less than MaxLength.
225 # @param Content The content of file
226 # @param MaxLength The Max Length of the line
228 def FileLinesSplit(Content
=None, MaxLength
=None):
229 ContentList
= Content
.split(TAB_LINE_BREAK
)
232 for Line
in ContentList
:
233 while len(Line
.rstrip()) > MaxLength
:
234 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
235 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
236 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
237 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
238 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
240 LineBreakIndex
= MaxLength
241 NewContentList
.append(Line
[:LineBreakIndex
])
242 Line
= Line
[LineBreakIndex
:]
244 NewContentList
.append(Line
)
245 for NewLine
in NewContentList
:
246 NewContent
+= NewLine
+ TAB_LINE_BREAK
248 NewContent
= NewContent
.replace(TAB_LINE_BREAK
, gEndOfLine
).replace('\r\r\n', gEndOfLine
)
254 # Parse binary dependency expression section
256 # This utility class parses the dependency expression section and translate the readable
257 # GUID name and value.
259 class DepexParser(object):
261 # Constructor function for class DepexParser
263 # This constructor function collect GUID values so that the readable
264 # GUID name can be translated.
266 # @param self The object pointer
267 # @param Wa Workspace context information
269 def __init__(self
, Wa
):
271 for Pa
in Wa
.AutoGenObjectList
:
272 for Package
in Pa
.PackageList
:
273 for Protocol
in Package
.Protocols
:
274 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
275 self
._GuidDb
[GuidValue
.upper()] = Protocol
276 for Ppi
in Package
.Ppis
:
277 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
278 self
._GuidDb
[GuidValue
.upper()] = Ppi
279 for Guid
in Package
.Guids
:
280 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
281 self
._GuidDb
[GuidValue
.upper()] = Guid
284 # Parse the binary dependency expression files.
286 # This function parses the binary dependency expression file and translate it
287 # to the instruction list.
289 # @param self The object pointer
290 # @param DepexFileName The file name of binary dependency expression file.
292 def ParseDepexFile(self
, DepexFileName
):
293 DepexFile
= open(DepexFileName
, "rb")
295 OpCode
= DepexFile
.read(1)
297 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
298 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
299 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
300 struct
.unpack("=LHHBBBBBBBB", DepexFile
.read(16))
301 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
302 Statement
= "%s %s" % (Statement
, GuidString
)
303 DepexStatement
.append(Statement
)
304 OpCode
= DepexFile
.read(1)
306 return DepexStatement
309 # Reports library information
311 # This class reports the module library subsection in the build report file.
313 class LibraryReport(object):
315 # Constructor function for class LibraryReport
317 # This constructor function generates LibraryReport object for
320 # @param self The object pointer
321 # @param M Module context information
323 def __init__(self
, M
):
324 self
.LibraryList
= []
325 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
326 self
._EdkIIModule
= True
328 self
._EdkIIModule
= False
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
)
362 # Report library class, library constructor and destructor for
363 # EDKII style module.
365 if self
._EdkIIModule
:
366 LibClass
= LibraryItem
[1]
368 LibConstructor
= " ".join(LibraryItem
[2])
370 EdkIILibInfo
+= " C = " + LibConstructor
371 LibDestructor
= " ".join(LibraryItem
[3])
373 EdkIILibInfo
+= " D = " + LibDestructor
374 LibDepex
= " ".join(LibraryItem
[4])
376 EdkIILibInfo
+= " Depex = " + LibDepex
378 EdkIILibInfo
+= " Time = " + LibraryItem
[5]
380 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
382 FileWrite(File
, "{%s}" % LibClass
)
384 FileWrite(File
, gSubSectionEnd
)
387 # Reports dependency expression information
389 # This class reports the module dependency expression subsection in the build report file.
391 class DepexReport(object):
393 # Constructor function for class DepexReport
395 # This constructor function generates DepexReport object for
396 # a module. If the module source contains the DXS file (usually EDK
397 # style module), it uses the dependency in DXS file; otherwise,
398 # it uses the dependency expression from its own INF [Depex] section
399 # and then merges with the ones from its dependent library INF.
401 # @param self The object pointer
402 # @param M Module context information
404 def __init__(self
, M
):
406 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
407 ModuleType
= M
.ModuleType
409 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
411 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "MM_CORE_STANDALONE", "UEFI_APPLICATION"]:
414 for Source
in M
.SourceFileList
:
415 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
416 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
418 self
.Depex
= Match
.group(1).strip()
422 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
423 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
424 if not self
.ModuleDepex
:
425 self
.ModuleDepex
= "(None)"
428 for Lib
in M
.DependentLibraryList
:
429 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
431 LibDepexList
.append("(" + LibDepex
+ ")")
432 self
.LibraryDepex
= " AND ".join(LibDepexList
)
433 if not self
.LibraryDepex
:
434 self
.LibraryDepex
= "(None)"
438 # Generate report for module dependency expression information
440 # This function generates report for the module dependency expression.
442 # @param self The object pointer
443 # @param File The file object for report
444 # @param GlobalDepexParser The platform global Dependency expression parser object
446 def GenerateReport(self
, File
, GlobalDepexParser
):
449 FileWrite(File
, gSubSectionStart
)
450 if os
.path
.isfile(self
._DepexFileName
):
452 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
453 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
454 for DepexStatement
in DepexStatements
:
455 FileWrite(File
, " %s" % DepexStatement
)
456 FileWrite(File
, gSubSectionSep
)
458 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
460 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
462 if self
.Source
== "INF":
463 FileWrite(File
, "%s" % self
.Depex
, True)
464 FileWrite(File
, gSubSectionSep
)
465 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
466 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
468 FileWrite(File
, "%s" % self
.Depex
)
469 FileWrite(File
, gSubSectionEnd
)
472 # Reports dependency expression information
474 # This class reports the module build flags subsection in the build report file.
476 class BuildFlagsReport(object):
478 # Constructor function for class BuildFlagsReport
480 # This constructor function generates BuildFlagsReport object for
481 # a module. It reports the build tool chain tag and all relevant
482 # build flags to build the module.
484 # @param self The object pointer
485 # @param M Module context information
487 def __init__(self
, M
):
490 # Add build flags according to source file extension so that
491 # irrelevant ones can be filtered out.
493 for Source
in M
.SourceFileList
:
494 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
495 if Ext
in [".c", ".cc", ".cpp"]:
496 BuildOptions
["CC"] = 1
497 elif Ext
in [".s", ".asm"]:
498 BuildOptions
["PP"] = 1
499 BuildOptions
["ASM"] = 1
500 elif Ext
in [".vfr"]:
501 BuildOptions
["VFRPP"] = 1
502 BuildOptions
["VFR"] = 1
503 elif Ext
in [".dxs"]:
504 BuildOptions
["APP"] = 1
505 BuildOptions
["CC"] = 1
506 elif Ext
in [".asl"]:
507 BuildOptions
["ASLPP"] = 1
508 BuildOptions
["ASL"] = 1
509 elif Ext
in [".aslc"]:
510 BuildOptions
["ASLCC"] = 1
511 BuildOptions
["ASLDLINK"] = 1
512 BuildOptions
["CC"] = 1
513 elif Ext
in [".asm16"]:
514 BuildOptions
["ASMLINK"] = 1
515 BuildOptions
["SLINK"] = 1
516 BuildOptions
["DLINK"] = 1
519 # Save module build flags.
521 self
.ToolChainTag
= M
.ToolChain
523 for Tool
in BuildOptions
:
524 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
527 # Generate report for module build flags information
529 # This function generates report for the module build flags expression.
531 # @param self The object pointer
532 # @param File The file object for report
534 def GenerateReport(self
, File
):
535 FileWrite(File
, gSubSectionStart
)
536 FileWrite(File
, "Build Flags")
537 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
538 for Tool
in self
.BuildFlags
:
539 FileWrite(File
, gSubSectionSep
)
540 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
542 FileWrite(File
, gSubSectionEnd
)
546 # Reports individual module information
548 # This class reports the module section in the build report file.
549 # It comprises of module summary, module PCD, library, dependency expression,
550 # build flags sections.
552 class ModuleReport(object):
554 # Constructor function for class ModuleReport
556 # This constructor function generates ModuleReport object for
557 # a separate module in a platform build.
559 # @param self The object pointer
560 # @param M Module context information
561 # @param ReportType The kind of report items in the final report file
563 def __init__(self
, M
, ReportType
):
564 self
.ModuleName
= M
.Module
.BaseName
565 self
.ModuleInfPath
= M
.MetaFile
.File
566 self
.FileGuid
= M
.Guid
568 self
.BuildTimeStamp
= None
572 ModuleType
= M
.ModuleType
574 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
576 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
578 if ModuleType
== "DXE_SMM_DRIVER":
579 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
580 if int(PiSpec
, 0) >= 0x0001000A:
581 ModuleType
= "SMM_DRIVER"
582 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
583 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
584 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
585 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
586 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
587 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
588 self
.BuildTime
= M
.BuildTime
590 self
._BuildDir
= M
.BuildDir
591 self
.ModulePcdSet
= {}
592 if "PCD" in ReportType
:
594 # Collect all module used PCD set: module INF referenced directly or indirectly.
595 # It also saves module INF default values of them in case they exist.
597 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
598 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
600 self
.LibraryReport
= None
601 if "LIBRARY" in ReportType
:
602 self
.LibraryReport
= LibraryReport(M
)
604 self
.DepexReport
= None
605 if "DEPEX" in ReportType
:
606 self
.DepexReport
= DepexReport(M
)
608 if "BUILD_FLAGS" in ReportType
:
609 self
.BuildFlagsReport
= BuildFlagsReport(M
)
613 # Generate report for module information
615 # This function generates report for separate module expression
616 # in a platform build.
618 # @param self The object pointer
619 # @param File The file object for report
620 # @param GlobalPcdReport The platform global PCD report object
621 # @param GlobalPredictionReport The platform global Prediction report object
622 # @param GlobalDepexParser The platform global Dependency expression parser object
623 # @param ReportType The kind of report items in the final report file
625 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
626 FileWrite(File
, gSectionStart
)
628 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
629 if os
.path
.isfile(FwReportFileName
):
631 FileContents
= open(FwReportFileName
).read()
632 Match
= gModuleSizePattern
.search(FileContents
)
634 self
.Size
= int(Match
.group(1))
636 Match
= gTimeStampPattern
.search(FileContents
)
638 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
640 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
642 if "HASH" in ReportType
:
643 OutputDir
= os
.path
.join(self
._BuildDir
, "OUTPUT")
644 DefaultEFIfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ ".efi")
645 if os
.path
.isfile(DefaultEFIfile
):
646 Tempfile
= os
.path
.join(OutputDir
, self
.ModuleName
+ "_hash.tmp")
647 # rebase the efi image since its base address may not zero
648 cmd
= ["GenFw", "--rebase", str(0), "-o", Tempfile
, DefaultEFIfile
]
650 PopenObject
= subprocess
.Popen(' '.join(cmd
), stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
652 EdkLogger
.error("GenFw", COMMAND_FAILURE
, ExtraData
="%s: %s" % (str(X
), cmd
[0]))
653 EndOfProcedure
= threading
.Event()
654 EndOfProcedure
.clear()
655 if PopenObject
.stderr
:
656 StdErrThread
= threading
.Thread(target
=ReadMessage
, args
=(PopenObject
.stderr
, EdkLogger
.quiet
, EndOfProcedure
))
657 StdErrThread
.setName("STDERR-Redirector")
658 StdErrThread
.setDaemon(False)
660 # waiting for program exit
662 if PopenObject
.stderr
:
664 if PopenObject
.returncode
!= 0:
665 EdkLogger
.error("GenFw", COMMAND_FAILURE
, "Failed to generate firmware hash image for %s" % (DefaultEFIfile
))
666 if os
.path
.isfile(Tempfile
):
667 self
.Hash
= hashlib
.sha1()
668 buf
= open(Tempfile
, 'rb').read()
669 if self
.Hash
.update(buf
):
670 self
.Hash
= self
.Hash
.update(buf
)
671 self
.Hash
= self
.Hash
.hexdigest()
674 FileWrite(File
, "Module Summary")
675 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
676 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
677 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
679 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
681 FileWrite(File
, "SHA1 HASH: %s *%s" % (self
.Hash
, self
.ModuleName
+ ".efi"))
682 if self
.BuildTimeStamp
:
683 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
685 FileWrite(File
, "Module Build Time: %s" % self
.BuildTime
)
687 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
688 if self
.UefiSpecVersion
:
689 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
690 if self
.PiSpecVersion
:
691 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
693 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
695 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
696 if self
.PciClassCode
:
697 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
699 FileWrite(File
, gSectionSep
)
701 if "PCD" in ReportType
:
702 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
704 if "LIBRARY" in ReportType
:
705 self
.LibraryReport
.GenerateReport(File
)
707 if "DEPEX" in ReportType
:
708 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
710 if "BUILD_FLAGS" in ReportType
:
711 self
.BuildFlagsReport
.GenerateReport(File
)
713 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
714 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
716 FileWrite(File
, gSectionEnd
)
718 def ReadMessage(From
, To
, ExitFlag
):
720 # read one line a time
721 Line
= From
.readline()
722 # empty string means "end"
723 if Line
!= None and Line
!= "":
731 # Reports platform and module PCD information
733 # This class reports the platform PCD section and module PCD subsection
734 # in the build report file.
736 class PcdReport(object):
738 # Constructor function for class PcdReport
740 # This constructor function generates PcdReport object a platform build.
741 # It collects the whole PCD database from platform DSC files, platform
742 # flash description file and package DEC files.
744 # @param self The object pointer
745 # @param Wa Workspace context information
747 def __init__(self
, Wa
):
750 self
.ConditionalPcds
= {}
754 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
758 self
.ModulePcdOverride
= {}
759 for Pa
in Wa
.AutoGenObjectList
:
762 # Collect all platform referenced PCDs and grouped them by PCD token space
765 for Pcd
in Pa
.AllPcdList
:
766 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
767 if Pcd
not in PcdList
:
769 if len(Pcd
.TokenCName
) > self
.MaxLen
:
770 self
.MaxLen
= len(Pcd
.TokenCName
)
772 # Collect the PCD defined in DSC/FDF file, but not used in module
774 UnusedPcdFullList
= []
775 for item
in Pa
.Platform
.Pcds
:
776 Pcd
= Pa
.Platform
.Pcds
[item
]
778 # check the Pcd in FDF file, whether it is used in module first
779 for T
in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:
780 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(T
, [])
786 for package
in Pa
.PackageList
:
787 for T
in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:
788 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
791 if not Pcd
.DatumType
:
792 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
796 if not Pcd
.DatumType
:
798 # Try to remove Hii and Vpd suffix
799 if PcdType
.startswith("DynamicEx"):
800 PcdType
= "DynamicEx"
801 elif PcdType
.startswith("Dynamic"):
803 for package
in Pa
.PackageList
:
804 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
805 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
808 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
809 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
810 UnusedPcdFullList
.append(Pcd
)
811 if len(Pcd
.TokenCName
) > self
.MaxLen
:
812 self
.MaxLen
= len(Pcd
.TokenCName
)
814 if GlobalData
.gConditionalPcds
:
815 for PcdItem
in GlobalData
.gConditionalPcds
:
817 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
818 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
.keys():
819 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
820 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
821 if Pcd
not in PcdList
:
825 if UnusedPcdFullList
:
826 for Pcd
in UnusedPcdFullList
:
827 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
829 UnusedPcdList
.append(Pcd
)
831 for Pcd
in UnusedPcdList
:
832 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
833 if Pcd
not in PcdList
:
836 for Module
in Pa
.Platform
.Modules
.values():
838 # Collect module override PCDs
840 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
841 TokenCName
= ModulePcd
.TokenCName
842 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
843 ModuleDefault
= ModulePcd
.DefaultValue
844 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
845 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
849 # Collect PCD DEC default value.
851 self
.DecPcdDefault
= {}
852 for Pa
in Wa
.AutoGenObjectList
:
853 for Package
in Pa
.PackageList
:
854 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
855 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
856 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
858 # Collect PCDs defined in DSC common section
860 self
.DscPcdDefault
= {}
861 for Pa
in Wa
.AutoGenObjectList
:
862 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
863 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
865 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
867 def GenerateReport(self
, File
, ModulePcdSet
):
868 if self
.ConditionalPcds
:
869 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
871 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
872 self
.GenerateReportDetail(File
, ModulePcdSet
)
875 # Generate report for PCD information
877 # This function generates report for separate module expression
878 # in a platform build.
880 # @param self The object pointer
881 # @param File The file object for report
882 # @param ModulePcdSet Set of all PCDs referenced by module or None for
883 # platform PCD report
884 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
885 # directives section report, 2 means Unused Pcds section report
886 # @param DscOverridePcds Module DSC override PCDs set
888 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
889 PcdDict
= self
.AllPcds
890 if ReportSubType
== 1:
891 PcdDict
= self
.ConditionalPcds
892 elif ReportSubType
== 2:
893 PcdDict
= self
.UnusedPcds
895 if ModulePcdSet
== None:
896 FileWrite(File
, gSectionStart
)
897 if ReportSubType
== 1:
898 FileWrite(File
, "Conditional Directives used by the build system")
899 elif ReportSubType
== 2:
900 FileWrite(File
, "PCDs not used by modules or in conditional directives")
902 FileWrite(File
, "Platform Configuration Database Report")
904 FileWrite(File
, " *B - PCD override in the build option")
905 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
906 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
907 if not ReportSubType
:
908 FileWrite(File
, " *M - Module scoped PCD override")
909 FileWrite(File
, gSectionSep
)
911 if not ReportSubType
and ModulePcdSet
:
913 # For module PCD sub-section
915 FileWrite(File
, gSubSectionStart
)
916 FileWrite(File
, TAB_BRG_PCD
)
917 FileWrite(File
, gSubSectionSep
)
921 # Group PCD by their token space GUID C Name
924 for Type
in PcdDict
[Key
]:
926 # Group PCD by their usage type
928 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
929 for Pcd
in PcdDict
[Key
][Type
]:
930 PcdTokenCName
= Pcd
.TokenCName
932 if GlobalData
.MixedPcd
:
933 for PcdKey
in GlobalData
.MixedPcd
:
934 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdKey
]:
935 PcdTokenCName
= PcdKey
[0]
937 if MixedPcdFlag
and not ModulePcdSet
:
940 # Get PCD default value and their override relationship
942 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
943 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
944 DscDefaultValBak
= DscDefaultValue
945 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
946 InfDefaultValue
= None
948 PcdValue
= DecDefaultValue
950 PcdValue
= DscDefaultValue
951 if ModulePcdSet
!= None:
952 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
954 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
958 BuildOptionMatch
= False
959 if GlobalData
.BuildOptionPcd
:
960 for pcd
in GlobalData
.BuildOptionPcd
:
961 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
963 BuildOptionMatch
= True
967 if ModulePcdSet
== None:
973 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
974 PcdValueNumber
= int(PcdValue
.strip(), 0)
975 if DecDefaultValue
== None:
978 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
979 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
981 if InfDefaultValue
== None:
984 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
985 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
987 if DscDefaultValue
== None:
990 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
991 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
993 if DecDefaultValue
== None:
996 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
998 if InfDefaultValue
== None:
1001 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
1003 if DscDefaultValue
== None:
1006 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
1009 if GlobalData
.gStructurePcd
and (self
.Arch
in GlobalData
.gStructurePcd
.keys()) and ((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
) in GlobalData
.gStructurePcd
[self
.Arch
]):
1011 if TypeName
in ('DYNVPD', 'DEXVPD'):
1012 SkuInfoList
= Pcd
.SkuInfoList
1013 Pcd
= GlobalData
.gStructurePcd
[self
.Arch
][(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
)]
1014 Pcd
.DatumType
= Pcd
.StructName
1015 if TypeName
in ('DYNVPD', 'DEXVPD'):
1016 Pcd
.SkuInfoList
= SkuInfoList
1017 if Pcd
.OverrideValues
:
1021 # Report PCD item according to their override relationship
1023 if DecMatch
and InfMatch
:
1024 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, ' ')
1025 elif BuildOptionMatch
:
1026 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*B')
1029 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
1030 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*F')
1032 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*P')
1034 self
.PrintPcdValue(File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, '*M')
1036 if ModulePcdSet
== None:
1039 if not TypeName
in ('PATCH', 'FLAG', 'FIXED'):
1041 if not BuildOptionMatch
:
1042 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
1043 for ModulePath
in ModuleOverride
:
1044 ModuleDefault
= ModuleOverride
[ModulePath
]
1045 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
1046 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
1047 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
1049 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
1052 IsByteArray
, ArrayList
= ByteArrayForamt(ModuleDefault
.strip())
1054 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, '{'))
1055 for Array
in ArrayList
:
1056 FileWrite(File
, '%s' % (Array
))
1058 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
1060 if ModulePcdSet
== None:
1061 FileWrite(File
, gSectionEnd
)
1063 if not ReportSubType
and ModulePcdSet
:
1064 FileWrite(File
, gSubSectionEnd
)
1067 def PrintPcdDefault(self
, File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
):
1068 if not DscMatch
and DscDefaultValue
!= None:
1069 Value
= DscDefaultValue
.strip()
1070 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1072 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', "{"))
1073 for Array
in ArrayList
:
1074 FileWrite(File
, '%s' % (Array
))
1076 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', Value
))
1077 if not InfMatch
and InfDefaultValue
!= None:
1078 Value
= InfDefaultValue
.strip()
1079 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1081 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', "{"))
1082 for Array
in ArrayList
:
1083 FileWrite(File
, '%s' % (Array
))
1085 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', Value
))
1087 if not DecMatch
and DecDefaultValue
!= None:
1088 Value
= DecDefaultValue
.strip()
1089 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1091 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', "{"))
1092 for Array
in ArrayList
:
1093 FileWrite(File
, '%s' % (Array
))
1095 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', Value
))
1097 self
.PrintStructureInfo(File
, Pcd
.DefaultValues
)
1099 def PrintPcdValue(self
, File
, Pcd
, PcdTokenCName
, TypeName
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
, Flag
= ' '):
1100 if not Pcd
.SkuInfoList
:
1101 Value
= Pcd
.DefaultValue
1102 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1104 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '{'))
1105 for Array
in ArrayList
:
1106 FileWrite(File
, '%s' % (Array
))
1108 FileWrite(File
, ' %-*s : %6s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', Value
))
1110 OverrideValues
= Pcd
.OverrideValues
1112 Keys
= OverrideValues
.keys()
1113 Data
= OverrideValues
[Keys
[0]]
1114 Struct
= Data
.values()[0]
1115 self
.PrintStructureInfo(File
, Struct
)
1116 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1119 SkuList
= sorted(Pcd
.SkuInfoList
.keys())
1121 SkuInfo
= Pcd
.SkuInfoList
[Sku
]
1122 if TypeName
in ('DYNHII', 'DEXHII'):
1123 if SkuInfo
.DefaultStoreDict
:
1124 DefaultStoreList
= sorted(SkuInfo
.DefaultStoreDict
.keys())
1125 for DefaultStore
in DefaultStoreList
:
1126 Value
= SkuInfo
.DefaultStoreDict
[DefaultStore
]
1127 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1131 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1132 for Array
in ArrayList
:
1133 FileWrite(File
, '%s' % (Array
))
1135 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1138 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', '(' + DefaultStore
+ ')', '{'))
1139 for Array
in ArrayList
:
1140 FileWrite(File
, '%s' % (Array
))
1142 FileWrite(File
, ' %-*s : %6s %10s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', '(' + DefaultStore
+ ')', Value
))
1143 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
1145 OverrideValues
= Pcd
.OverrideValues
[Sku
]
1146 Struct
= OverrideValues
[DefaultStore
]
1147 self
.PrintStructureInfo(File
, Struct
)
1148 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1149 elif TypeName
in ('DYNVPD', 'DEXVPD'):
1150 Value
= SkuInfo
.DefaultValue
1151 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1155 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', "{"))
1156 for Array
in ArrayList
:
1157 FileWrite(File
, '%s' % (Array
))
1159 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', Value
))
1162 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ' , TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', "{"))
1163 for Array
in ArrayList
:
1164 FileWrite(File
, '%s' % (Array
))
1166 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ' , TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', Value
))
1167 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
1169 OverrideValues
= Pcd
.OverrideValues
[Sku
]
1171 Keys
= OverrideValues
.keys()
1172 Struct
= OverrideValues
[Keys
[0]]
1173 self
.PrintStructureInfo(File
, Struct
)
1174 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1176 Value
= SkuInfo
.DefaultValue
1177 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1181 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', '{'))
1182 for Array
in ArrayList
:
1183 FileWrite(File
, '%s' % (Array
))
1185 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, Flag
+ ' ' + PcdTokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', Value
))
1188 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', '{'))
1189 for Array
in ArrayList
:
1190 FileWrite(File
, '%s' % (Array
))
1192 FileWrite(File
, ' %-*s : %6s %10s %10s = %s' % (self
.MaxLen
, ' ', TypeName
, '(' + Pcd
.DatumType
+ ')', '(' + SkuInfo
.SkuIdName
+ ')', Value
))
1194 OverrideValues
= Pcd
.OverrideValues
[Sku
]
1196 Keys
= OverrideValues
.keys()
1197 Struct
= OverrideValues
[Keys
[0]]
1198 self
.PrintStructureInfo(File
, Struct
)
1199 self
.PrintPcdDefault(File
, Pcd
, IsStructure
, DscMatch
, DscDefaultValue
, InfMatch
, InfDefaultValue
, DecMatch
, DecDefaultValue
)
1201 def PrintStructureInfo(self
, File
, Struct
):
1202 NewInfo
= collections
.OrderedDict()
1203 for Key
, Value
in Struct
.items():
1204 if Key
not in NewInfo
:
1205 NewInfo
[Key
] = Value
[0]
1208 NewInfo
[Key
] = Value
[0]
1210 for item
in NewInfo
:
1211 FileWrite(File
, ' %-*s = %s' % (self
.MaxLen
+ 4, '.' + item
, NewInfo
[item
]))
1213 def StrtoHex(self
, value
):
1215 value
= hex(int(value
))
1218 if value
.startswith("L\"") and value
.endswith("\""):
1220 for ch
in value
[2:-1]:
1221 valuelist
.append(hex(ord(ch
)))
1222 valuelist
.append('0x00')
1224 elif value
.startswith("\"") and value
.endswith("\""):
1225 return hex(ord(value
[1:-1]))
1226 elif value
.startswith("{") and value
.endswith("}"):
1228 if ',' not in value
:
1230 for ch
in value
[1:-1].split(','):
1232 if ch
.startswith('0x') or ch
.startswith('0X'):
1233 valuelist
.append(ch
)
1236 valuelist
.append(hex(int(ch
.strip())))
1244 # Reports platform and module Prediction information
1246 # This class reports the platform execution order prediction section and
1247 # module load fixed address prediction subsection in the build report file.
1249 class PredictionReport(object):
1251 # Constructor function for class PredictionReport
1253 # This constructor function generates PredictionReport object for the platform.
1255 # @param self: The object pointer
1256 # @param Wa Workspace context information
1258 def __init__(self
, Wa
):
1259 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
1260 self
._MapFileParsed
= False
1261 self
._EotToolInvoked
= False
1262 self
._FvDir
= Wa
.FvDir
1263 self
._EotDir
= Wa
.BuildDir
1264 self
._FfsEntryPoint
= {}
1266 self
._SourceList
= []
1267 self
.FixedMapDict
= {}
1272 # Collect all platform reference source files and GUID C Name
1274 for Pa
in Wa
.AutoGenObjectList
:
1275 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
1277 # BASE typed modules are EFI agnostic, so we need not scan
1278 # their source code to find PPI/Protocol produce or consume
1281 if Module
.ModuleType
== "BASE":
1284 # Add module referenced source files
1286 self
._SourceList
.append(str(Module
))
1288 for Source
in Module
.SourceFileList
:
1289 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1290 self
._SourceList
.append(" " + str(Source
))
1291 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1292 for IncludeFile
in IncludeList
.values():
1293 self
._SourceList
.append(" " + IncludeFile
)
1295 for Guid
in Module
.PpiList
:
1296 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1297 for Guid
in Module
.ProtocolList
:
1298 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1299 for Guid
in Module
.GuidList
:
1300 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1302 if Module
.Guid
and not Module
.IsLibrary
:
1303 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1304 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
1305 RealEntryPoint
= "_ModuleEntryPoint"
1307 RealEntryPoint
= EntryPoint
1308 if EntryPoint
== "_ModuleEntryPoint":
1309 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
1310 Match
= gGlueLibEntryPoint
.search(CCFlags
)
1312 EntryPoint
= Match
.group(1)
1314 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1318 # Collect platform firmware volume list as the input of EOT.
1322 for Fd
in Wa
.FdfProfile
.FdDict
:
1323 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1324 if FdRegion
.RegionType
!= "FV":
1326 for FvName
in FdRegion
.RegionDataList
:
1327 if FvName
in self
._FvList
:
1329 self
._FvList
.append(FvName
)
1330 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1331 for Section
in Ffs
.SectionList
:
1333 for FvSection
in Section
.SectionList
:
1334 if FvSection
.FvName
in self
._FvList
:
1336 self
._FvList
.append(FvSection
.FvName
)
1337 except AttributeError:
1342 # Parse platform fixed address map files
1344 # This function parses the platform final fixed address map file to get
1345 # the database of predicted fixed address for module image base, entry point
1348 # @param self: The object pointer
1350 def _ParseMapFile(self
):
1351 if self
._MapFileParsed
:
1353 self
._MapFileParsed
= True
1354 if os
.path
.isfile(self
._MapFileName
):
1356 FileContents
= open(self
._MapFileName
).read()
1357 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1358 AddressType
= Match
.group(1)
1359 BaseAddress
= Match
.group(2)
1360 EntryPoint
= Match
.group(3)
1361 Guid
= Match
.group(4).upper()
1362 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1363 List
.append((AddressType
, BaseAddress
, "*I"))
1364 List
.append((AddressType
, EntryPoint
, "*E"))
1366 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1369 # Invokes EOT tool to get the predicted the execution order.
1371 # This function invokes EOT tool to calculate the predicted dispatch order
1373 # @param self: The object pointer
1375 def _InvokeEotTool(self
):
1376 if self
._EotToolInvoked
:
1379 self
._EotToolInvoked
= True
1381 for FvName
in self
._FvList
:
1382 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1383 if os
.path
.isfile(FvFile
):
1384 FvFileList
.append(FvFile
)
1386 if len(FvFileList
) == 0:
1389 # Write source file list and GUID file list to an intermediate file
1390 # as the input for EOT tool and dispatch List as the output file
1393 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1394 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1395 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1397 TempFile
= open(SourceList
, "w+")
1398 for Item
in self
._SourceList
:
1399 FileWrite(TempFile
, Item
)
1401 TempFile
= open(GuidList
, "w+")
1402 for Key
in self
._GuidMap
:
1403 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1407 from Eot
.Eot
import Eot
1410 # Invoke EOT tool and echo its runtime performance
1412 EotStartTime
= time
.time()
1413 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1414 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1415 EotEndTime
= time
.time()
1416 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1417 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1420 # Parse the output of EOT tool
1422 for Line
in open(DispatchList
):
1423 if len(Line
.split()) < 4:
1425 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1426 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1427 if len(Symbol
) > self
.MaxLen
:
1428 self
.MaxLen
= len(Symbol
)
1429 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1431 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1432 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1436 # Generate platform execution order report
1438 # This function generates the predicted module execution order.
1440 # @param self The object pointer
1441 # @param File The file object for report
1443 def _GenerateExecutionOrderReport(self
, File
):
1444 self
._InvokeEotTool
()
1445 if len(self
.ItemList
) == 0:
1447 FileWrite(File
, gSectionStart
)
1448 FileWrite(File
, "Execution Order Prediction")
1449 FileWrite(File
, "*P PEI phase")
1450 FileWrite(File
, "*D DXE phase")
1451 FileWrite(File
, "*E Module INF entry point name")
1452 FileWrite(File
, "*N Module notification function name")
1454 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1455 FileWrite(File
, gSectionSep
)
1456 for Item
in self
.ItemList
:
1457 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1459 FileWrite(File
, gSectionStart
)
1462 # Generate Fixed Address report.
1464 # This function generate the predicted fixed address report for a module
1465 # specified by Guid.
1467 # @param self The object pointer
1468 # @param File The file object for report
1469 # @param Guid The module Guid value.
1470 # @param NotifyList The list of all notify function in a module
1472 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1473 self
._ParseMapFile
()
1474 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1475 if not FixedAddressList
:
1478 FileWrite(File
, gSubSectionStart
)
1479 FileWrite(File
, "Fixed Address Prediction")
1480 FileWrite(File
, "*I Image Loading Address")
1481 FileWrite(File
, "*E Entry Point Address")
1482 FileWrite(File
, "*N Notification Function Address")
1483 FileWrite(File
, "*F Flash Address")
1484 FileWrite(File
, "*M Memory Address")
1485 FileWrite(File
, "*S SMM RAM Offset")
1486 FileWrite(File
, "TOM Top of Memory")
1488 FileWrite(File
, "Type Address Name")
1489 FileWrite(File
, gSubSectionSep
)
1490 for Item
in FixedAddressList
:
1495 Name
= "(Image Base)"
1496 elif Symbol
== "*E":
1497 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1498 elif Symbol
in NotifyList
:
1506 elif "Memory" in Type
:
1512 Value
= "TOM" + Value
1514 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1517 # Generate report for the prediction part
1519 # This function generate the predicted fixed address report for a module or
1520 # predicted module execution order for a platform.
1521 # If the input Guid is None, then, it generates the predicted module execution order;
1522 # otherwise it generated the module fixed loading address for the module specified by
1525 # @param self The object pointer
1526 # @param File The file object for report
1527 # @param Guid The module Guid value.
1529 def GenerateReport(self
, File
, Guid
):
1531 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1533 self
._GenerateExecutionOrderReport
(File
)
1536 # Reports FD region information
1538 # This class reports the FD subsection in the build report file.
1539 # It collects region information of platform flash device.
1540 # If the region is a firmware volume, it lists the set of modules
1541 # and its space information; otherwise, it only lists its region name,
1542 # base address and size in its sub-section header.
1543 # If there are nesting FVs, the nested FVs will list immediate after
1544 # this FD region subsection
1546 class FdRegionReport(object):
1548 # Discover all the nested FV name list.
1550 # This is an internal worker function to discover the all the nested FV information
1551 # in the parent firmware volume. It uses deep first search algorithm recursively to
1552 # find all the FV list name and append them to the list.
1554 # @param self The object pointer
1555 # @param FvName The name of current firmware file system
1556 # @param Wa Workspace context information
1558 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1559 FvDictKey
=FvName
.upper()
1560 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1561 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1562 for Section
in Ffs
.SectionList
:
1564 for FvSection
in Section
.SectionList
:
1565 if FvSection
.FvName
in self
.FvList
:
1567 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1568 self
.FvList
.append(FvSection
.FvName
)
1569 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1570 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1571 except AttributeError:
1575 # Constructor function for class FdRegionReport
1577 # This constructor function generates FdRegionReport object for a specified FdRegion.
1578 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1579 # volume list. This function also collects GUID map in order to dump module identification
1580 # in the final report.
1582 # @param self: The object pointer
1583 # @param FdRegion The current FdRegion object
1584 # @param Wa Workspace context information
1586 def __init__(self
, FdRegion
, Wa
):
1587 self
.Type
= FdRegion
.RegionType
1588 self
.BaseAddress
= FdRegion
.Offset
1589 self
.Size
= FdRegion
.Size
1593 self
._FvDir
= Wa
.FvDir
1596 # If the input FdRegion is not a firmware volume,
1599 if self
.Type
!= "FV":
1603 # Find all nested FVs in the FdRegion
1605 for FvName
in FdRegion
.RegionDataList
:
1606 if FvName
in self
.FvList
:
1608 self
.FvList
.append(FvName
)
1609 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1610 self
._DiscoverNestedFvList
(FvName
, Wa
)
1614 # Collect PCDs declared in DEC files.
1616 for Pa
in Wa
.AutoGenObjectList
:
1617 for Package
in Pa
.PackageList
:
1618 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1619 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1620 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1622 # Collect PCDs defined in DSC file
1624 for Pa
in Wa
.AutoGenObjectList
:
1625 for (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
:
1626 DscDefaultValue
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1627 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1630 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1632 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1633 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1635 # Add ACPI table storage file
1637 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1639 for Pa
in Wa
.AutoGenObjectList
:
1640 for ModuleKey
in Pa
.Platform
.Modules
:
1641 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1642 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1643 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1646 # Collect the GUID map in the FV firmware volume
1648 for FvName
in self
.FvList
:
1649 FvDictKey
=FvName
.upper()
1650 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1651 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1654 # collect GUID map for binary EFI file in FDF file.
1656 Guid
= Ffs
.NameGuid
.upper()
1657 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1659 PcdTokenspace
= Match
.group(1)
1660 PcdToken
= Match
.group(2)
1661 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1662 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1663 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1664 for Section
in Ffs
.SectionList
:
1666 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1667 self
._GuidsDb
[Guid
] = ModuleSectFile
1668 except AttributeError:
1670 except AttributeError:
1675 # Internal worker function to generate report for the FD region
1677 # This internal worker function to generate report for the FD region.
1678 # It the type is firmware volume, it lists offset and module identification.
1680 # @param self The object pointer
1681 # @param File The file object for report
1682 # @param Title The title for the FD subsection
1683 # @param BaseAddress The base address for the FD region
1684 # @param Size The size of the FD region
1685 # @param FvName The FV name if the FD region is a firmware volume
1687 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1688 FileWrite(File
, gSubSectionStart
)
1689 FileWrite(File
, Title
)
1690 FileWrite(File
, "Type: %s" % Type
)
1691 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1693 if self
.Type
== "FV":
1697 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv.txt")
1700 # Collect size info in the firmware volume.
1702 FvReport
= open(FvReportFileName
).read()
1703 Match
= gFvTotalSizePattern
.search(FvReport
)
1705 FvTotalSize
= int(Match
.group(1), 16)
1706 Match
= gFvTakenSizePattern
.search(FvReport
)
1708 FvTakenSize
= int(Match
.group(1), 16)
1709 FvFreeSize
= FvTotalSize
- FvTakenSize
1711 # Write size information to the report file.
1713 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1714 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1715 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1716 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1717 FileWrite(File
, "Offset Module")
1718 FileWrite(File
, gSubSectionSep
)
1720 # Write module offset and module identification to the report file.
1723 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1724 Guid
= Match
.group(2).upper()
1725 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1726 OffsetList
= OffsetInfo
.keys()
1728 for Offset
in OffsetList
:
1729 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1731 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1733 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1734 FileWrite(File
, gSubSectionEnd
)
1737 # Generate report for the FD region
1739 # This function generates report for the FD region.
1741 # @param self The object pointer
1742 # @param File The file object for report
1744 def GenerateReport(self
, File
):
1745 if (len(self
.FvList
) > 0):
1746 for FvItem
in self
.FvList
:
1747 Info
= self
.FvInfo
[FvItem
]
1748 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1750 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1753 # Reports FD information
1755 # This class reports the FD section in the build report file.
1756 # It collects flash device information for a platform.
1758 class FdReport(object):
1760 # Constructor function for class FdReport
1762 # This constructor function generates FdReport object for a specified
1765 # @param self The object pointer
1766 # @param Fd The current Firmware device object
1767 # @param Wa Workspace context information
1769 def __init__(self
, Fd
, Wa
):
1770 self
.FdName
= Fd
.FdUiName
1771 self
.BaseAddress
= Fd
.BaseAddress
1773 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1774 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, "FV")
1775 self
.VpdFilePath
= os
.path
.join(self
.FvPath
, "%s.map" % Wa
.Platform
.VpdToolGuid
)
1776 self
.VPDBaseAddress
= 0
1778 self
.VPDInfoList
= []
1779 for index
, FdRegion
in enumerate(Fd
.RegionList
):
1780 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
1781 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
1782 self
.VPDSize
= self
.FdRegionList
[index
].Size
1785 if os
.path
.isfile(self
.VpdFilePath
):
1786 fd
= open(self
.VpdFilePath
, "r")
1787 Lines
= fd
.readlines()
1790 if len(Line
) == 0 or Line
.startswith("#"):
1793 PcdName
, SkuId
, Offset
, Size
, Value
= Line
.split("#")[0].split("|")
1794 PcdName
, SkuId
, Offset
, Size
, Value
= PcdName
.strip(), SkuId
.strip(), Offset
.strip(), Size
.strip(), Value
.strip()
1795 if Offset
.lower().startswith('0x'):
1796 Offset
= '0x%08X' % (int(Offset
, 16) + self
.VPDBaseAddress
)
1798 Offset
= '0x%08X' % (int(Offset
, 10) + self
.VPDBaseAddress
)
1799 self
.VPDInfoList
.append("%s | %s | %s | %s | %s" % (PcdName
, SkuId
, Offset
, Size
, Value
))
1801 EdkLogger
.error("BuildReport", CODE_ERROR
, "Fail to parse VPD information file %s" % self
.VpdFilePath
)
1805 # Generate report for the firmware device.
1807 # This function generates report for the firmware device.
1809 # @param self The object pointer
1810 # @param File The file object for report
1812 def GenerateReport(self
, File
):
1813 FileWrite(File
, gSectionStart
)
1814 FileWrite(File
, "Firmware Device (FD)")
1815 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1816 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1817 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1818 if len(self
.FdRegionList
) > 0:
1819 FileWrite(File
, gSectionSep
)
1820 for FdRegionItem
in self
.FdRegionList
:
1821 FdRegionItem
.GenerateReport(File
)
1823 if len(self
.VPDInfoList
) > 0:
1824 FileWrite(File
, gSubSectionStart
)
1825 FileWrite(File
, "FD VPD Region")
1826 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
1827 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
1828 FileWrite(File
, gSubSectionSep
)
1829 for item
in self
.VPDInfoList
:
1830 ValueList
= item
.split('|')
1831 Value
= ValueList
[-1].strip()
1832 IsByteArray
, ArrayList
= ByteArrayForamt(Value
)
1834 ValueList
[-1] = ' {'
1835 FileWrite(File
, '|'.join(ValueList
))
1836 for Array
in ArrayList
:
1837 FileWrite(File
, '%s' % (Array
))
1839 FileWrite(File
, item
)
1840 FileWrite(File
, gSubSectionEnd
)
1841 FileWrite(File
, gSectionEnd
)
1846 # Reports platform information
1848 # This class reports the whole platform information
1850 class PlatformReport(object):
1852 # Constructor function for class PlatformReport
1854 # This constructor function generates PlatformReport object a platform build.
1855 # It generates report for platform summary, flash, global PCDs and detailed
1856 # module information for modules involved in platform build.
1858 # @param self The object pointer
1859 # @param Wa Workspace context information
1860 # @param MaList The list of modules in the platform build
1862 def __init__(self
, Wa
, MaList
, ReportType
):
1863 self
._WorkspaceDir
= Wa
.WorkspaceDir
1864 self
.PlatformName
= Wa
.Name
1865 self
.PlatformDscPath
= Wa
.Platform
1866 self
.Architectures
= " ".join(Wa
.ArchList
)
1867 self
.ToolChain
= Wa
.ToolChain
1868 self
.Target
= Wa
.BuildTarget
1869 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1870 self
.BuildEnvironment
= platform
.platform()
1872 self
.PcdReport
= None
1873 if "PCD" in ReportType
:
1874 self
.PcdReport
= PcdReport(Wa
)
1876 self
.FdReportList
= []
1877 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1878 for Fd
in Wa
.FdfProfile
.FdDict
:
1879 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1881 self
.PredictionReport
= None
1882 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1883 self
.PredictionReport
= PredictionReport(Wa
)
1885 self
.DepexParser
= None
1886 if "DEPEX" in ReportType
:
1887 self
.DepexParser
= DepexParser(Wa
)
1889 self
.ModuleReportList
= []
1891 self
._IsModuleBuild
= True
1893 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1895 self
._IsModuleBuild
= False
1896 for Pa
in Wa
.AutoGenObjectList
:
1897 ModuleAutoGenList
= []
1898 for ModuleKey
in Pa
.Platform
.Modules
:
1899 ModuleAutoGenList
.append(Pa
.Platform
.Modules
[ModuleKey
].M
)
1900 if GlobalData
.gFdfParser
!= None:
1901 if Pa
.Arch
in GlobalData
.gFdfParser
.Profile
.InfDict
:
1902 INFList
= GlobalData
.gFdfParser
.Profile
.InfDict
[Pa
.Arch
]
1903 for InfName
in INFList
:
1904 InfClass
= PathClass(NormPath(InfName
), Wa
.WorkspaceDir
, Pa
.Arch
)
1905 Ma
= ModuleAutoGen(Wa
, InfClass
, Pa
.BuildTarget
, Pa
.ToolChain
, Pa
.Arch
, Wa
.MetaFile
)
1908 if Ma
not in ModuleAutoGenList
:
1909 ModuleAutoGenList
.append(Ma
)
1910 for MGen
in ModuleAutoGenList
:
1911 self
.ModuleReportList
.append(ModuleReport(MGen
, ReportType
))
1916 # Generate report for the whole platform.
1918 # This function generates report for platform information.
1919 # It comprises of platform summary, global PCD, flash and
1920 # module list sections.
1922 # @param self The object pointer
1923 # @param File The file object for report
1924 # @param BuildDuration The total time to build the modules
1925 # @param AutoGenTime The total time of AutoGen Phase
1926 # @param MakeTime The total time of Make Phase
1927 # @param GenFdsTime The total time of GenFds Phase
1928 # @param ReportType The kind of report items in the final report file
1930 def GenerateReport(self
, File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, ReportType
):
1931 FileWrite(File
, "Platform Summary")
1932 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1933 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1934 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1935 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1936 FileWrite(File
, "Target: %s" % self
.Target
)
1937 if GlobalData
.gSkuids
:
1938 FileWrite(File
, "SKUID: %s" % " ".join(GlobalData
.gSkuids
))
1939 if GlobalData
.gDefaultStores
:
1940 FileWrite(File
, "DefaultStore: %s" % " ".join(GlobalData
.gDefaultStores
))
1941 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1942 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1943 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1945 FileWrite(File
, "AutoGen Duration: %s" % AutoGenTime
)
1947 FileWrite(File
, "Make Duration: %s" % MakeTime
)
1949 FileWrite(File
, "GenFds Duration: %s" % GenFdsTime
)
1950 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1952 if GlobalData
.MixedPcd
:
1953 FileWrite(File
, gSectionStart
)
1954 FileWrite(File
, "The following PCDs use different access methods:")
1955 FileWrite(File
, gSectionSep
)
1956 for PcdItem
in GlobalData
.MixedPcd
:
1957 FileWrite(File
, "%s.%s" % (str(PcdItem
[1]), str(PcdItem
[0])))
1958 FileWrite(File
, gSectionEnd
)
1960 if not self
._IsModuleBuild
:
1961 if "PCD" in ReportType
:
1962 self
.PcdReport
.GenerateReport(File
, None)
1964 if "FLASH" in ReportType
:
1965 for FdReportListItem
in self
.FdReportList
:
1966 FdReportListItem
.GenerateReport(File
)
1968 for ModuleReportItem
in self
.ModuleReportList
:
1969 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
1971 if not self
._IsModuleBuild
:
1972 if "EXECUTION_ORDER" in ReportType
:
1973 self
.PredictionReport
.GenerateReport(File
, None)
1975 ## BuildReport class
1977 # This base class contain the routines to collect data and then
1978 # applies certain format to the output report
1980 class BuildReport(object):
1982 # Constructor function for class BuildReport
1984 # This constructor function generates BuildReport object a platform build.
1985 # It generates report for platform summary, flash, global PCDs and detailed
1986 # module information for modules involved in platform build.
1988 # @param self The object pointer
1989 # @param ReportFile The file name to save report file
1990 # @param ReportType The kind of report items in the final report file
1992 def __init__(self
, ReportFile
, ReportType
):
1993 self
.ReportFile
= ReportFile
1995 self
.ReportList
= []
1996 self
.ReportType
= []
1998 for ReportTypeItem
in ReportType
:
1999 if ReportTypeItem
not in self
.ReportType
:
2000 self
.ReportType
.append(ReportTypeItem
)
2002 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2004 # Adds platform report to the list
2006 # This function adds a platform report to the final report list.
2008 # @param self The object pointer
2009 # @param Wa Workspace context information
2010 # @param MaList The list of modules in the platform build
2012 def AddPlatformReport(self
, Wa
, MaList
=None):
2014 self
.ReportList
.append((Wa
, MaList
))
2017 # Generates the final report.
2019 # This function generates platform build report. It invokes GenerateReport()
2020 # method for every platform report in the list.
2022 # @param self The object pointer
2023 # @param BuildDuration The total time to build the modules
2024 # @param AutoGenTime The total time of AutoGen phase
2025 # @param MakeTime The total time of Make phase
2026 # @param GenFdsTime The total time of GenFds phase
2028 def GenerateReport(self
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
):
2032 for (Wa
, MaList
) in self
.ReportList
:
2033 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, AutoGenTime
, MakeTime
, GenFdsTime
, self
.ReportType
)
2034 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
2035 SaveFileOnChange(self
.ReportFile
, Content
, True)
2036 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
2038 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
2040 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
2041 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
2044 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2045 if __name__
== '__main__':