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