]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/BuildReport.py
BaseTools:Fix the issue that build report failed
[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 PcdGuidList = self.UnusedPcds.get(Pcd.TokenSpaceGuidCName)
1423 if PcdGuidList:
1424 PcdList = PcdGuidList.get(Pcd.Type)
1425 if not PcdList:
1426 VPDPcdList.append(VPDPcdItem)
1427 for VpdPcd in PcdList:
1428 if PcdTokenCName == VpdPcd.TokenCName:
1429 break
1430 else:
1431 VPDPcdList.append(VPDPcdItem)
1432 if IsStructure:
1433 FiledOverrideFlag = False
1434 OverrideValues = Pcd.SkuOverrideValues.get(Sku)
1435 if OverrideValues:
1436 Keys = list(OverrideValues.keys())
1437 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[Keys[0]])
1438 self.PrintStructureInfo(File, OverrideFieldStruct)
1439 FiledOverrideFlag = True
1440 if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):
1441 OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})
1442 self.PrintStructureInfo(File, OverrideFieldStruct)
1443 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
1444
1445 def OverrideFieldValue(self, Pcd, OverrideStruct):
1446 OverrideFieldStruct = collections.OrderedDict()
1447 if OverrideStruct:
1448 for _, Values in OverrideStruct.items():
1449 for Key,value in Values.items():
1450 if value[1] and value[1].endswith('.dsc'):
1451 OverrideFieldStruct[Key] = value
1452 if Pcd.PcdFieldValueFromFdf:
1453 for Key, Values in Pcd.PcdFieldValueFromFdf.items():
1454 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
1455 continue
1456 OverrideFieldStruct[Key] = Values
1457 if Pcd.PcdFieldValueFromComm:
1458 for Key, Values in Pcd.PcdFieldValueFromComm.items():
1459 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
1460 continue
1461 OverrideFieldStruct[Key] = Values
1462 return OverrideFieldStruct
1463
1464 def PrintStructureInfo(self, File, Struct):
1465 for Key, Value in sorted(Struct.items(), key=lambda x: x[0]):
1466 if Value[1] and 'build command options' in Value[1]:
1467 FileWrite(File, ' *B %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1468 elif Value[1] and Value[1].endswith('.fdf'):
1469 FileWrite(File, ' *F %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1470 else:
1471 FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1472
1473 def StrtoHex(self, value):
1474 try:
1475 value = hex(int(value))
1476 return value
1477 except:
1478 if value.startswith("L\"") and value.endswith("\""):
1479 valuelist = []
1480 for ch in value[2:-1]:
1481 valuelist.append(hex(ord(ch)))
1482 valuelist.append('0x00')
1483 return valuelist
1484 elif value.startswith("\"") and value.endswith("\""):
1485 return hex(ord(value[1:-1]))
1486 elif value.startswith("{") and value.endswith("}"):
1487 valuelist = []
1488 if ',' not in value:
1489 return value[1:-1]
1490 for ch in value[1:-1].split(','):
1491 ch = ch.strip()
1492 if ch.startswith('0x') or ch.startswith('0X'):
1493 valuelist.append(ch)
1494 continue
1495 try:
1496 valuelist.append(hex(int(ch.strip())))
1497 except:
1498 pass
1499 return valuelist
1500 else:
1501 return value
1502
1503 def IsStructurePcd(self, PcdToken, PcdTokenSpaceGuid):
1504 if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd) and ((PcdToken, PcdTokenSpaceGuid) in GlobalData.gStructurePcd[self.Arch]):
1505 return True
1506 else:
1507 return False
1508
1509 ##
1510 # Reports platform and module Prediction information
1511 #
1512 # This class reports the platform execution order prediction section and
1513 # module load fixed address prediction subsection in the build report file.
1514 #
1515 class PredictionReport(object):
1516 ##
1517 # Constructor function for class PredictionReport
1518 #
1519 # This constructor function generates PredictionReport object for the platform.
1520 #
1521 # @param self: The object pointer
1522 # @param Wa Workspace context information
1523 #
1524 def __init__(self, Wa):
1525 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")
1526 self._MapFileParsed = False
1527 self._EotToolInvoked = False
1528 self._FvDir = Wa.FvDir
1529 self._EotDir = Wa.BuildDir
1530 self._FfsEntryPoint = {}
1531 self._GuidMap = {}
1532 self._SourceList = []
1533 self.FixedMapDict = {}
1534 self.ItemList = []
1535 self.MaxLen = 0
1536
1537 #
1538 # Collect all platform reference source files and GUID C Name
1539 #
1540 for Pa in Wa.AutoGenObjectList:
1541 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:
1542 #
1543 # BASE typed modules are EFI agnostic, so we need not scan
1544 # their source code to find PPI/Protocol produce or consume
1545 # information.
1546 #
1547 if Module.ModuleType == SUP_MODULE_BASE:
1548 continue
1549 #
1550 # Add module referenced source files
1551 #
1552 self._SourceList.append(str(Module))
1553 IncludeList = {}
1554 for Source in Module.SourceFileList:
1555 if os.path.splitext(str(Source))[1].lower() == ".c":
1556 self._SourceList.append(" " + str(Source))
1557 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)
1558 for IncludeFile in IncludeList.values():
1559 self._SourceList.append(" " + IncludeFile)
1560
1561 for Guid in Module.PpiList:
1562 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])
1563 for Guid in Module.ProtocolList:
1564 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])
1565 for Guid in Module.GuidList:
1566 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])
1567
1568 if Module.Guid and not Module.IsLibrary:
1569 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)
1570
1571 RealEntryPoint = "_ModuleEntryPoint"
1572
1573 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)
1574
1575
1576 #
1577 # Collect platform firmware volume list as the input of EOT.
1578 #
1579 self._FvList = []
1580 if Wa.FdfProfile:
1581 for Fd in Wa.FdfProfile.FdDict:
1582 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:
1583 if FdRegion.RegionType != BINARY_FILE_TYPE_FV:
1584 continue
1585 for FvName in FdRegion.RegionDataList:
1586 if FvName in self._FvList:
1587 continue
1588 self._FvList.append(FvName)
1589 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1590 for Section in Ffs.SectionList:
1591 try:
1592 for FvSection in Section.SectionList:
1593 if FvSection.FvName in self._FvList:
1594 continue
1595 self._FvList.append(FvSection.FvName)
1596 except AttributeError:
1597 pass
1598
1599
1600 ##
1601 # Parse platform fixed address map files
1602 #
1603 # This function parses the platform final fixed address map file to get
1604 # the database of predicted fixed address for module image base, entry point
1605 # etc.
1606 #
1607 # @param self: The object pointer
1608 #
1609 def _ParseMapFile(self):
1610 if self._MapFileParsed:
1611 return
1612 self._MapFileParsed = True
1613 if os.path.isfile(self._MapFileName):
1614 try:
1615 FileContents = open(self._MapFileName).read()
1616 for Match in gMapFileItemPattern.finditer(FileContents):
1617 AddressType = Match.group(1)
1618 BaseAddress = Match.group(2)
1619 EntryPoint = Match.group(3)
1620 Guid = Match.group(4).upper()
1621 List = self.FixedMapDict.setdefault(Guid, [])
1622 List.append((AddressType, BaseAddress, "*I"))
1623 List.append((AddressType, EntryPoint, "*E"))
1624 except:
1625 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)
1626
1627 ##
1628 # Invokes EOT tool to get the predicted the execution order.
1629 #
1630 # This function invokes EOT tool to calculate the predicted dispatch order
1631 #
1632 # @param self: The object pointer
1633 #
1634 def _InvokeEotTool(self):
1635 if self._EotToolInvoked:
1636 return
1637
1638 self._EotToolInvoked = True
1639 FvFileList = []
1640 for FvName in self._FvList:
1641 FvFile = os.path.join(self._FvDir, FvName + ".Fv")
1642 if os.path.isfile(FvFile):
1643 FvFileList.append(FvFile)
1644
1645 if len(FvFileList) == 0:
1646 return
1647 #
1648 # Write source file list and GUID file list to an intermediate file
1649 # as the input for EOT tool and dispatch List as the output file
1650 # from EOT tool.
1651 #
1652 SourceList = os.path.join(self._EotDir, "SourceFile.txt")
1653 GuidList = os.path.join(self._EotDir, "GuidList.txt")
1654 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")
1655
1656 TempFile = []
1657 for Item in self._SourceList:
1658 FileWrite(TempFile, Item)
1659 SaveFileOnChange(SourceList, "".join(TempFile), False)
1660 TempFile = []
1661 for Key in self._GuidMap:
1662 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))
1663 SaveFileOnChange(GuidList, "".join(TempFile), False)
1664
1665 try:
1666 from Eot.EotMain import Eot
1667
1668 #
1669 # Invoke EOT tool and echo its runtime performance
1670 #
1671 EotStartTime = time.time()
1672 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,
1673 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)
1674 EotEndTime = time.time()
1675 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))
1676 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)
1677
1678 #
1679 # Parse the output of EOT tool
1680 #
1681 for Line in open(DispatchList):
1682 if len(Line.split()) < 4:
1683 continue
1684 (Guid, Phase, FfsName, FilePath) = Line.split()
1685 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]
1686 if len(Symbol) > self.MaxLen:
1687 self.MaxLen = len(Symbol)
1688 self.ItemList.append((Phase, Symbol, FilePath))
1689 except:
1690 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
1691 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1692
1693
1694 ##
1695 # Generate platform execution order report
1696 #
1697 # This function generates the predicted module execution order.
1698 #
1699 # @param self The object pointer
1700 # @param File The file object for report
1701 #
1702 def _GenerateExecutionOrderReport(self, File):
1703 self._InvokeEotTool()
1704 if len(self.ItemList) == 0:
1705 return
1706 FileWrite(File, gSectionStart)
1707 FileWrite(File, "Execution Order Prediction")
1708 FileWrite(File, "*P PEI phase")
1709 FileWrite(File, "*D DXE phase")
1710 FileWrite(File, "*E Module INF entry point name")
1711 FileWrite(File, "*N Module notification function name")
1712
1713 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))
1714 FileWrite(File, gSectionSep)
1715 for Item in self.ItemList:
1716 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))
1717
1718 FileWrite(File, gSectionStart)
1719
1720 ##
1721 # Generate Fixed Address report.
1722 #
1723 # This function generate the predicted fixed address report for a module
1724 # specified by Guid.
1725 #
1726 # @param self The object pointer
1727 # @param File The file object for report
1728 # @param Guid The module Guid value.
1729 # @param NotifyList The list of all notify function in a module
1730 #
1731 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):
1732 self._ParseMapFile()
1733 FixedAddressList = self.FixedMapDict.get(Guid)
1734 if not FixedAddressList:
1735 return
1736
1737 FileWrite(File, gSubSectionStart)
1738 FileWrite(File, "Fixed Address Prediction")
1739 FileWrite(File, "*I Image Loading Address")
1740 FileWrite(File, "*E Entry Point Address")
1741 FileWrite(File, "*N Notification Function Address")
1742 FileWrite(File, "*F Flash Address")
1743 FileWrite(File, "*M Memory Address")
1744 FileWrite(File, "*S SMM RAM Offset")
1745 FileWrite(File, "TOM Top of Memory")
1746
1747 FileWrite(File, "Type Address Name")
1748 FileWrite(File, gSubSectionSep)
1749 for Item in FixedAddressList:
1750 Type = Item[0]
1751 Value = Item[1]
1752 Symbol = Item[2]
1753 if Symbol == "*I":
1754 Name = "(Image Base)"
1755 elif Symbol == "*E":
1756 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]
1757 elif Symbol in NotifyList:
1758 Name = Symbol
1759 Symbol = "*N"
1760 else:
1761 continue
1762
1763 if "Flash" in Type:
1764 Symbol += "F"
1765 elif "Memory" in Type:
1766 Symbol += "M"
1767 else:
1768 Symbol += "S"
1769
1770 if Value[0] == "-":
1771 Value = "TOM" + Value
1772
1773 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))
1774
1775 ##
1776 # Generate report for the prediction part
1777 #
1778 # This function generate the predicted fixed address report for a module or
1779 # predicted module execution order for a platform.
1780 # If the input Guid is None, then, it generates the predicted module execution order;
1781 # otherwise it generated the module fixed loading address for the module specified by
1782 # Guid.
1783 #
1784 # @param self The object pointer
1785 # @param File The file object for report
1786 # @param Guid The module Guid value.
1787 #
1788 def GenerateReport(self, File, Guid):
1789 if Guid:
1790 self._GenerateFixedAddressReport(File, Guid.upper(), [])
1791 else:
1792 self._GenerateExecutionOrderReport(File)
1793
1794 ##
1795 # Reports FD region information
1796 #
1797 # This class reports the FD subsection in the build report file.
1798 # It collects region information of platform flash device.
1799 # If the region is a firmware volume, it lists the set of modules
1800 # and its space information; otherwise, it only lists its region name,
1801 # base address and size in its sub-section header.
1802 # If there are nesting FVs, the nested FVs will list immediate after
1803 # this FD region subsection
1804 #
1805 class FdRegionReport(object):
1806 ##
1807 # Discover all the nested FV name list.
1808 #
1809 # This is an internal worker function to discover the all the nested FV information
1810 # in the parent firmware volume. It uses deep first search algorithm recursively to
1811 # find all the FV list name and append them to the list.
1812 #
1813 # @param self The object pointer
1814 # @param FvName The name of current firmware file system
1815 # @param Wa Workspace context information
1816 #
1817 def _DiscoverNestedFvList(self, FvName, Wa):
1818 FvDictKey=FvName.upper()
1819 if FvDictKey in Wa.FdfProfile.FvDict:
1820 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1821 for Section in Ffs.SectionList:
1822 try:
1823 for FvSection in Section.SectionList:
1824 if FvSection.FvName in self.FvList:
1825 continue
1826 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName
1827 self.FvList.append(FvSection.FvName)
1828 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)
1829 self._DiscoverNestedFvList(FvSection.FvName, Wa)
1830 except AttributeError:
1831 pass
1832
1833 ##
1834 # Constructor function for class FdRegionReport
1835 #
1836 # This constructor function generates FdRegionReport object for a specified FdRegion.
1837 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1838 # volume list. This function also collects GUID map in order to dump module identification
1839 # in the final report.
1840 #
1841 # @param self: The object pointer
1842 # @param FdRegion The current FdRegion object
1843 # @param Wa Workspace context information
1844 #
1845 def __init__(self, FdRegion, Wa):
1846 self.Type = FdRegion.RegionType
1847 self.BaseAddress = FdRegion.Offset
1848 self.Size = FdRegion.Size
1849 self.FvList = []
1850 self.FvInfo = {}
1851 self._GuidsDb = {}
1852 self._FvDir = Wa.FvDir
1853 self._WorkspaceDir = Wa.WorkspaceDir
1854
1855 #
1856 # If the input FdRegion is not a firmware volume,
1857 # we are done.
1858 #
1859 if self.Type != BINARY_FILE_TYPE_FV:
1860 return
1861
1862 #
1863 # Find all nested FVs in the FdRegion
1864 #
1865 for FvName in FdRegion.RegionDataList:
1866 if FvName in self.FvList:
1867 continue
1868 self.FvList.append(FvName)
1869 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)
1870 self._DiscoverNestedFvList(FvName, Wa)
1871
1872 PlatformPcds = {}
1873 #
1874 # Collect PCDs declared in DEC files.
1875 #
1876 for Pa in Wa.AutoGenObjectList:
1877 for Package in Pa.PackageList:
1878 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
1879 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
1880 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue
1881 #
1882 # Collect PCDs defined in DSC file
1883 #
1884 for Pa in Wa.AutoGenObjectList:
1885 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
1886 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
1887 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
1888
1889 #
1890 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1891 #
1892 self._GuidsDb[PEI_APRIORI_GUID] = "PEI Apriori"
1893 self._GuidsDb[DXE_APRIORI_GUID] = "DXE Apriori"
1894 #
1895 # Add ACPI table storage file
1896 #
1897 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1898
1899 for Pa in Wa.AutoGenObjectList:
1900 for ModuleKey in Pa.Platform.Modules:
1901 M = Pa.Platform.Modules[ModuleKey].M
1902 InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)
1903 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)
1904
1905 #
1906 # Collect the GUID map in the FV firmware volume
1907 #
1908 for FvName in self.FvList:
1909 FvDictKey=FvName.upper()
1910 if FvDictKey in Wa.FdfProfile.FvDict:
1911 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1912 try:
1913 #
1914 # collect GUID map for binary EFI file in FDF file.
1915 #
1916 Guid = Ffs.NameGuid.upper()
1917 Match = gPcdGuidPattern.match(Ffs.NameGuid)
1918 if Match:
1919 PcdTokenspace = Match.group(1)
1920 PcdToken = Match.group(2)
1921 if (PcdToken, PcdTokenspace) in PlatformPcds:
1922 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]
1923 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()
1924 for Section in Ffs.SectionList:
1925 try:
1926 ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)
1927 self._GuidsDb[Guid] = ModuleSectFile
1928 except AttributeError:
1929 pass
1930 except AttributeError:
1931 pass
1932
1933
1934 ##
1935 # Internal worker function to generate report for the FD region
1936 #
1937 # This internal worker function to generate report for the FD region.
1938 # It the type is firmware volume, it lists offset and module identification.
1939 #
1940 # @param self The object pointer
1941 # @param File The file object for report
1942 # @param Title The title for the FD subsection
1943 # @param BaseAddress The base address for the FD region
1944 # @param Size The size of the FD region
1945 # @param FvName The FV name if the FD region is a firmware volume
1946 #
1947 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):
1948 FileWrite(File, gSubSectionStart)
1949 FileWrite(File, Title)
1950 FileWrite(File, "Type: %s" % Type)
1951 FileWrite(File, "Base Address: 0x%X" % BaseAddress)
1952
1953 if self.Type == BINARY_FILE_TYPE_FV:
1954 FvTotalSize = 0
1955 FvTakenSize = 0
1956 FvFreeSize = 0
1957 if FvName.upper().endswith('.FV'):
1958 FileExt = FvName + ".txt"
1959 else:
1960 FileExt = FvName + ".Fv.txt"
1961
1962 if not os.path.isfile(FileExt):
1963 FvReportFileName = mws.join(self._WorkspaceDir, FileExt)
1964 if not os.path.isfile(FvReportFileName):
1965 FvReportFileName = os.path.join(self._FvDir, FileExt)
1966 try:
1967 #
1968 # Collect size info in the firmware volume.
1969 #
1970 FvReport = open(FvReportFileName).read()
1971 Match = gFvTotalSizePattern.search(FvReport)
1972 if Match:
1973 FvTotalSize = int(Match.group(1), 16)
1974 Match = gFvTakenSizePattern.search(FvReport)
1975 if Match:
1976 FvTakenSize = int(Match.group(1), 16)
1977 FvFreeSize = FvTotalSize - FvTakenSize
1978 #
1979 # Write size information to the report file.
1980 #
1981 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))
1982 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))
1983 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))
1984 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))
1985 FileWrite(File, "Offset Module")
1986 FileWrite(File, gSubSectionSep)
1987 #
1988 # Write module offset and module identification to the report file.
1989 #
1990 OffsetInfo = {}
1991 for Match in gOffsetGuidPattern.finditer(FvReport):
1992 Guid = Match.group(2).upper()
1993 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)
1994 OffsetList = sorted(OffsetInfo.keys())
1995 for Offset in OffsetList:
1996 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))
1997 except IOError:
1998 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)
1999 else:
2000 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))
2001 FileWrite(File, gSubSectionEnd)
2002
2003 ##
2004 # Generate report for the FD region
2005 #
2006 # This function generates report for the FD region.
2007 #
2008 # @param self The object pointer
2009 # @param File The file object for report
2010 #
2011 def GenerateReport(self, File):
2012 if (len(self.FvList) > 0):
2013 for FvItem in self.FvList:
2014 Info = self.FvInfo[FvItem]
2015 self._GenerateReport(File, Info[0], TAB_FV_DIRECTORY, Info[1], Info[2], FvItem)
2016 else:
2017 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)
2018
2019 ##
2020 # Reports FD information
2021 #
2022 # This class reports the FD section in the build report file.
2023 # It collects flash device information for a platform.
2024 #
2025 class FdReport(object):
2026 ##
2027 # Constructor function for class FdReport
2028 #
2029 # This constructor function generates FdReport object for a specified
2030 # firmware device.
2031 #
2032 # @param self The object pointer
2033 # @param Fd The current Firmware device object
2034 # @param Wa Workspace context information
2035 #
2036 def __init__(self, Fd, Wa):
2037 self.FdName = Fd.FdUiName
2038 self.BaseAddress = Fd.BaseAddress
2039 self.Size = Fd.Size
2040 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]
2041 self.FvPath = os.path.join(Wa.BuildDir, TAB_FV_DIRECTORY)
2042 self.VPDBaseAddress = 0
2043 self.VPDSize = 0
2044 for index, FdRegion in enumerate(Fd.RegionList):
2045 if str(FdRegion.RegionType) is 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
2046 self.VPDBaseAddress = self.FdRegionList[index].BaseAddress
2047 self.VPDSize = self.FdRegionList[index].Size
2048 break
2049
2050 ##
2051 # Generate report for the firmware device.
2052 #
2053 # This function generates report for the firmware device.
2054 #
2055 # @param self The object pointer
2056 # @param File The file object for report
2057 #
2058 def GenerateReport(self, File):
2059 FileWrite(File, gSectionStart)
2060 FileWrite(File, "Firmware Device (FD)")
2061 FileWrite(File, "FD Name: %s" % self.FdName)
2062 FileWrite(File, "Base Address: %s" % self.BaseAddress)
2063 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))
2064 if len(self.FdRegionList) > 0:
2065 FileWrite(File, gSectionSep)
2066 for FdRegionItem in self.FdRegionList:
2067 FdRegionItem.GenerateReport(File)
2068
2069 if VPDPcdList:
2070 VPDPcdList.sort(key=lambda x: int(x[2], 0))
2071 FileWrite(File, gSubSectionStart)
2072 FileWrite(File, "FD VPD Region")
2073 FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)
2074 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))
2075 FileWrite(File, gSubSectionSep)
2076 for item in VPDPcdList:
2077 # Add BaseAddress for offset
2078 Offset = '0x%08X' % (int(item[2], 16) + self.VPDBaseAddress)
2079 IsByteArray, ArrayList = ByteArrayForamt(item[-1])
2080 Skuinfo = item[1]
2081 if len(GlobalData.gSkuids) == 1 :
2082 Skuinfo = GlobalData.gSkuids[0]
2083 if IsByteArray:
2084 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], '{'))
2085 for Array in ArrayList:
2086 FileWrite(File, Array)
2087 else:
2088 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], item[-1]))
2089 FileWrite(File, gSubSectionEnd)
2090 FileWrite(File, gSectionEnd)
2091
2092
2093
2094 ##
2095 # Reports platform information
2096 #
2097 # This class reports the whole platform information
2098 #
2099 class PlatformReport(object):
2100 ##
2101 # Constructor function for class PlatformReport
2102 #
2103 # This constructor function generates PlatformReport object a platform build.
2104 # It generates report for platform summary, flash, global PCDs and detailed
2105 # module information for modules involved in platform build.
2106 #
2107 # @param self The object pointer
2108 # @param Wa Workspace context information
2109 # @param MaList The list of modules in the platform build
2110 #
2111 def __init__(self, Wa, MaList, ReportType):
2112 self._WorkspaceDir = Wa.WorkspaceDir
2113 self.PlatformName = Wa.Name
2114 self.PlatformDscPath = Wa.Platform
2115 self.Architectures = " ".join(Wa.ArchList)
2116 self.ToolChain = Wa.ToolChain
2117 self.Target = Wa.BuildTarget
2118 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)
2119 self.BuildEnvironment = platform.platform()
2120
2121 self.PcdReport = None
2122 if "PCD" in ReportType:
2123 self.PcdReport = PcdReport(Wa)
2124
2125 self.FdReportList = []
2126 if "FLASH" in ReportType and Wa.FdfProfile and MaList is None:
2127 for Fd in Wa.FdfProfile.FdDict:
2128 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))
2129
2130 self.PredictionReport = None
2131 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:
2132 self.PredictionReport = PredictionReport(Wa)
2133
2134 self.DepexParser = None
2135 if "DEPEX" in ReportType:
2136 self.DepexParser = DepexParser(Wa)
2137
2138 self.ModuleReportList = []
2139 if MaList is not None:
2140 self._IsModuleBuild = True
2141 for Ma in MaList:
2142 self.ModuleReportList.append(ModuleReport(Ma, ReportType))
2143 else:
2144 self._IsModuleBuild = False
2145 for Pa in Wa.AutoGenObjectList:
2146 ModuleAutoGenList = []
2147 for ModuleKey in Pa.Platform.Modules:
2148 ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)
2149 if GlobalData.gFdfParser is not None:
2150 if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:
2151 INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]
2152 for InfName in INFList:
2153 InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)
2154 Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile, Pa.DataPipe)
2155 if Ma is None:
2156 continue
2157 if Ma not in ModuleAutoGenList:
2158 ModuleAutoGenList.append(Ma)
2159 for MGen in ModuleAutoGenList:
2160 self.ModuleReportList.append(ModuleReport(MGen, ReportType))
2161
2162
2163
2164 ##
2165 # Generate report for the whole platform.
2166 #
2167 # This function generates report for platform information.
2168 # It comprises of platform summary, global PCD, flash and
2169 # module list sections.
2170 #
2171 # @param self The object pointer
2172 # @param File The file object for report
2173 # @param BuildDuration The total time to build the modules
2174 # @param AutoGenTime The total time of AutoGen Phase
2175 # @param MakeTime The total time of Make Phase
2176 # @param GenFdsTime The total time of GenFds Phase
2177 # @param ReportType The kind of report items in the final report file
2178 #
2179 def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):
2180 FileWrite(File, "Platform Summary")
2181 FileWrite(File, "Platform Name: %s" % self.PlatformName)
2182 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)
2183 FileWrite(File, "Architectures: %s" % self.Architectures)
2184 FileWrite(File, "Tool Chain: %s" % self.ToolChain)
2185 FileWrite(File, "Target: %s" % self.Target)
2186 if GlobalData.gSkuids:
2187 FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids))
2188 if GlobalData.gDefaultStores:
2189 FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores))
2190 FileWrite(File, "Output Path: %s" % self.OutputPath)
2191 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)
2192 FileWrite(File, "Build Duration: %s" % BuildDuration)
2193 if AutoGenTime:
2194 FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)
2195 if MakeTime:
2196 FileWrite(File, "Make Duration: %s" % MakeTime)
2197 if GenFdsTime:
2198 FileWrite(File, "GenFds Duration: %s" % GenFdsTime)
2199 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))
2200
2201 if GlobalData.MixedPcd:
2202 FileWrite(File, gSectionStart)
2203 FileWrite(File, "The following PCDs use different access methods:")
2204 FileWrite(File, gSectionSep)
2205 for PcdItem in GlobalData.MixedPcd:
2206 FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))
2207 FileWrite(File, gSectionEnd)
2208
2209 if not self._IsModuleBuild:
2210 if "PCD" in ReportType:
2211 self.PcdReport.GenerateReport(File, None)
2212
2213 if "FLASH" in ReportType:
2214 for FdReportListItem in self.FdReportList:
2215 FdReportListItem.GenerateReport(File)
2216
2217 for ModuleReportItem in self.ModuleReportList:
2218 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)
2219
2220 if not self._IsModuleBuild:
2221 if "EXECUTION_ORDER" in ReportType:
2222 self.PredictionReport.GenerateReport(File, None)
2223
2224 ## BuildReport class
2225 #
2226 # This base class contain the routines to collect data and then
2227 # applies certain format to the output report
2228 #
2229 class BuildReport(object):
2230 ##
2231 # Constructor function for class BuildReport
2232 #
2233 # This constructor function generates BuildReport object a platform build.
2234 # It generates report for platform summary, flash, global PCDs and detailed
2235 # module information for modules involved in platform build.
2236 #
2237 # @param self The object pointer
2238 # @param ReportFile The file name to save report file
2239 # @param ReportType The kind of report items in the final report file
2240 #
2241 def __init__(self, ReportFile, ReportType):
2242 self.ReportFile = ReportFile
2243 if ReportFile:
2244 self.ReportList = []
2245 self.ReportType = []
2246 if ReportType:
2247 for ReportTypeItem in ReportType:
2248 if ReportTypeItem not in self.ReportType:
2249 self.ReportType.append(ReportTypeItem)
2250 else:
2251 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2252 ##
2253 # Adds platform report to the list
2254 #
2255 # This function adds a platform report to the final report list.
2256 #
2257 # @param self The object pointer
2258 # @param Wa Workspace context information
2259 # @param MaList The list of modules in the platform build
2260 #
2261 def AddPlatformReport(self, Wa, MaList=None):
2262 if self.ReportFile:
2263 self.ReportList.append((Wa, MaList))
2264
2265 ##
2266 # Generates the final report.
2267 #
2268 # This function generates platform build report. It invokes GenerateReport()
2269 # method for every platform report in the list.
2270 #
2271 # @param self The object pointer
2272 # @param BuildDuration The total time to build the modules
2273 # @param AutoGenTime The total time of AutoGen phase
2274 # @param MakeTime The total time of Make phase
2275 # @param GenFdsTime The total time of GenFds phase
2276 #
2277 def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):
2278 if self.ReportFile:
2279 try:
2280 File = []
2281 for (Wa, MaList) in self.ReportList:
2282 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)
2283 Content = FileLinesSplit(''.join(File), gLineMaxLength)
2284 SaveFileOnChange(self.ReportFile, Content, False)
2285 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))
2286 except IOError:
2287 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)
2288 except:
2289 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)
2290 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
2291
2292 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2293 if __name__ == '__main__':
2294 pass
2295