]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/BuildReport.py
BaseTools: Update incorrect variable name 'DataPile'
[mirror_edk2.git] / BaseTools / Source / Python / build / BuildReport.py
1 ## @file
2 # Routines for generating build report.
3 #
4 # This module contains the functionality to generate build report after
5 # build all target completes successfully.
6 #
7 # Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
9 #
10
11 ## Import Modules
12 #
13 import Common.LongFilePathOs as os
14 import re
15 import platform
16 import textwrap
17 import traceback
18 import sys
19 import time
20 import struct
21 import hashlib
22 import subprocess
23 import threading
24 from datetime import datetime
25 from io import BytesIO
26 from Common import EdkLogger
27 from Common.Misc import SaveFileOnChange
28 from Common.Misc import GuidStructureByteArrayToGuidString
29 from Common.Misc import GuidStructureStringToGuidString
30 from Common.BuildToolError import FILE_WRITE_FAILURE
31 from Common.BuildToolError import CODE_ERROR
32 from Common.BuildToolError import COMMAND_FAILURE
33 from Common.BuildToolError import FORMAT_INVALID
34 from Common.LongFilePathSupport import OpenLongFilePath as open
35 from Common.MultipleWorkspace import MultipleWorkspace as mws
36 import Common.GlobalData as GlobalData
37 from AutoGen.ModuleAutoGen import ModuleAutoGen
38 from Common.Misc import PathClass
39 from Common.StringUtils import NormPath
40 from Common.DataType import *
41 import collections
42 from Common.Expression import *
43 from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID
44
45 ## Pattern to extract contents in EDK DXS files
46 gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)
47
48 ## Pattern to find total FV total size, occupied size in flash report intermediate file
49 gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
50 gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
51
52 ## Pattern to find module size and time stamp in module summary report intermediate file
53 gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")
54 gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")
55
56 ## Pattern to find GUID value in flash description files
57 gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")
58
59 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
60 gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
61
62 ## Pattern to find module base address and entry point in fixed flash map file
63 gModulePattern = r"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
64 gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
65
66 ## Pattern to find all module referenced header files in source files
67 gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')
68 gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
69
70 ## Pattern to find the entry point for EDK module using EDKII Glue library
71 gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
72
73 ## Tags for MaxLength of line in report
74 gLineMaxLength = 120
75
76 ## Tags for end of line in report
77 gEndOfLine = "\r\n"
78
79 ## Tags for section start, end and separator
80 gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<"
81 gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n"
82 gSectionSep = "=" * gLineMaxLength
83
84 ## Tags for subsection start, end and separator
85 gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<"
86 gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">"
87 gSubSectionSep = "-" * gLineMaxLength
88
89
90 ## The look up table to map PCD type to pair of report display type and DEC type
91 gPcdTypeMap = {
92 TAB_PCDS_FIXED_AT_BUILD : ('FIXED', TAB_PCDS_FIXED_AT_BUILD),
93 TAB_PCDS_PATCHABLE_IN_MODULE: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE),
94 TAB_PCDS_FEATURE_FLAG : ('FLAG', TAB_PCDS_FEATURE_FLAG),
95 TAB_PCDS_DYNAMIC : ('DYN', TAB_PCDS_DYNAMIC),
96 TAB_PCDS_DYNAMIC_HII : ('DYNHII', TAB_PCDS_DYNAMIC),
97 TAB_PCDS_DYNAMIC_VPD : ('DYNVPD', TAB_PCDS_DYNAMIC),
98 TAB_PCDS_DYNAMIC_EX : ('DEX', TAB_PCDS_DYNAMIC_EX),
99 TAB_PCDS_DYNAMIC_EX_HII : ('DEXHII', TAB_PCDS_DYNAMIC_EX),
100 TAB_PCDS_DYNAMIC_EX_VPD : ('DEXVPD', TAB_PCDS_DYNAMIC_EX),
101 }
102
103 ## The look up table to map module type to driver type
104 gDriverTypeMap = {
105 SUP_MODULE_SEC : '0x3 (SECURITY_CORE)',
106 SUP_MODULE_PEI_CORE : '0x4 (PEI_CORE)',
107 SUP_MODULE_PEIM : '0x6 (PEIM)',
108 SUP_MODULE_DXE_CORE : '0x5 (DXE_CORE)',
109 SUP_MODULE_DXE_DRIVER : '0x7 (DRIVER)',
110 SUP_MODULE_DXE_SAL_DRIVER : '0x7 (DRIVER)',
111 SUP_MODULE_DXE_SMM_DRIVER : '0x7 (DRIVER)',
112 SUP_MODULE_DXE_RUNTIME_DRIVER: '0x7 (DRIVER)',
113 SUP_MODULE_UEFI_DRIVER : '0x7 (DRIVER)',
114 SUP_MODULE_UEFI_APPLICATION : '0x9 (APPLICATION)',
115 SUP_MODULE_SMM_CORE : '0xD (SMM_CORE)',
116 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
117 SUP_MODULE_MM_STANDALONE : '0xE (MM_STANDALONE)',
118 SUP_MODULE_MM_CORE_STANDALONE : '0xF (MM_CORE_STANDALONE)'
119 }
120
121 ## The look up table of the supported opcode in the dependency expression binaries
122 gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
123
124 ## Save VPD Pcd
125 VPDPcdList = []
126
127 ##
128 # Writes a string to the file object.
129 #
130 # This function writes a string to the file object and a new line is appended
131 # afterwards. It may optionally wraps the string for better readability.
132 #
133 # @File The file object to write
134 # @String The string to be written to the file
135 # @Wrapper Indicates whether to wrap the string
136 #
137 def FileWrite(File, String, Wrapper=False):
138 if Wrapper:
139 String = textwrap.fill(String, 120)
140 File.append(String + gEndOfLine)
141
142 def ByteArrayForamt(Value):
143 IsByteArray = False
144 SplitNum = 16
145 ArrayList = []
146 if Value.startswith('{') and Value.endswith('}') and not Value.startswith("{CODE("):
147 Value = Value[1:-1]
148 ValueList = Value.split(',')
149 if len(ValueList) >= SplitNum:
150 IsByteArray = True
151 if IsByteArray:
152 if ValueList:
153 Len = len(ValueList)/SplitNum
154 for i, element in enumerate(ValueList):
155 ValueList[i] = '0x%02X' % int(element.strip(), 16)
156 if Len:
157 Id = 0
158 while (Id <= Len):
159 End = min(SplitNum*(Id+1), len(ValueList))
160 Str = ','.join(ValueList[SplitNum*Id : End])
161 if End == len(ValueList):
162 Str += '}'
163 ArrayList.append(Str)
164 break
165 else:
166 Str += ','
167 ArrayList.append(Str)
168 Id += 1
169 else:
170 ArrayList = [Value + '}']
171 return IsByteArray, ArrayList
172
173 ##
174 # Find all the header file that the module source directly includes.
175 #
176 # This function scans source code to find all header files the module may
177 # include. This is not accurate but very effective to find all the header
178 # file the module might include with #include statement.
179 #
180 # @Source The source file name
181 # @IncludePathList The list of include path to find the source file.
182 # @IncludeFiles The dictionary of current found include files.
183 #
184 def FindIncludeFiles(Source, IncludePathList, IncludeFiles):
185 FileContents = open(Source).read()
186 #
187 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
188 #
189 for Match in gIncludePattern.finditer(FileContents):
190 FileName = Match.group(1).strip()
191 for Dir in [os.path.dirname(Source)] + IncludePathList:
192 FullFileName = os.path.normpath(os.path.join(Dir, FileName))
193 if os.path.exists(FullFileName):
194 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
195 break
196
197 #
198 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
199 #
200 for Match in gIncludePattern2.finditer(FileContents):
201 Key = Match.group(2)
202 Type = Match.group(1)
203 if "ARCH_PROTOCOL" in Type:
204 FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
205 elif "PROTOCOL" in Type:
206 FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
207 elif "PPI" in Type:
208 FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}
209 elif TAB_GUID in Type:
210 FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}
211 else:
212 continue
213 for Dir in IncludePathList:
214 FullFileName = os.path.normpath(os.path.join(Dir, FileName))
215 if os.path.exists(FullFileName):
216 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
217 break
218
219 ## Split each lines in file
220 #
221 # This method is used to split the lines in file to make the length of each line
222 # less than MaxLength.
223 #
224 # @param Content The content of file
225 # @param MaxLength The Max Length of the line
226 #
227 def FileLinesSplit(Content=None, MaxLength=None):
228 ContentList = Content.split(TAB_LINE_BREAK)
229 NewContent = ''
230 NewContentList = []
231 for Line in ContentList:
232 while len(Line.rstrip()) > MaxLength:
233 LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)
234 LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)
235 LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)
236 if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:
237 LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)
238 else:
239 LineBreakIndex = MaxLength
240 NewContentList.append(Line[:LineBreakIndex])
241 Line = Line[LineBreakIndex:]
242 if Line:
243 NewContentList.append(Line)
244 for NewLine in NewContentList:
245 NewContent += NewLine + TAB_LINE_BREAK
246
247 NewContent = NewContent.replace(gEndOfLine, TAB_LINE_BREAK).replace('\r\r\n', gEndOfLine)
248 return NewContent
249
250
251
252 ##
253 # Parse binary dependency expression section
254 #
255 # This utility class parses the dependency expression section and translate the readable
256 # GUID name and value.
257 #
258 class DepexParser(object):
259 ##
260 # Constructor function for class DepexParser
261 #
262 # This constructor function collect GUID values so that the readable
263 # GUID name can be translated.
264 #
265 # @param self The object pointer
266 # @param Wa Workspace context information
267 #
268 def __init__(self, Wa):
269 self._GuidDb = {}
270 for Pa in Wa.AutoGenObjectList:
271 for Package in Pa.PackageList:
272 for Protocol in Package.Protocols:
273 GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])
274 self._GuidDb[GuidValue.upper()] = Protocol
275 for Ppi in Package.Ppis:
276 GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])
277 self._GuidDb[GuidValue.upper()] = Ppi
278 for Guid in Package.Guids:
279 GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])
280 self._GuidDb[GuidValue.upper()] = Guid
281 for Ma in Pa.ModuleAutoGenList:
282 for Pcd in Ma.FixedVoidTypePcds:
283 PcdValue = Ma.FixedVoidTypePcds[Pcd]
284 if len(PcdValue.split(',')) == 16:
285 GuidValue = GuidStructureByteArrayToGuidString(PcdValue)
286 self._GuidDb[GuidValue.upper()] = Pcd
287 ##
288 # Parse the binary dependency expression files.
289 #
290 # This function parses the binary dependency expression file and translate it
291 # to the instruction list.
292 #
293 # @param self The object pointer
294 # @param DepexFileName The file name of binary dependency expression file.
295 #
296 def ParseDepexFile(self, DepexFileName):
297 DepexFile = open(DepexFileName, "rb")
298 DepexStatement = []
299 OpCode = DepexFile.read(1)
300 while OpCode:
301 Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]
302 if Statement in ["BEFORE", "AFTER", "PUSH"]:
303 GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
304 struct.unpack(PACK_PATTERN_GUID, DepexFile.read(16))
305 GuidString = self._GuidDb.get(GuidValue, GuidValue)
306 Statement = "%s %s" % (Statement, GuidString)
307 DepexStatement.append(Statement)
308 OpCode = DepexFile.read(1)
309
310 return DepexStatement
311
312 ##
313 # Reports library information
314 #
315 # This class reports the module library subsection in the build report file.
316 #
317 class LibraryReport(object):
318 ##
319 # Constructor function for class LibraryReport
320 #
321 # This constructor function generates LibraryReport object for
322 # a module.
323 #
324 # @param self The object pointer
325 # @param M Module context information
326 #
327 def __init__(self, M):
328 self.LibraryList = []
329
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
339 break
340 self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList, LibTime))
341
342 ##
343 # Generate report for module library information
344 #
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.
348 #
349 # @param self The object pointer
350 # @param File The file object for report
351 #
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)
360
361 LibClass = LibraryItem[1]
362 EdkIILibInfo = ""
363 LibConstructor = " ".join(LibraryItem[2])
364 if LibConstructor:
365 EdkIILibInfo += " C = " + LibConstructor
366 LibDestructor = " ".join(LibraryItem[3])
367 if LibDestructor:
368 EdkIILibInfo += " D = " + LibDestructor
369 LibDepex = " ".join(LibraryItem[4])
370 if LibDepex:
371 EdkIILibInfo += " Depex = " + LibDepex
372 if LibraryItem[5]:
373 EdkIILibInfo += " Time = " + LibraryItem[5]
374 if EdkIILibInfo:
375 FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))
376 else:
377 FileWrite(File, "{%s}" % LibClass)
378
379 FileWrite(File, gSubSectionEnd)
380
381 ##
382 # Reports dependency expression information
383 #
384 # This class reports the module dependency expression subsection in the build report file.
385 #
386 class DepexReport(object):
387 ##
388 # Constructor function for class DepexReport
389 #
390 # This constructor function generates DepexReport object for
391 # a module. If the module source contains the DXS file (usually EDK
392 # style module), it uses the dependency in DXS file; otherwise,
393 # it uses the dependency expression from its own INF [Depex] section
394 # and then merges with the ones from its dependent library INF.
395 #
396 # @param self The object pointer
397 # @param M Module context information
398 #
399 def __init__(self, M):
400 self.Depex = ""
401 self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex")
402 ModuleType = M.ModuleType
403 if not ModuleType:
404 ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")
405
406 if ModuleType in [SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_DXE_CORE, SUP_MODULE_SMM_CORE, SUP_MODULE_MM_CORE_STANDALONE, SUP_MODULE_UEFI_APPLICATION]:
407 return
408
409 for Source in M.SourceFileList:
410 if os.path.splitext(Source.Path)[1].lower() == ".dxs":
411 Match = gDxsDependencyPattern.search(open(Source.Path).read())
412 if Match:
413 self.Depex = Match.group(1).strip()
414 self.Source = "DXS"
415 break
416 else:
417 self.Depex = M.DepexExpressionDict.get(M.ModuleType, "")
418 self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])
419 if not self.ModuleDepex:
420 self.ModuleDepex = "(None)"
421
422 LibDepexList = []
423 for Lib in M.DependentLibraryList:
424 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()
425 if LibDepex != "":
426 LibDepexList.append("(" + LibDepex + ")")
427 self.LibraryDepex = " AND ".join(LibDepexList)
428 if not self.LibraryDepex:
429 self.LibraryDepex = "(None)"
430 self.Source = "INF"
431
432 ##
433 # Generate report for module dependency expression information
434 #
435 # This function generates report for the module dependency expression.
436 #
437 # @param self The object pointer
438 # @param File The file object for report
439 # @param GlobalDepexParser The platform global Dependency expression parser object
440 #
441 def GenerateReport(self, File, GlobalDepexParser):
442 if not self.Depex:
443 return
444 FileWrite(File, gSubSectionStart)
445 if os.path.isfile(self._DepexFileName):
446 try:
447 DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)
448 FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")
449 for DepexStatement in DepexStatements:
450 FileWrite(File, " %s" % DepexStatement)
451 FileWrite(File, gSubSectionSep)
452 except:
453 EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)
454
455 FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)
456
457 if self.Source == "INF":
458 FileWrite(File, self.Depex, True)
459 FileWrite(File, gSubSectionSep)
460 FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)
461 FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)
462 else:
463 FileWrite(File, self.Depex)
464 FileWrite(File, gSubSectionEnd)
465
466 ##
467 # Reports dependency expression information
468 #
469 # This class reports the module build flags subsection in the build report file.
470 #
471 class BuildFlagsReport(object):
472 ##
473 # Constructor function for class BuildFlagsReport
474 #
475 # This constructor function generates BuildFlagsReport object for
476 # a module. It reports the build tool chain tag and all relevant
477 # build flags to build the module.
478 #
479 # @param self The object pointer
480 # @param M Module context information
481 #
482 def __init__(self, M):
483 BuildOptions = {}
484 #
485 # Add build flags according to source file extension so that
486 # irrelevant ones can be filtered out.
487 #
488 for Source in M.SourceFileList:
489 Ext = os.path.splitext(Source.File)[1].lower()
490 if Ext in [".c", ".cc", ".cpp"]:
491 BuildOptions["CC"] = 1
492 elif Ext in [".s", ".asm"]:
493 BuildOptions["PP"] = 1
494 BuildOptions["ASM"] = 1
495 elif Ext in [".vfr"]:
496 BuildOptions["VFRPP"] = 1
497 BuildOptions["VFR"] = 1
498 elif Ext in [".dxs"]:
499 BuildOptions["APP"] = 1
500 BuildOptions["CC"] = 1
501 elif Ext in [".asl"]:
502 BuildOptions["ASLPP"] = 1
503 BuildOptions["ASL"] = 1
504 elif Ext in [".aslc"]:
505 BuildOptions["ASLCC"] = 1
506 BuildOptions["ASLDLINK"] = 1
507 BuildOptions["CC"] = 1
508 elif Ext in [".asm16"]:
509 BuildOptions["ASMLINK"] = 1
510 BuildOptions["SLINK"] = 1
511 BuildOptions["DLINK"] = 1
512
513 #
514 # Save module build flags.
515 #
516 self.ToolChainTag = M.ToolChain
517 self.BuildFlags = {}
518 for Tool in BuildOptions:
519 self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")
520
521 ##
522 # Generate report for module build flags information
523 #
524 # This function generates report for the module build flags expression.
525 #
526 # @param self The object pointer
527 # @param File The file object for report
528 #
529 def GenerateReport(self, File):
530 FileWrite(File, gSubSectionStart)
531 FileWrite(File, "Build Flags")
532 FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)
533 for Tool in self.BuildFlags:
534 FileWrite(File, gSubSectionSep)
535 FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)
536
537 FileWrite(File, gSubSectionEnd)
538
539
540 ##
541 # Reports individual module information
542 #
543 # This class reports the module section in the build report file.
544 # It comprises of module summary, module PCD, library, dependency expression,
545 # build flags sections.
546 #
547 class ModuleReport(object):
548 ##
549 # Constructor function for class ModuleReport
550 #
551 # This constructor function generates ModuleReport object for
552 # a separate module in a platform build.
553 #
554 # @param self The object pointer
555 # @param M Module context information
556 # @param ReportType The kind of report items in the final report file
557 #
558 def __init__(self, M, ReportType):
559 self.ModuleName = M.Module.BaseName
560 self.ModuleInfPath = M.MetaFile.File
561 self.ModuleArch = M.Arch
562 self.FileGuid = M.Guid
563 self.Size = 0
564 self.BuildTimeStamp = None
565 self.Hash = 0
566 self.DriverType = ""
567 if not M.IsLibrary:
568 ModuleType = M.ModuleType
569 if not ModuleType:
570 ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")
571 #
572 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
573 #
574 if ModuleType == SUP_MODULE_DXE_SMM_DRIVER:
575 PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")
576 if int(PiSpec, 0) >= 0x0001000A:
577 ModuleType = "SMM_DRIVER"
578 self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")
579 self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")
580 self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")
581 self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")
582 self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")
583 self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")
584 self.BuildTime = M.BuildTime
585
586 self._BuildDir = M.BuildDir
587 self.ModulePcdSet = {}
588 if "PCD" in ReportType:
589 #
590 # Collect all module used PCD set: module INF referenced directly or indirectly.
591 # It also saves module INF default values of them in case they exist.
592 #
593 for Pcd in M.ModulePcdList + M.LibraryPcdList:
594 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))
595
596 self.LibraryReport = None
597 if "LIBRARY" in ReportType:
598 self.LibraryReport = LibraryReport(M)
599
600 self.DepexReport = None
601 if "DEPEX" in ReportType:
602 self.DepexReport = DepexReport(M)
603
604 if "BUILD_FLAGS" in ReportType:
605 self.BuildFlagsReport = BuildFlagsReport(M)
606
607
608 ##
609 # Generate report for module information
610 #
611 # This function generates report for separate module expression
612 # in a platform build.
613 #
614 # @param self The object pointer
615 # @param File The file object for report
616 # @param GlobalPcdReport The platform global PCD report object
617 # @param GlobalPredictionReport The platform global Prediction report object
618 # @param GlobalDepexParser The platform global Dependency expression parser object
619 # @param ReportType The kind of report items in the final report file
620 #
621 def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType):
622 FileWrite(File, gSectionStart)
623
624 FwReportFileName = os.path.join(self._BuildDir, "OUTPUT", self.ModuleName + ".txt")
625 if os.path.isfile(FwReportFileName):
626 try:
627 FileContents = open(FwReportFileName).read()
628 Match = gModuleSizePattern.search(FileContents)
629 if Match:
630 self.Size = int(Match.group(1))
631
632 Match = gTimeStampPattern.search(FileContents)
633 if Match:
634 self.BuildTimeStamp = datetime.utcfromtimestamp(int(Match.group(1)))
635 except IOError:
636 EdkLogger.warn(None, "Fail to read report file", FwReportFileName)
637
638 if "HASH" in ReportType:
639 OutputDir = os.path.join(self._BuildDir, "OUTPUT")
640 DefaultEFIfile = os.path.join(OutputDir, self.ModuleName + ".efi")
641 if os.path.isfile(DefaultEFIfile):
642 Tempfile = os.path.join(OutputDir, self.ModuleName + "_hash.tmp")
643 # rebase the efi image since its base address may not zero
644 cmd = ["GenFw", "--rebase", str(0), "-o", Tempfile, DefaultEFIfile]
645 try:
646 PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
647 except Exception as X:
648 EdkLogger.error("GenFw", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))
649 EndOfProcedure = threading.Event()
650 EndOfProcedure.clear()
651 if PopenObject.stderr:
652 StdErrThread = threading.Thread(target=ReadMessage, args=(PopenObject.stderr, EdkLogger.quiet, EndOfProcedure))
653 StdErrThread.setName("STDERR-Redirector")
654 StdErrThread.setDaemon(False)
655 StdErrThread.start()
656 # waiting for program exit
657 PopenObject.wait()
658 if PopenObject.stderr:
659 StdErrThread.join()
660 if PopenObject.returncode != 0:
661 EdkLogger.error("GenFw", COMMAND_FAILURE, "Failed to generate firmware hash image for %s" % (DefaultEFIfile))
662 if os.path.isfile(Tempfile):
663 self.Hash = hashlib.sha1()
664 buf = open(Tempfile, 'rb').read()
665 if self.Hash.update(buf):
666 self.Hash = self.Hash.update(buf)
667 self.Hash = self.Hash.hexdigest()
668 os.remove(Tempfile)
669
670 FileWrite(File, "Module Summary")
671 FileWrite(File, "Module Name: %s" % self.ModuleName)
672 FileWrite(File, "Module Arch: %s" % self.ModuleArch)
673 FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)
674 FileWrite(File, "File GUID: %s" % self.FileGuid)
675 if self.Size:
676 FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))
677 if self.Hash:
678 FileWrite(File, "SHA1 HASH: %s *%s" % (self.Hash, self.ModuleName + ".efi"))
679 if self.BuildTimeStamp:
680 FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)
681 if self.BuildTime:
682 FileWrite(File, "Module Build Time: %s" % self.BuildTime)
683 if self.DriverType:
684 FileWrite(File, "Driver Type: %s" % self.DriverType)
685 if self.UefiSpecVersion:
686 FileWrite(File, "UEFI Spec Version: %s" % self.UefiSpecVersion)
687 if self.PiSpecVersion:
688 FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)
689 if self.PciDeviceId:
690 FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)
691 if self.PciVendorId:
692 FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)
693 if self.PciClassCode:
694 FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)
695
696 FileWrite(File, gSectionSep)
697
698 if "PCD" in ReportType:
699 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet)
700
701 if "LIBRARY" in ReportType:
702 self.LibraryReport.GenerateReport(File)
703
704 if "DEPEX" in ReportType:
705 self.DepexReport.GenerateReport(File, GlobalDepexParser)
706
707 if "BUILD_FLAGS" in ReportType:
708 self.BuildFlagsReport.GenerateReport(File)
709
710 if "FIXED_ADDRESS" in ReportType and self.FileGuid:
711 GlobalPredictionReport.GenerateReport(File, self.FileGuid)
712
713 FileWrite(File, gSectionEnd)
714
715 def ReadMessage(From, To, ExitFlag):
716 while True:
717 # read one line a time
718 Line = From.readline()
719 # empty string means "end"
720 if Line is not None and Line != b"":
721 To(Line.rstrip().decode(encoding='utf-8', errors='ignore'))
722 else:
723 break
724 if ExitFlag.isSet():
725 break
726
727 ##
728 # Reports platform and module PCD information
729 #
730 # This class reports the platform PCD section and module PCD subsection
731 # in the build report file.
732 #
733 class PcdReport(object):
734 ##
735 # Constructor function for class PcdReport
736 #
737 # This constructor function generates PcdReport object a platform build.
738 # It collects the whole PCD database from platform DSC files, platform
739 # flash description file and package DEC files.
740 #
741 # @param self The object pointer
742 # @param Wa Workspace context information
743 #
744 def __init__(self, Wa):
745 self.AllPcds = {}
746 self.UnusedPcds = {}
747 self.ConditionalPcds = {}
748 self.MaxLen = 0
749 self.Arch = None
750 if Wa.FdfProfile:
751 self.FdfPcdSet = Wa.FdfProfile.PcdDict
752 else:
753 self.FdfPcdSet = {}
754
755 self.DefaultStoreSingle = True
756 self.SkuSingle = True
757 if GlobalData.gDefaultStores and len(GlobalData.gDefaultStores) > 1:
758 self.DefaultStoreSingle = False
759 if GlobalData.gSkuids and len(GlobalData.gSkuids) > 1:
760 self.SkuSingle = False
761
762 self.ModulePcdOverride = {}
763 for Pa in Wa.AutoGenObjectList:
764 self.Arch = Pa.Arch
765 #
766 # Collect all platform referenced PCDs and grouped them by PCD token space
767 # GUID C Names
768 #
769 for Pcd in Pa.AllPcdList:
770 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
771 if Pcd not in PcdList:
772 PcdList.append(Pcd)
773 if len(Pcd.TokenCName) > self.MaxLen:
774 self.MaxLen = len(Pcd.TokenCName)
775 #
776 # Collect the PCD defined in DSC/FDF file, but not used in module
777 #
778 UnusedPcdFullList = []
779 StructPcdDict = GlobalData.gStructurePcd.get(self.Arch, collections.OrderedDict())
780 for Name, Guid in StructPcdDict:
781 if (Name, Guid) not in Pa.Platform.Pcds:
782 Pcd = StructPcdDict[(Name, Guid)]
783 PcdList = self.AllPcds.setdefault(Guid, {}).setdefault(Pcd.Type, [])
784 if Pcd not in PcdList and Pcd not in UnusedPcdFullList:
785 UnusedPcdFullList.append(Pcd)
786 for item in Pa.Platform.Pcds:
787 Pcd = Pa.Platform.Pcds[item]
788 if not Pcd.Type:
789 # check the Pcd in FDF file, whether it is used in module first
790 for T in PCD_TYPE_LIST:
791 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(T, [])
792 if Pcd in PcdList:
793 Pcd.Type = T
794 break
795 if not Pcd.Type:
796 PcdTypeFlag = False
797 for package in Pa.PackageList:
798 for T in PCD_TYPE_LIST:
799 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T) in package.Pcds:
800 Pcd.Type = T
801 PcdTypeFlag = True
802 if not Pcd.DatumType:
803 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T)].DatumType
804 break
805 if PcdTypeFlag:
806 break
807 if not Pcd.DatumType:
808 PcdType = Pcd.Type
809 # Try to remove Hii and Vpd suffix
810 if PcdType.startswith(TAB_PCDS_DYNAMIC_EX):
811 PcdType = TAB_PCDS_DYNAMIC_EX
812 elif PcdType.startswith(TAB_PCDS_DYNAMIC):
813 PcdType = TAB_PCDS_DYNAMIC
814 for package in Pa.PackageList:
815 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType) in package.Pcds:
816 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType)].DatumType
817 break
818
819 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
820 UnusedPcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
821 if Pcd in UnusedPcdList:
822 UnusedPcdList.remove(Pcd)
823 if Pcd not in PcdList and Pcd not in UnusedPcdFullList:
824 UnusedPcdFullList.append(Pcd)
825 if len(Pcd.TokenCName) > self.MaxLen:
826 self.MaxLen = len(Pcd.TokenCName)
827
828 if GlobalData.gConditionalPcds:
829 for PcdItem in GlobalData.gConditionalPcds:
830 if '.' in PcdItem:
831 (TokenSpaceGuidCName, TokenCName) = PcdItem.split('.')
832 if (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
833 Pcd = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)]
834 PcdList = self.ConditionalPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
835 if Pcd not in PcdList:
836 PcdList.append(Pcd)
837
838 UnusedPcdList = []
839 if UnusedPcdFullList:
840 for Pcd in UnusedPcdFullList:
841 if Pcd.TokenSpaceGuidCName + '.' + Pcd.TokenCName in GlobalData.gConditionalPcds:
842 continue
843 UnusedPcdList.append(Pcd)
844
845 for Pcd in UnusedPcdList:
846 PcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
847 if Pcd not in PcdList:
848 PcdList.append(Pcd)
849
850 for Module in Pa.Platform.Modules.values():
851 #
852 # Collect module override PCDs
853 #
854 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:
855 TokenCName = ModulePcd.TokenCName
856 TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName
857 ModuleDefault = ModulePcd.DefaultValue
858 ModulePath = os.path.basename(Module.M.MetaFile.File)
859 self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), {})[ModulePath] = ModuleDefault
860
861
862 #
863 # Collect PCD DEC default value.
864 #
865 self.DecPcdDefault = {}
866 self._GuidDict = {}
867 for Pa in Wa.AutoGenObjectList:
868 for Package in Pa.PackageList:
869 Guids = Package.Guids
870 self._GuidDict.update(Guids)
871 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
872 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
873 self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)
874 #
875 # Collect PCDs defined in DSC common section
876 #
877 self.DscPcdDefault = {}
878 for Pa in Wa.AutoGenObjectList:
879 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
880 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DscDefaultValue
881 if DscDefaultValue:
882 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
883
884 def GenerateReport(self, File, ModulePcdSet):
885 if not ModulePcdSet:
886 if self.ConditionalPcds:
887 self.GenerateReportDetail(File, ModulePcdSet, 1)
888 if self.UnusedPcds:
889 IsEmpty = True
890 for Token in self.UnusedPcds:
891 TokenDict = self.UnusedPcds[Token]
892 for Type in TokenDict:
893 if TokenDict[Type]:
894 IsEmpty = False
895 break
896 if not IsEmpty:
897 break
898 if not IsEmpty:
899 self.GenerateReportDetail(File, ModulePcdSet, 2)
900 self.GenerateReportDetail(File, ModulePcdSet)
901
902 ##
903 # Generate report for PCD information
904 #
905 # This function generates report for separate module expression
906 # in a platform build.
907 #
908 # @param self The object pointer
909 # @param File The file object for report
910 # @param ModulePcdSet Set of all PCDs referenced by module or None for
911 # platform PCD report
912 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
913 # directives section report, 2 means Unused Pcds section report
914 # @param DscOverridePcds Module DSC override PCDs set
915 #
916 def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0):
917 PcdDict = self.AllPcds
918 if ReportSubType == 1:
919 PcdDict = self.ConditionalPcds
920 elif ReportSubType == 2:
921 PcdDict = self.UnusedPcds
922
923 if not ModulePcdSet:
924 FileWrite(File, gSectionStart)
925 if ReportSubType == 1:
926 FileWrite(File, "Conditional Directives used by the build system")
927 elif ReportSubType == 2:
928 FileWrite(File, "PCDs not used by modules or in conditional directives")
929 else:
930 FileWrite(File, "Platform Configuration Database Report")
931
932 FileWrite(File, " *B - PCD override in the build option")
933 FileWrite(File, " *P - Platform scoped PCD override in DSC file")
934 FileWrite(File, " *F - Platform scoped PCD override in FDF file")
935 if not ReportSubType:
936 FileWrite(File, " *M - Module scoped PCD override")
937 FileWrite(File, gSectionSep)
938 else:
939 if not ReportSubType and ModulePcdSet:
940 #
941 # For module PCD sub-section
942 #
943 FileWrite(File, gSubSectionStart)
944 FileWrite(File, TAB_BRG_PCD)
945 FileWrite(File, gSubSectionSep)
946 AllPcdDict = {}
947 for Key in PcdDict:
948 AllPcdDict[Key] = {}
949 for Type in PcdDict[Key]:
950 for Pcd in PcdDict[Key][Type]:
951 AllPcdDict[Key][(Pcd.TokenCName, Type)] = Pcd
952 for Key in sorted(AllPcdDict):
953 #
954 # Group PCD by their token space GUID C Name
955 #
956 First = True
957 for PcdTokenCName, Type in sorted(AllPcdDict[Key]):
958 #
959 # Group PCD by their usage type
960 #
961 Pcd = AllPcdDict[Key][(PcdTokenCName, Type)]
962 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))
963 MixedPcdFlag = False
964 if GlobalData.MixedPcd:
965 for PcdKey in GlobalData.MixedPcd:
966 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdKey]:
967 PcdTokenCName = PcdKey[0]
968 MixedPcdFlag = True
969 if MixedPcdFlag and not ModulePcdSet:
970 continue
971 #
972 # Get PCD default value and their override relationship
973 #
974 DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))
975 DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
976 DscDefaultValBak = DscDefaultValue
977 Field = ''
978 for (CName, Guid, Field) in self.FdfPcdSet:
979 if CName == PcdTokenCName and Guid == Key:
980 DscDefaultValue = self.FdfPcdSet[(CName, Guid, Field)]
981 break
982 if DscDefaultValue != DscDefaultValBak:
983 try:
984 DscDefaultValue = ValueExpressionEx(DscDefaultValue, Pcd.DatumType, self._GuidDict)(True)
985 except BadExpression as DscDefaultValue:
986 EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" %(DscDefaultValue, Pcd.DatumType))
987
988 InfDefaultValue = None
989
990 PcdValue = DecDefaultValue
991 if DscDefaultValue:
992 PcdValue = DscDefaultValue
993 #The DefaultValue of StructurePcd already be the latest, no need to update.
994 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
995 Pcd.DefaultValue = PcdValue
996 if ModulePcdSet is not None:
997 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:
998 continue
999 InfDefaultValue, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
1000 #The DefaultValue of StructurePcd already be the latest, no need to update.
1001 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
1002 Pcd.DefaultValue = PcdValue
1003 if InfDefaultValue:
1004 try:
1005 InfDefaultValue = ValueExpressionEx(InfDefaultValue, Pcd.DatumType, self._GuidDict)(True)
1006 except BadExpression as InfDefaultValue:
1007 EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" % (InfDefaultValue, Pcd.DatumType))
1008 if InfDefaultValue == "":
1009 InfDefaultValue = None
1010
1011 BuildOptionMatch = False
1012 if GlobalData.BuildOptionPcd:
1013 for pcd in GlobalData.BuildOptionPcd:
1014 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]):
1015 if pcd[2]:
1016 continue
1017 PcdValue = pcd[3]
1018 #The DefaultValue of StructurePcd already be the latest, no need to update.
1019 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
1020 Pcd.DefaultValue = PcdValue
1021 BuildOptionMatch = True
1022 break
1023
1024 if First:
1025 if ModulePcdSet is None:
1026 FileWrite(File, "")
1027 FileWrite(File, Key)
1028 First = False
1029
1030
1031 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
1032 if PcdValue.startswith('0') and not PcdValue.lower().startswith('0x') and \
1033 len(PcdValue) > 1 and PcdValue.lstrip('0'):
1034 PcdValue = PcdValue.lstrip('0')
1035 PcdValueNumber = int(PcdValue.strip(), 0)
1036 if DecDefaultValue is None:
1037 DecMatch = True
1038 else:
1039 if DecDefaultValue.startswith('0') and not DecDefaultValue.lower().startswith('0x') and \
1040 len(DecDefaultValue) > 1 and DecDefaultValue.lstrip('0'):
1041 DecDefaultValue = DecDefaultValue.lstrip('0')
1042 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)
1043 DecMatch = (DecDefaultValueNumber == PcdValueNumber)
1044
1045 if InfDefaultValue is None:
1046 InfMatch = True
1047 else:
1048 if InfDefaultValue.startswith('0') and not InfDefaultValue.lower().startswith('0x') and \
1049 len(InfDefaultValue) > 1 and InfDefaultValue.lstrip('0'):
1050 InfDefaultValue = InfDefaultValue.lstrip('0')
1051 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)
1052 InfMatch = (InfDefaultValueNumber == PcdValueNumber)
1053
1054 if DscDefaultValue is None:
1055 DscMatch = True
1056 else:
1057 if DscDefaultValue.startswith('0') and not DscDefaultValue.lower().startswith('0x') and \
1058 len(DscDefaultValue) > 1 and DscDefaultValue.lstrip('0'):
1059 DscDefaultValue = DscDefaultValue.lstrip('0')
1060 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)
1061 DscMatch = (DscDefaultValueNumber == PcdValueNumber)
1062 else:
1063 if DecDefaultValue is None:
1064 DecMatch = True
1065 else:
1066 DecMatch = (DecDefaultValue.strip() == PcdValue.strip())
1067
1068 if InfDefaultValue is None:
1069 InfMatch = True
1070 else:
1071 InfMatch = (InfDefaultValue.strip() == PcdValue.strip())
1072
1073 if DscDefaultValue is None:
1074 DscMatch = True
1075 else:
1076 DscMatch = (DscDefaultValue.strip() == PcdValue.strip())
1077
1078 IsStructure = False
1079 if self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
1080 IsStructure = True
1081 if TypeName in ('DYNVPD', 'DEXVPD'):
1082 SkuInfoList = Pcd.SkuInfoList
1083 Pcd = GlobalData.gStructurePcd[self.Arch][(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]
1084 Pcd.DatumType = Pcd.StructName
1085 if TypeName in ('DYNVPD', 'DEXVPD'):
1086 Pcd.SkuInfoList = SkuInfoList
1087 if Pcd.PcdValueFromComm or Pcd.PcdFieldValueFromComm:
1088 BuildOptionMatch = True
1089 DecMatch = False
1090 elif Pcd.PcdValueFromFdf or Pcd.PcdFieldValueFromFdf:
1091 DscDefaultValue = True
1092 DscMatch = True
1093 DecMatch = False
1094 elif Pcd.SkuOverrideValues:
1095 DscOverride = False
1096 if Pcd.DefaultFromDSC:
1097 DscOverride = True
1098 else:
1099 DictLen = 0
1100 for item in Pcd.SkuOverrideValues:
1101 DictLen += len(Pcd.SkuOverrideValues[item])
1102 if not DictLen:
1103 DscOverride = False
1104 else:
1105 if not Pcd.SkuInfoList:
1106 OverrideValues = Pcd.SkuOverrideValues
1107 if OverrideValues:
1108 for Data in OverrideValues.values():
1109 Struct = list(Data.values())
1110 if Struct:
1111 DscOverride = self.ParseStruct(Struct[0])
1112 break
1113 else:
1114 SkuList = sorted(Pcd.SkuInfoList.keys())
1115 for Sku in SkuList:
1116 SkuInfo = Pcd.SkuInfoList[Sku]
1117 if SkuInfo.DefaultStoreDict:
1118 DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())
1119 for DefaultStore in DefaultStoreList:
1120 OverrideValues = Pcd.SkuOverrideValues[Sku]
1121 DscOverride = self.ParseStruct(OverrideValues[DefaultStore])
1122 if DscOverride:
1123 break
1124 if DscOverride:
1125 break
1126 if DscOverride:
1127 DscDefaultValue = True
1128 DscMatch = True
1129 DecMatch = False
1130 else:
1131 DecMatch = True
1132 else:
1133 DscDefaultValue = True
1134 DscMatch = True
1135 DecMatch = False
1136
1137 #
1138 # Report PCD item according to their override relationship
1139 #
1140 if Pcd.DatumType == 'BOOLEAN':
1141 if DscDefaultValue:
1142 DscDefaultValue = str(int(DscDefaultValue, 0))
1143 if DecDefaultValue:
1144 DecDefaultValue = str(int(DecDefaultValue, 0))
1145 if InfDefaultValue:
1146 InfDefaultValue = str(int(InfDefaultValue, 0))
1147 if Pcd.DefaultValue:
1148 Pcd.DefaultValue = str(int(Pcd.DefaultValue, 0))
1149 if DecMatch:
1150 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, ' ')
1151 elif InfDefaultValue and InfMatch:
1152 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')
1153 elif BuildOptionMatch:
1154 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*B')
1155 else:
1156 if DscDefaultValue and DscMatch:
1157 if (Pcd.TokenCName, Key, Field) in self.FdfPcdSet:
1158 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*F')
1159 else:
1160 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*P')
1161 else:
1162 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')
1163
1164 if ModulePcdSet is None:
1165 if IsStructure:
1166 continue
1167 if not TypeName in ('PATCH', 'FLAG', 'FIXED'):
1168 continue
1169 if not BuildOptionMatch:
1170 ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})
1171 for ModulePath in ModuleOverride:
1172 ModuleDefault = ModuleOverride[ModulePath]
1173 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
1174 if ModuleDefault.startswith('0') and not ModuleDefault.lower().startswith('0x') and \
1175 len(ModuleDefault) > 1 and ModuleDefault.lstrip('0'):
1176 ModuleDefault = ModuleDefault.lstrip('0')
1177 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)
1178 Match = (ModulePcdDefaultValueNumber == PcdValueNumber)
1179 if Pcd.DatumType == 'BOOLEAN':
1180 ModuleDefault = str(ModulePcdDefaultValueNumber)
1181 else:
1182 Match = (ModuleDefault.strip() == PcdValue.strip())
1183 if Match:
1184 continue
1185 IsByteArray, ArrayList = ByteArrayForamt(ModuleDefault.strip())
1186 if IsByteArray:
1187 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, '{'))
1188 for Array in ArrayList:
1189 FileWrite(File, Array)
1190 else:
1191 Value = ModuleDefault.strip()
1192 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1193 if Value.startswith(('0x', '0X')):
1194 Value = '{} ({:d})'.format(Value, int(Value, 0))
1195 else:
1196 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1197 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, Value))
1198
1199 if ModulePcdSet is None:
1200 FileWrite(File, gSectionEnd)
1201 else:
1202 if not ReportSubType and ModulePcdSet:
1203 FileWrite(File, gSubSectionEnd)
1204
1205 def ParseStruct(self, struct):
1206 HasDscOverride = False
1207 if struct:
1208 for _, Values in list(struct.items()):
1209 for Key, value in Values.items():
1210 if value[1] and value[1].endswith('.dsc'):
1211 HasDscOverride = True
1212 break
1213 if HasDscOverride == True:
1214 break
1215 return HasDscOverride
1216
1217 def PrintPcdDefault(self, File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue):
1218 if not DscMatch and DscDefaultValue is not None:
1219 Value = DscDefaultValue.strip()
1220 IsByteArray, ArrayList = ByteArrayForamt(Value)
1221 if IsByteArray:
1222 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', "{"))
1223 for Array in ArrayList:
1224 FileWrite(File, Array)
1225 else:
1226 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1227 if Value.startswith(('0x', '0X')):
1228 Value = '{} ({:d})'.format(Value, int(Value, 0))
1229 else:
1230 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1231 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', Value))
1232 if not InfMatch and InfDefaultValue is not None:
1233 Value = InfDefaultValue.strip()
1234 IsByteArray, ArrayList = ByteArrayForamt(Value)
1235 if IsByteArray:
1236 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', "{"))
1237 for Array in ArrayList:
1238 FileWrite(File, Array)
1239 else:
1240 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1241 if Value.startswith(('0x', '0X')):
1242 Value = '{} ({:d})'.format(Value, int(Value, 0))
1243 else:
1244 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1245 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', Value))
1246
1247 if not DecMatch and DecDefaultValue is not None:
1248 Value = DecDefaultValue.strip()
1249 IsByteArray, ArrayList = ByteArrayForamt(Value)
1250 if IsByteArray:
1251 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', "{"))
1252 for Array in ArrayList:
1253 FileWrite(File, Array)
1254 else:
1255 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1256 if Value.startswith(('0x', '0X')):
1257 Value = '{} ({:d})'.format(Value, int(Value, 0))
1258 else:
1259 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1260 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', Value))
1261 if IsStructure:
1262 for filedvalues in Pcd.DefaultValues.values():
1263 self.PrintStructureInfo(File, filedvalues)
1264 if DecMatch and IsStructure:
1265 for filedvalues in Pcd.DefaultValues.values():
1266 self.PrintStructureInfo(File, filedvalues)
1267
1268 def PrintPcdValue(self, File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, Flag = ' '):
1269 if not Pcd.SkuInfoList:
1270 Value = Pcd.DefaultValue
1271 IsByteArray, ArrayList = ByteArrayForamt(Value)
1272 if IsByteArray:
1273 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))
1274 for Array in ArrayList:
1275 FileWrite(File, Array)
1276 else:
1277 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1278 if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'):
1279 Value = Value.lstrip('0')
1280 if Value.startswith(('0x', '0X')):
1281 Value = '{} ({:d})'.format(Value, int(Value, 0))
1282 else:
1283 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1284 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
1285 if IsStructure:
1286 FiledOverrideFlag = False
1287 if (Pcd.TokenCName,Pcd.TokenSpaceGuidCName) in GlobalData.gPcdSkuOverrides:
1288 OverrideValues = GlobalData.gPcdSkuOverrides[(Pcd.TokenCName,Pcd.TokenSpaceGuidCName)]
1289 else:
1290 OverrideValues = Pcd.SkuOverrideValues
1291 if OverrideValues:
1292 for Data in OverrideValues.values():
1293 Struct = list(Data.values())
1294 if Struct:
1295 OverrideFieldStruct = self.OverrideFieldValue(Pcd, Struct[0])
1296 self.PrintStructureInfo(File, OverrideFieldStruct)
1297 FiledOverrideFlag = True
1298 break
1299 if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):
1300 OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})
1301 self.PrintStructureInfo(File, OverrideFieldStruct)
1302 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
1303 else:
1304 FirstPrint = True
1305 SkuList = sorted(Pcd.SkuInfoList.keys())
1306 for Sku in SkuList:
1307 SkuInfo = Pcd.SkuInfoList[Sku]
1308 SkuIdName = SkuInfo.SkuIdName
1309 if TypeName in ('DYNHII', 'DEXHII'):
1310 if SkuInfo.DefaultStoreDict:
1311 DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())
1312 for DefaultStore in DefaultStoreList:
1313 Value = SkuInfo.DefaultStoreDict[DefaultStore]
1314 IsByteArray, ArrayList = ByteArrayForamt(Value)
1315 if Pcd.DatumType == 'BOOLEAN':
1316 Value = str(int(Value, 0))
1317 if FirstPrint:
1318 FirstPrint = False
1319 if IsByteArray:
1320 if self.DefaultStoreSingle and self.SkuSingle:
1321 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))
1322 elif self.DefaultStoreSingle and not self.SkuSingle:
1323 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))
1324 elif not self.DefaultStoreSingle and self.SkuSingle:
1325 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))
1326 else:
1327 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))
1328 for Array in ArrayList:
1329 FileWrite(File, Array)
1330 else:
1331 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1332 if Value.startswith(('0x', '0X')):
1333 Value = '{} ({:d})'.format(Value, int(Value, 0))
1334 else:
1335 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1336 if self.DefaultStoreSingle and self.SkuSingle:
1337 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
1338 elif self.DefaultStoreSingle and not self.SkuSingle:
1339 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
1340 elif not self.DefaultStoreSingle and self.SkuSingle:
1341 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))
1342 else:
1343 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))
1344 else:
1345 if IsByteArray:
1346 if self.DefaultStoreSingle and self.SkuSingle:
1347 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '{'))
1348 elif self.DefaultStoreSingle and not self.SkuSingle:
1349 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))
1350 elif not self.DefaultStoreSingle and self.SkuSingle:
1351 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))
1352 else:
1353 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))
1354 for Array in ArrayList:
1355 FileWrite(File, Array)
1356 else:
1357 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1358 if Value.startswith(('0x', '0X')):
1359 Value = '{} ({:d})'.format(Value, int(Value, 0))
1360 else:
1361 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1362 if self.DefaultStoreSingle and self.SkuSingle:
1363 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))
1364 elif self.DefaultStoreSingle and not self.SkuSingle:
1365 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
1366 elif not self.DefaultStoreSingle and self.SkuSingle:
1367 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))
1368 else:
1369 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))
1370 FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))
1371 if IsStructure:
1372 OverrideValues = Pcd.SkuOverrideValues[Sku]
1373 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[DefaultStore])
1374 self.PrintStructureInfo(File, OverrideFieldStruct)
1375 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
1376 else:
1377 Value = SkuInfo.DefaultValue
1378 IsByteArray, ArrayList = ByteArrayForamt(Value)
1379 if Pcd.DatumType == 'BOOLEAN':
1380 Value = str(int(Value, 0))
1381 if FirstPrint:
1382 FirstPrint = False
1383 if IsByteArray:
1384 if self.SkuSingle:
1385 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', "{"))
1386 else:
1387 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))
1388 for Array in ArrayList:
1389 FileWrite(File, Array)
1390 else:
1391 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1392 if Value.startswith(('0x', '0X')):
1393 Value = '{} ({:d})'.format(Value, int(Value, 0))
1394 else:
1395 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1396 if self.SkuSingle:
1397 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
1398 else:
1399 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
1400 else:
1401 if IsByteArray:
1402 if self.SkuSingle:
1403 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', "{"))
1404 else:
1405 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))
1406 for Array in ArrayList:
1407 FileWrite(File, Array)
1408 else:
1409 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
1410 if Value.startswith(('0x', '0X')):
1411 Value = '{} ({:d})'.format(Value, int(Value, 0))
1412 else:
1413 Value = "0x{:X} ({})".format(int(Value, 0), Value)
1414 if self.SkuSingle:
1415 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))
1416 else:
1417 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
1418 if TypeName in ('DYNVPD', 'DEXVPD'):
1419 FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))
1420 VPDPcdItem = (Pcd.TokenSpaceGuidCName + '.' + PcdTokenCName, SkuIdName, SkuInfo.VpdOffset, Pcd.MaxDatumSize, SkuInfo.DefaultValue)
1421 if VPDPcdItem not in VPDPcdList:
1422 VPDPcdList.append(VPDPcdItem)
1423 if IsStructure:
1424 FiledOverrideFlag = False
1425 OverrideValues = Pcd.SkuOverrideValues[Sku]
1426 if OverrideValues:
1427 Keys = list(OverrideValues.keys())
1428 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[Keys[0]])
1429 self.PrintStructureInfo(File, OverrideFieldStruct)
1430 FiledOverrideFlag = True
1431 if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):
1432 OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})
1433 self.PrintStructureInfo(File, OverrideFieldStruct)
1434 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
1435
1436 def OverrideFieldValue(self, Pcd, OverrideStruct):
1437 OverrideFieldStruct = collections.OrderedDict()
1438 if OverrideStruct:
1439 for _, Values in OverrideStruct.items():
1440 for Key,value in Values.items():
1441 if value[1] and value[1].endswith('.dsc'):
1442 OverrideFieldStruct[Key] = value
1443 if Pcd.PcdFieldValueFromFdf:
1444 for Key, Values in Pcd.PcdFieldValueFromFdf.items():
1445 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
1446 continue
1447 OverrideFieldStruct[Key] = Values
1448 if Pcd.PcdFieldValueFromComm:
1449 for Key, Values in Pcd.PcdFieldValueFromComm.items():
1450 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
1451 continue
1452 OverrideFieldStruct[Key] = Values
1453 return OverrideFieldStruct
1454
1455 def PrintStructureInfo(self, File, Struct):
1456 for Key, Value in sorted(Struct.items(), key=lambda x: x[0]):
1457 if Value[1] and 'build command options' in Value[1]:
1458 FileWrite(File, ' *B %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1459 elif Value[1] and Value[1].endswith('.fdf'):
1460 FileWrite(File, ' *F %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1461 else:
1462 FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1463
1464 def StrtoHex(self, value):
1465 try:
1466 value = hex(int(value))
1467 return value
1468 except:
1469 if value.startswith("L\"") and value.endswith("\""):
1470 valuelist = []
1471 for ch in value[2:-1]:
1472 valuelist.append(hex(ord(ch)))
1473 valuelist.append('0x00')
1474 return valuelist
1475 elif value.startswith("\"") and value.endswith("\""):
1476 return hex(ord(value[1:-1]))
1477 elif value.startswith("{") and value.endswith("}"):
1478 valuelist = []
1479 if ',' not in value:
1480 return value[1:-1]
1481 for ch in value[1:-1].split(','):
1482 ch = ch.strip()
1483 if ch.startswith('0x') or ch.startswith('0X'):
1484 valuelist.append(ch)
1485 continue
1486 try:
1487 valuelist.append(hex(int(ch.strip())))
1488 except:
1489 pass
1490 return valuelist
1491 else:
1492 return value
1493
1494 def IsStructurePcd(self, PcdToken, PcdTokenSpaceGuid):
1495 if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd) and ((PcdToken, PcdTokenSpaceGuid) in GlobalData.gStructurePcd[self.Arch]):
1496 return True
1497 else:
1498 return False
1499
1500 ##
1501 # Reports platform and module Prediction information
1502 #
1503 # This class reports the platform execution order prediction section and
1504 # module load fixed address prediction subsection in the build report file.
1505 #
1506 class PredictionReport(object):
1507 ##
1508 # Constructor function for class PredictionReport
1509 #
1510 # This constructor function generates PredictionReport object for the platform.
1511 #
1512 # @param self: The object pointer
1513 # @param Wa Workspace context information
1514 #
1515 def __init__(self, Wa):
1516 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")
1517 self._MapFileParsed = False
1518 self._EotToolInvoked = False
1519 self._FvDir = Wa.FvDir
1520 self._EotDir = Wa.BuildDir
1521 self._FfsEntryPoint = {}
1522 self._GuidMap = {}
1523 self._SourceList = []
1524 self.FixedMapDict = {}
1525 self.ItemList = []
1526 self.MaxLen = 0
1527
1528 #
1529 # Collect all platform reference source files and GUID C Name
1530 #
1531 for Pa in Wa.AutoGenObjectList:
1532 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:
1533 #
1534 # BASE typed modules are EFI agnostic, so we need not scan
1535 # their source code to find PPI/Protocol produce or consume
1536 # information.
1537 #
1538 if Module.ModuleType == SUP_MODULE_BASE:
1539 continue
1540 #
1541 # Add module referenced source files
1542 #
1543 self._SourceList.append(str(Module))
1544 IncludeList = {}
1545 for Source in Module.SourceFileList:
1546 if os.path.splitext(str(Source))[1].lower() == ".c":
1547 self._SourceList.append(" " + str(Source))
1548 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)
1549 for IncludeFile in IncludeList.values():
1550 self._SourceList.append(" " + IncludeFile)
1551
1552 for Guid in Module.PpiList:
1553 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])
1554 for Guid in Module.ProtocolList:
1555 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])
1556 for Guid in Module.GuidList:
1557 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])
1558
1559 if Module.Guid and not Module.IsLibrary:
1560 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)
1561
1562 RealEntryPoint = "_ModuleEntryPoint"
1563
1564 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)
1565
1566
1567 #
1568 # Collect platform firmware volume list as the input of EOT.
1569 #
1570 self._FvList = []
1571 if Wa.FdfProfile:
1572 for Fd in Wa.FdfProfile.FdDict:
1573 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:
1574 if FdRegion.RegionType != BINARY_FILE_TYPE_FV:
1575 continue
1576 for FvName in FdRegion.RegionDataList:
1577 if FvName in self._FvList:
1578 continue
1579 self._FvList.append(FvName)
1580 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1581 for Section in Ffs.SectionList:
1582 try:
1583 for FvSection in Section.SectionList:
1584 if FvSection.FvName in self._FvList:
1585 continue
1586 self._FvList.append(FvSection.FvName)
1587 except AttributeError:
1588 pass
1589
1590
1591 ##
1592 # Parse platform fixed address map files
1593 #
1594 # This function parses the platform final fixed address map file to get
1595 # the database of predicted fixed address for module image base, entry point
1596 # etc.
1597 #
1598 # @param self: The object pointer
1599 #
1600 def _ParseMapFile(self):
1601 if self._MapFileParsed:
1602 return
1603 self._MapFileParsed = True
1604 if os.path.isfile(self._MapFileName):
1605 try:
1606 FileContents = open(self._MapFileName).read()
1607 for Match in gMapFileItemPattern.finditer(FileContents):
1608 AddressType = Match.group(1)
1609 BaseAddress = Match.group(2)
1610 EntryPoint = Match.group(3)
1611 Guid = Match.group(4).upper()
1612 List = self.FixedMapDict.setdefault(Guid, [])
1613 List.append((AddressType, BaseAddress, "*I"))
1614 List.append((AddressType, EntryPoint, "*E"))
1615 except:
1616 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)
1617
1618 ##
1619 # Invokes EOT tool to get the predicted the execution order.
1620 #
1621 # This function invokes EOT tool to calculate the predicted dispatch order
1622 #
1623 # @param self: The object pointer
1624 #
1625 def _InvokeEotTool(self):
1626 if self._EotToolInvoked:
1627 return
1628
1629 self._EotToolInvoked = True
1630 FvFileList = []
1631 for FvName in self._FvList:
1632 FvFile = os.path.join(self._FvDir, FvName + ".Fv")
1633 if os.path.isfile(FvFile):
1634 FvFileList.append(FvFile)
1635
1636 if len(FvFileList) == 0:
1637 return
1638 #
1639 # Write source file list and GUID file list to an intermediate file
1640 # as the input for EOT tool and dispatch List as the output file
1641 # from EOT tool.
1642 #
1643 SourceList = os.path.join(self._EotDir, "SourceFile.txt")
1644 GuidList = os.path.join(self._EotDir, "GuidList.txt")
1645 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")
1646
1647 TempFile = []
1648 for Item in self._SourceList:
1649 FileWrite(TempFile, Item)
1650 SaveFileOnChange(SourceList, "".join(TempFile), False)
1651 TempFile = []
1652 for Key in self._GuidMap:
1653 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))
1654 SaveFileOnChange(GuidList, "".join(TempFile), False)
1655
1656 try:
1657 from Eot.EotMain import Eot
1658
1659 #
1660 # Invoke EOT tool and echo its runtime performance
1661 #
1662 EotStartTime = time.time()
1663 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,
1664 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)
1665 EotEndTime = time.time()
1666 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))
1667 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)
1668
1669 #
1670 # Parse the output of EOT tool
1671 #
1672 for Line in open(DispatchList):
1673 if len(Line.split()) < 4:
1674 continue
1675 (Guid, Phase, FfsName, FilePath) = Line.split()
1676 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]
1677 if len(Symbol) > self.MaxLen:
1678 self.MaxLen = len(Symbol)
1679 self.ItemList.append((Phase, Symbol, FilePath))
1680 except:
1681 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
1682 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1683
1684
1685 ##
1686 # Generate platform execution order report
1687 #
1688 # This function generates the predicted module execution order.
1689 #
1690 # @param self The object pointer
1691 # @param File The file object for report
1692 #
1693 def _GenerateExecutionOrderReport(self, File):
1694 self._InvokeEotTool()
1695 if len(self.ItemList) == 0:
1696 return
1697 FileWrite(File, gSectionStart)
1698 FileWrite(File, "Execution Order Prediction")
1699 FileWrite(File, "*P PEI phase")
1700 FileWrite(File, "*D DXE phase")
1701 FileWrite(File, "*E Module INF entry point name")
1702 FileWrite(File, "*N Module notification function name")
1703
1704 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))
1705 FileWrite(File, gSectionSep)
1706 for Item in self.ItemList:
1707 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))
1708
1709 FileWrite(File, gSectionStart)
1710
1711 ##
1712 # Generate Fixed Address report.
1713 #
1714 # This function generate the predicted fixed address report for a module
1715 # specified by Guid.
1716 #
1717 # @param self The object pointer
1718 # @param File The file object for report
1719 # @param Guid The module Guid value.
1720 # @param NotifyList The list of all notify function in a module
1721 #
1722 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):
1723 self._ParseMapFile()
1724 FixedAddressList = self.FixedMapDict.get(Guid)
1725 if not FixedAddressList:
1726 return
1727
1728 FileWrite(File, gSubSectionStart)
1729 FileWrite(File, "Fixed Address Prediction")
1730 FileWrite(File, "*I Image Loading Address")
1731 FileWrite(File, "*E Entry Point Address")
1732 FileWrite(File, "*N Notification Function Address")
1733 FileWrite(File, "*F Flash Address")
1734 FileWrite(File, "*M Memory Address")
1735 FileWrite(File, "*S SMM RAM Offset")
1736 FileWrite(File, "TOM Top of Memory")
1737
1738 FileWrite(File, "Type Address Name")
1739 FileWrite(File, gSubSectionSep)
1740 for Item in FixedAddressList:
1741 Type = Item[0]
1742 Value = Item[1]
1743 Symbol = Item[2]
1744 if Symbol == "*I":
1745 Name = "(Image Base)"
1746 elif Symbol == "*E":
1747 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]
1748 elif Symbol in NotifyList:
1749 Name = Symbol
1750 Symbol = "*N"
1751 else:
1752 continue
1753
1754 if "Flash" in Type:
1755 Symbol += "F"
1756 elif "Memory" in Type:
1757 Symbol += "M"
1758 else:
1759 Symbol += "S"
1760
1761 if Value[0] == "-":
1762 Value = "TOM" + Value
1763
1764 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))
1765
1766 ##
1767 # Generate report for the prediction part
1768 #
1769 # This function generate the predicted fixed address report for a module or
1770 # predicted module execution order for a platform.
1771 # If the input Guid is None, then, it generates the predicted module execution order;
1772 # otherwise it generated the module fixed loading address for the module specified by
1773 # Guid.
1774 #
1775 # @param self The object pointer
1776 # @param File The file object for report
1777 # @param Guid The module Guid value.
1778 #
1779 def GenerateReport(self, File, Guid):
1780 if Guid:
1781 self._GenerateFixedAddressReport(File, Guid.upper(), [])
1782 else:
1783 self._GenerateExecutionOrderReport(File)
1784
1785 ##
1786 # Reports FD region information
1787 #
1788 # This class reports the FD subsection in the build report file.
1789 # It collects region information of platform flash device.
1790 # If the region is a firmware volume, it lists the set of modules
1791 # and its space information; otherwise, it only lists its region name,
1792 # base address and size in its sub-section header.
1793 # If there are nesting FVs, the nested FVs will list immediate after
1794 # this FD region subsection
1795 #
1796 class FdRegionReport(object):
1797 ##
1798 # Discover all the nested FV name list.
1799 #
1800 # This is an internal worker function to discover the all the nested FV information
1801 # in the parent firmware volume. It uses deep first search algorithm recursively to
1802 # find all the FV list name and append them to the list.
1803 #
1804 # @param self The object pointer
1805 # @param FvName The name of current firmware file system
1806 # @param Wa Workspace context information
1807 #
1808 def _DiscoverNestedFvList(self, FvName, Wa):
1809 FvDictKey=FvName.upper()
1810 if FvDictKey in Wa.FdfProfile.FvDict:
1811 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1812 for Section in Ffs.SectionList:
1813 try:
1814 for FvSection in Section.SectionList:
1815 if FvSection.FvName in self.FvList:
1816 continue
1817 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName
1818 self.FvList.append(FvSection.FvName)
1819 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)
1820 self._DiscoverNestedFvList(FvSection.FvName, Wa)
1821 except AttributeError:
1822 pass
1823
1824 ##
1825 # Constructor function for class FdRegionReport
1826 #
1827 # This constructor function generates FdRegionReport object for a specified FdRegion.
1828 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1829 # volume list. This function also collects GUID map in order to dump module identification
1830 # in the final report.
1831 #
1832 # @param self: The object pointer
1833 # @param FdRegion The current FdRegion object
1834 # @param Wa Workspace context information
1835 #
1836 def __init__(self, FdRegion, Wa):
1837 self.Type = FdRegion.RegionType
1838 self.BaseAddress = FdRegion.Offset
1839 self.Size = FdRegion.Size
1840 self.FvList = []
1841 self.FvInfo = {}
1842 self._GuidsDb = {}
1843 self._FvDir = Wa.FvDir
1844 self._WorkspaceDir = Wa.WorkspaceDir
1845
1846 #
1847 # If the input FdRegion is not a firmware volume,
1848 # we are done.
1849 #
1850 if self.Type != BINARY_FILE_TYPE_FV:
1851 return
1852
1853 #
1854 # Find all nested FVs in the FdRegion
1855 #
1856 for FvName in FdRegion.RegionDataList:
1857 if FvName in self.FvList:
1858 continue
1859 self.FvList.append(FvName)
1860 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)
1861 self._DiscoverNestedFvList(FvName, Wa)
1862
1863 PlatformPcds = {}
1864 #
1865 # Collect PCDs declared in DEC files.
1866 #
1867 for Pa in Wa.AutoGenObjectList:
1868 for Package in Pa.PackageList:
1869 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
1870 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
1871 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue
1872 #
1873 # Collect PCDs defined in DSC file
1874 #
1875 for Pa in Wa.AutoGenObjectList:
1876 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
1877 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
1878 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
1879
1880 #
1881 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1882 #
1883 self._GuidsDb[PEI_APRIORI_GUID] = "PEI Apriori"
1884 self._GuidsDb[DXE_APRIORI_GUID] = "DXE Apriori"
1885 #
1886 # Add ACPI table storage file
1887 #
1888 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1889
1890 for Pa in Wa.AutoGenObjectList:
1891 for ModuleKey in Pa.Platform.Modules:
1892 M = Pa.Platform.Modules[ModuleKey].M
1893 InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)
1894 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)
1895
1896 #
1897 # Collect the GUID map in the FV firmware volume
1898 #
1899 for FvName in self.FvList:
1900 FvDictKey=FvName.upper()
1901 if FvDictKey in Wa.FdfProfile.FvDict:
1902 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1903 try:
1904 #
1905 # collect GUID map for binary EFI file in FDF file.
1906 #
1907 Guid = Ffs.NameGuid.upper()
1908 Match = gPcdGuidPattern.match(Ffs.NameGuid)
1909 if Match:
1910 PcdTokenspace = Match.group(1)
1911 PcdToken = Match.group(2)
1912 if (PcdToken, PcdTokenspace) in PlatformPcds:
1913 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]
1914 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()
1915 for Section in Ffs.SectionList:
1916 try:
1917 ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)
1918 self._GuidsDb[Guid] = ModuleSectFile
1919 except AttributeError:
1920 pass
1921 except AttributeError:
1922 pass
1923
1924
1925 ##
1926 # Internal worker function to generate report for the FD region
1927 #
1928 # This internal worker function to generate report for the FD region.
1929 # It the type is firmware volume, it lists offset and module identification.
1930 #
1931 # @param self The object pointer
1932 # @param File The file object for report
1933 # @param Title The title for the FD subsection
1934 # @param BaseAddress The base address for the FD region
1935 # @param Size The size of the FD region
1936 # @param FvName The FV name if the FD region is a firmware volume
1937 #
1938 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):
1939 FileWrite(File, gSubSectionStart)
1940 FileWrite(File, Title)
1941 FileWrite(File, "Type: %s" % Type)
1942 FileWrite(File, "Base Address: 0x%X" % BaseAddress)
1943
1944 if self.Type == BINARY_FILE_TYPE_FV:
1945 FvTotalSize = 0
1946 FvTakenSize = 0
1947 FvFreeSize = 0
1948 if FvName.upper().endswith('.FV'):
1949 FileExt = FvName + ".txt"
1950 else:
1951 FileExt = FvName + ".Fv.txt"
1952
1953 if not os.path.isfile(FileExt):
1954 FvReportFileName = mws.join(self._WorkspaceDir, FileExt)
1955 if not os.path.isfile(FvReportFileName):
1956 FvReportFileName = os.path.join(self._FvDir, FileExt)
1957 try:
1958 #
1959 # Collect size info in the firmware volume.
1960 #
1961 FvReport = open(FvReportFileName).read()
1962 Match = gFvTotalSizePattern.search(FvReport)
1963 if Match:
1964 FvTotalSize = int(Match.group(1), 16)
1965 Match = gFvTakenSizePattern.search(FvReport)
1966 if Match:
1967 FvTakenSize = int(Match.group(1), 16)
1968 FvFreeSize = FvTotalSize - FvTakenSize
1969 #
1970 # Write size information to the report file.
1971 #
1972 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))
1973 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))
1974 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))
1975 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))
1976 FileWrite(File, "Offset Module")
1977 FileWrite(File, gSubSectionSep)
1978 #
1979 # Write module offset and module identification to the report file.
1980 #
1981 OffsetInfo = {}
1982 for Match in gOffsetGuidPattern.finditer(FvReport):
1983 Guid = Match.group(2).upper()
1984 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)
1985 OffsetList = sorted(OffsetInfo.keys())
1986 for Offset in OffsetList:
1987 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))
1988 except IOError:
1989 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)
1990 else:
1991 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))
1992 FileWrite(File, gSubSectionEnd)
1993
1994 ##
1995 # Generate report for the FD region
1996 #
1997 # This function generates report for the FD region.
1998 #
1999 # @param self The object pointer
2000 # @param File The file object for report
2001 #
2002 def GenerateReport(self, File):
2003 if (len(self.FvList) > 0):
2004 for FvItem in self.FvList:
2005 Info = self.FvInfo[FvItem]
2006 self._GenerateReport(File, Info[0], TAB_FV_DIRECTORY, Info[1], Info[2], FvItem)
2007 else:
2008 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)
2009
2010 ##
2011 # Reports FD information
2012 #
2013 # This class reports the FD section in the build report file.
2014 # It collects flash device information for a platform.
2015 #
2016 class FdReport(object):
2017 ##
2018 # Constructor function for class FdReport
2019 #
2020 # This constructor function generates FdReport object for a specified
2021 # firmware device.
2022 #
2023 # @param self The object pointer
2024 # @param Fd The current Firmware device object
2025 # @param Wa Workspace context information
2026 #
2027 def __init__(self, Fd, Wa):
2028 self.FdName = Fd.FdUiName
2029 self.BaseAddress = Fd.BaseAddress
2030 self.Size = Fd.Size
2031 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]
2032 self.FvPath = os.path.join(Wa.BuildDir, TAB_FV_DIRECTORY)
2033 self.VPDBaseAddress = 0
2034 self.VPDSize = 0
2035 for index, FdRegion in enumerate(Fd.RegionList):
2036 if str(FdRegion.RegionType) is 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
2037 self.VPDBaseAddress = self.FdRegionList[index].BaseAddress
2038 self.VPDSize = self.FdRegionList[index].Size
2039 break
2040
2041 ##
2042 # Generate report for the firmware device.
2043 #
2044 # This function generates report for the firmware device.
2045 #
2046 # @param self The object pointer
2047 # @param File The file object for report
2048 #
2049 def GenerateReport(self, File):
2050 FileWrite(File, gSectionStart)
2051 FileWrite(File, "Firmware Device (FD)")
2052 FileWrite(File, "FD Name: %s" % self.FdName)
2053 FileWrite(File, "Base Address: %s" % self.BaseAddress)
2054 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))
2055 if len(self.FdRegionList) > 0:
2056 FileWrite(File, gSectionSep)
2057 for FdRegionItem in self.FdRegionList:
2058 FdRegionItem.GenerateReport(File)
2059
2060 if VPDPcdList:
2061 VPDPcdList.sort(key=lambda x: int(x[2], 0))
2062 FileWrite(File, gSubSectionStart)
2063 FileWrite(File, "FD VPD Region")
2064 FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)
2065 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))
2066 FileWrite(File, gSubSectionSep)
2067 for item in VPDPcdList:
2068 # Add BaseAddress for offset
2069 Offset = '0x%08X' % (int(item[2], 16) + self.VPDBaseAddress)
2070 IsByteArray, ArrayList = ByteArrayForamt(item[-1])
2071 Skuinfo = item[1]
2072 if len(GlobalData.gSkuids) == 1 :
2073 Skuinfo = GlobalData.gSkuids[0]
2074 if IsByteArray:
2075 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], '{'))
2076 for Array in ArrayList:
2077 FileWrite(File, Array)
2078 else:
2079 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], item[-1]))
2080 FileWrite(File, gSubSectionEnd)
2081 FileWrite(File, gSectionEnd)
2082
2083
2084
2085 ##
2086 # Reports platform information
2087 #
2088 # This class reports the whole platform information
2089 #
2090 class PlatformReport(object):
2091 ##
2092 # Constructor function for class PlatformReport
2093 #
2094 # This constructor function generates PlatformReport object a platform build.
2095 # It generates report for platform summary, flash, global PCDs and detailed
2096 # module information for modules involved in platform build.
2097 #
2098 # @param self The object pointer
2099 # @param Wa Workspace context information
2100 # @param MaList The list of modules in the platform build
2101 #
2102 def __init__(self, Wa, MaList, ReportType):
2103 self._WorkspaceDir = Wa.WorkspaceDir
2104 self.PlatformName = Wa.Name
2105 self.PlatformDscPath = Wa.Platform
2106 self.Architectures = " ".join(Wa.ArchList)
2107 self.ToolChain = Wa.ToolChain
2108 self.Target = Wa.BuildTarget
2109 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)
2110 self.BuildEnvironment = platform.platform()
2111
2112 self.PcdReport = None
2113 if "PCD" in ReportType:
2114 self.PcdReport = PcdReport(Wa)
2115
2116 self.FdReportList = []
2117 if "FLASH" in ReportType and Wa.FdfProfile and MaList is None:
2118 for Fd in Wa.FdfProfile.FdDict:
2119 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))
2120
2121 self.PredictionReport = None
2122 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:
2123 self.PredictionReport = PredictionReport(Wa)
2124
2125 self.DepexParser = None
2126 if "DEPEX" in ReportType:
2127 self.DepexParser = DepexParser(Wa)
2128
2129 self.ModuleReportList = []
2130 if MaList is not None:
2131 self._IsModuleBuild = True
2132 for Ma in MaList:
2133 self.ModuleReportList.append(ModuleReport(Ma, ReportType))
2134 else:
2135 self._IsModuleBuild = False
2136 for Pa in Wa.AutoGenObjectList:
2137 ModuleAutoGenList = []
2138 for ModuleKey in Pa.Platform.Modules:
2139 ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)
2140 if GlobalData.gFdfParser is not None:
2141 if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:
2142 INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]
2143 for InfName in INFList:
2144 InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)
2145 Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile, Pa.DataPipe)
2146 if Ma is None:
2147 continue
2148 if Ma not in ModuleAutoGenList:
2149 ModuleAutoGenList.append(Ma)
2150 for MGen in ModuleAutoGenList:
2151 self.ModuleReportList.append(ModuleReport(MGen, ReportType))
2152
2153
2154
2155 ##
2156 # Generate report for the whole platform.
2157 #
2158 # This function generates report for platform information.
2159 # It comprises of platform summary, global PCD, flash and
2160 # module list sections.
2161 #
2162 # @param self The object pointer
2163 # @param File The file object for report
2164 # @param BuildDuration The total time to build the modules
2165 # @param AutoGenTime The total time of AutoGen Phase
2166 # @param MakeTime The total time of Make Phase
2167 # @param GenFdsTime The total time of GenFds Phase
2168 # @param ReportType The kind of report items in the final report file
2169 #
2170 def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):
2171 FileWrite(File, "Platform Summary")
2172 FileWrite(File, "Platform Name: %s" % self.PlatformName)
2173 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)
2174 FileWrite(File, "Architectures: %s" % self.Architectures)
2175 FileWrite(File, "Tool Chain: %s" % self.ToolChain)
2176 FileWrite(File, "Target: %s" % self.Target)
2177 if GlobalData.gSkuids:
2178 FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids))
2179 if GlobalData.gDefaultStores:
2180 FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores))
2181 FileWrite(File, "Output Path: %s" % self.OutputPath)
2182 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)
2183 FileWrite(File, "Build Duration: %s" % BuildDuration)
2184 if AutoGenTime:
2185 FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)
2186 if MakeTime:
2187 FileWrite(File, "Make Duration: %s" % MakeTime)
2188 if GenFdsTime:
2189 FileWrite(File, "GenFds Duration: %s" % GenFdsTime)
2190 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))
2191
2192 if GlobalData.MixedPcd:
2193 FileWrite(File, gSectionStart)
2194 FileWrite(File, "The following PCDs use different access methods:")
2195 FileWrite(File, gSectionSep)
2196 for PcdItem in GlobalData.MixedPcd:
2197 FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))
2198 FileWrite(File, gSectionEnd)
2199
2200 if not self._IsModuleBuild:
2201 if "PCD" in ReportType:
2202 self.PcdReport.GenerateReport(File, None)
2203
2204 if "FLASH" in ReportType:
2205 for FdReportListItem in self.FdReportList:
2206 FdReportListItem.GenerateReport(File)
2207
2208 for ModuleReportItem in self.ModuleReportList:
2209 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)
2210
2211 if not self._IsModuleBuild:
2212 if "EXECUTION_ORDER" in ReportType:
2213 self.PredictionReport.GenerateReport(File, None)
2214
2215 ## BuildReport class
2216 #
2217 # This base class contain the routines to collect data and then
2218 # applies certain format to the output report
2219 #
2220 class BuildReport(object):
2221 ##
2222 # Constructor function for class BuildReport
2223 #
2224 # This constructor function generates BuildReport object a platform build.
2225 # It generates report for platform summary, flash, global PCDs and detailed
2226 # module information for modules involved in platform build.
2227 #
2228 # @param self The object pointer
2229 # @param ReportFile The file name to save report file
2230 # @param ReportType The kind of report items in the final report file
2231 #
2232 def __init__(self, ReportFile, ReportType):
2233 self.ReportFile = ReportFile
2234 if ReportFile:
2235 self.ReportList = []
2236 self.ReportType = []
2237 if ReportType:
2238 for ReportTypeItem in ReportType:
2239 if ReportTypeItem not in self.ReportType:
2240 self.ReportType.append(ReportTypeItem)
2241 else:
2242 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2243 ##
2244 # Adds platform report to the list
2245 #
2246 # This function adds a platform report to the final report list.
2247 #
2248 # @param self The object pointer
2249 # @param Wa Workspace context information
2250 # @param MaList The list of modules in the platform build
2251 #
2252 def AddPlatformReport(self, Wa, MaList=None):
2253 if self.ReportFile:
2254 self.ReportList.append((Wa, MaList))
2255
2256 ##
2257 # Generates the final report.
2258 #
2259 # This function generates platform build report. It invokes GenerateReport()
2260 # method for every platform report in the list.
2261 #
2262 # @param self The object pointer
2263 # @param BuildDuration The total time to build the modules
2264 # @param AutoGenTime The total time of AutoGen phase
2265 # @param MakeTime The total time of Make phase
2266 # @param GenFdsTime The total time of GenFds phase
2267 #
2268 def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):
2269 if self.ReportFile:
2270 try:
2271 File = []
2272 for (Wa, MaList) in self.ReportList:
2273 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)
2274 Content = FileLinesSplit(''.join(File), gLineMaxLength)
2275 SaveFileOnChange(self.ReportFile, Content, False)
2276 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))
2277 except IOError:
2278 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)
2279 except:
2280 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)
2281 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
2282
2283 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2284 if __name__ == '__main__':
2285 pass
2286