mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-28 12:25:19 +01:00
469 lines
17 KiB
Python
469 lines
17 KiB
Python
|
## @file
|
||
|
# This file is used to create report for Eot tool
|
||
|
#
|
||
|
# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
|
||
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
#
|
||
|
|
||
|
##
|
||
|
# Import Modules
|
||
|
#
|
||
|
from __future__ import absolute_import
|
||
|
import Common.LongFilePathOs as os
|
||
|
from . import EotGlobalData
|
||
|
from Common.LongFilePathSupport import OpenLongFilePath as open
|
||
|
|
||
|
## Report() class
|
||
|
#
|
||
|
# This class defined Report
|
||
|
#
|
||
|
# @param object: Inherited from object class
|
||
|
#
|
||
|
class Report(object):
|
||
|
## The constructor
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
# @param ReportName: name of the report
|
||
|
# @param FvObj: FV object after parsing FV images
|
||
|
#
|
||
|
def __init__(self, ReportName = 'Report.html', FvObj = None, DispatchName=None):
|
||
|
self.ReportName = ReportName
|
||
|
self.Op = open(ReportName, 'w+')
|
||
|
self.DispatchList = None
|
||
|
if DispatchName:
|
||
|
self.DispatchList = open(DispatchName, 'w+')
|
||
|
self.FvObj = FvObj
|
||
|
self.FfsIndex = 0
|
||
|
self.PpiIndex = 0
|
||
|
self.ProtocolIndex = 0
|
||
|
if EotGlobalData.gMACRO['EFI_SOURCE'] == '':
|
||
|
EotGlobalData.gMACRO['EFI_SOURCE'] = EotGlobalData.gMACRO['EDK_SOURCE']
|
||
|
|
||
|
## WriteLn() method
|
||
|
#
|
||
|
# Write a line in the report
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
# @param Line: The lint to be written into
|
||
|
#
|
||
|
def WriteLn(self, Line):
|
||
|
self.Op.write('%s\n' % Line)
|
||
|
|
||
|
## GenerateReport() method
|
||
|
#
|
||
|
# A caller to generate report
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
#
|
||
|
def GenerateReport(self):
|
||
|
self.GenerateHeader()
|
||
|
self.GenerateFv()
|
||
|
self.GenerateTail()
|
||
|
self.Op.close()
|
||
|
self.GenerateUnDispatchedList()
|
||
|
|
||
|
## GenerateUnDispatchedList() method
|
||
|
#
|
||
|
# Create a list for not dispatched items
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
#
|
||
|
def GenerateUnDispatchedList(self):
|
||
|
FvObj = self.FvObj
|
||
|
EotGlobalData.gOP_UN_DISPATCHED.write('%s\n' % FvObj.Name)
|
||
|
for Item in FvObj.UnDispatchedFfsDict.keys():
|
||
|
EotGlobalData.gOP_UN_DISPATCHED.write('%s\n' % FvObj.UnDispatchedFfsDict[Item])
|
||
|
|
||
|
## GenerateFv() method
|
||
|
#
|
||
|
# Generate FV information
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
#
|
||
|
def GenerateFv(self):
|
||
|
FvObj = self.FvObj
|
||
|
Content = """ <tr>
|
||
|
<td width="20%%"><strong>Name</strong></td>
|
||
|
<td width="60%%"><strong>Guid</strong></td>
|
||
|
<td width="20%%"><strong>Size</strong></td>
|
||
|
</tr>"""
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
for Info in FvObj.BasicInfo:
|
||
|
FvName = Info[0]
|
||
|
FvGuid = Info[1]
|
||
|
FvSize = Info[2]
|
||
|
|
||
|
Content = """ <tr>
|
||
|
<td>%s</td>
|
||
|
<td>%s</td>
|
||
|
<td>%s</td>
|
||
|
</tr>""" % (FvName, FvGuid, FvSize)
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
Content = """ <td colspan="3"><table width="100%%" border="1">
|
||
|
<tr>"""
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
EotGlobalData.gOP_DISPATCH_ORDER.write('Dispatched:\n')
|
||
|
for FfsId in FvObj.OrderedFfsDict.keys():
|
||
|
self.GenerateFfs(FvObj.OrderedFfsDict[FfsId])
|
||
|
Content = """ </table></td>
|
||
|
</tr>"""
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
# For UnDispatched
|
||
|
Content = """ <td colspan="3"><table width="100%%" border="1">
|
||
|
<tr>
|
||
|
<tr><strong>UnDispatched</strong></tr>"""
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
EotGlobalData.gOP_DISPATCH_ORDER.write('\nUnDispatched:\n')
|
||
|
for FfsId in FvObj.UnDispatchedFfsDict.keys():
|
||
|
self.GenerateFfs(FvObj.UnDispatchedFfsDict[FfsId])
|
||
|
Content = """ </table></td>
|
||
|
</tr>"""
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
## GenerateDepex() method
|
||
|
#
|
||
|
# Generate Depex information
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
# @param DepexString: A DEPEX string needed to be parsed
|
||
|
#
|
||
|
def GenerateDepex(self, DepexString):
|
||
|
NonGuidList = ['AND', 'OR', 'NOT', 'BEFORE', 'AFTER', 'TRUE', 'FALSE']
|
||
|
ItemList = DepexString.split(' ')
|
||
|
DepexString = ''
|
||
|
for Item in ItemList:
|
||
|
if Item not in NonGuidList:
|
||
|
SqlCommand = """select DISTINCT GuidName from Report where GuidValue like '%s' and ItemMode = 'Produced' group by GuidName""" % (Item)
|
||
|
RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
|
||
|
if RecordSet != []:
|
||
|
Item = RecordSet[0][0]
|
||
|
DepexString = DepexString + Item + ' '
|
||
|
Content = """ <tr>
|
||
|
<td width="5%%"></td>
|
||
|
<td width="95%%">%s</td>
|
||
|
</tr>""" % (DepexString)
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
## GeneratePpi() method
|
||
|
#
|
||
|
# Generate PPI information
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
# @param Name: CName of a GUID
|
||
|
# @param Guid: Value of a GUID
|
||
|
# @param Type: Type of a GUID
|
||
|
#
|
||
|
def GeneratePpi(self, Name, Guid, Type):
|
||
|
self.GeneratePpiProtocol('Ppi', Name, Guid, Type, self.PpiIndex)
|
||
|
|
||
|
## GenerateProtocol() method
|
||
|
#
|
||
|
# Generate PROTOCOL information
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
# @param Name: CName of a GUID
|
||
|
# @param Guid: Value of a GUID
|
||
|
# @param Type: Type of a GUID
|
||
|
#
|
||
|
def GenerateProtocol(self, Name, Guid, Type):
|
||
|
self.GeneratePpiProtocol('Protocol', Name, Guid, Type, self.ProtocolIndex)
|
||
|
|
||
|
## GeneratePpiProtocol() method
|
||
|
#
|
||
|
# Generate PPI/PROTOCOL information
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
# @param Model: Model of a GUID, PPI or PROTOCOL
|
||
|
# @param Name: Name of a GUID
|
||
|
# @param Guid: Value of a GUID
|
||
|
# @param Type: Type of a GUID
|
||
|
# @param CName: CName(Index) of a GUID
|
||
|
#
|
||
|
def GeneratePpiProtocol(self, Model, Name, Guid, Type, CName):
|
||
|
Content = """ <tr>
|
||
|
<td width="5%%"></td>
|
||
|
<td width="10%%">%s</td>
|
||
|
<td width="85%%" colspan="3">%s</td>
|
||
|
<!-- %s -->
|
||
|
</tr>""" % (Model, Name, Guid)
|
||
|
self.WriteLn(Content)
|
||
|
if Type == 'Produced':
|
||
|
SqlCommand = """select DISTINCT SourceFileFullPath, BelongsToFunction from Report where GuidName like '%s' and ItemMode = 'Callback'""" % Name
|
||
|
RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
|
||
|
for Record in RecordSet:
|
||
|
SqlCommand = """select FullPath from File
|
||
|
where ID = (
|
||
|
select DISTINCT BelongsToFile from Inf
|
||
|
where Value1 like '%s')""" % Record[0]
|
||
|
ModuleSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
|
||
|
Inf = ModuleSet[0][0].replace(EotGlobalData.gMACRO['WORKSPACE'], '.')
|
||
|
Function = Record[1]
|
||
|
Address = ''
|
||
|
for Item in EotGlobalData.gMap:
|
||
|
if Function in EotGlobalData.gMap[Item]:
|
||
|
Address = EotGlobalData.gMap[Item][Function]
|
||
|
break
|
||
|
if '_' + Function in EotGlobalData.gMap[Item]:
|
||
|
Address = EotGlobalData.gMap[Item]['_' + Function]
|
||
|
break
|
||
|
Content = """ <tr>
|
||
|
<td width="5%%"></td>
|
||
|
<td width="10%%">%s</td>
|
||
|
<td width="40%%">%s</td>
|
||
|
<td width="35%%">%s</td>
|
||
|
<td width="10%%">%s</td>
|
||
|
</tr>""" % ('Callback', Inf, Function, Address)
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
## GenerateFfs() method
|
||
|
#
|
||
|
# Generate FFS information
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
# @param FfsObj: FFS object after FV image is parsed
|
||
|
#
|
||
|
def GenerateFfs(self, FfsObj):
|
||
|
self.FfsIndex = self.FfsIndex + 1
|
||
|
if FfsObj is not None and FfsObj.Type in [0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xA]:
|
||
|
FfsGuid = FfsObj.Guid
|
||
|
FfsOffset = FfsObj._OFF_
|
||
|
FfsName = 'Unknown-Module'
|
||
|
FfsPath = FfsGuid
|
||
|
FfsType = FfsObj._TypeName[FfsObj.Type]
|
||
|
|
||
|
# Hard code for Binary INF
|
||
|
if FfsGuid.upper() == '7BB28B99-61BB-11D5-9A5D-0090273FC14D':
|
||
|
FfsName = 'Logo'
|
||
|
|
||
|
if FfsGuid.upper() == '7E374E25-8E01-4FEE-87F2-390C23C606CD':
|
||
|
FfsName = 'AcpiTables'
|
||
|
|
||
|
if FfsGuid.upper() == '961578FE-B6B7-44C3-AF35-6BC705CD2B1F':
|
||
|
FfsName = 'Fat'
|
||
|
|
||
|
# Find FFS Path and Name
|
||
|
SqlCommand = """select Value2 from Inf
|
||
|
where BelongsToFile = (select BelongsToFile from Inf where Value1 = 'FILE_GUID' and lower(Value2) = lower('%s') and Model = %s)
|
||
|
and Model = %s and Value1='BASE_NAME'""" % (FfsGuid, 5001, 5001)
|
||
|
RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
|
||
|
if RecordSet != []:
|
||
|
FfsName = RecordSet[0][0]
|
||
|
|
||
|
SqlCommand = """select FullPath from File
|
||
|
where ID = (select BelongsToFile from Inf where Value1 = 'FILE_GUID' and lower(Value2) = lower('%s') and Model = %s)
|
||
|
and Model = %s""" % (FfsGuid, 5001, 1011)
|
||
|
RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
|
||
|
if RecordSet != []:
|
||
|
FfsPath = RecordSet[0][0]
|
||
|
|
||
|
Content = """ <tr>
|
||
|
<tr class='styleFfs' id='FfsHeader%s'>
|
||
|
<td width="55%%"><span onclick="Display('FfsHeader%s', 'Ffs%s')" onMouseOver="funOnMouseOver()" onMouseOut="funOnMouseOut()">%s</span></td>
|
||
|
<td width="15%%">%s</td>
|
||
|
<!--<td width="20%%">%s</td>-->
|
||
|
<!--<td width="20%%">%s</td>-->
|
||
|
<td width="10%%">%s</td>
|
||
|
</tr>
|
||
|
<tr id='Ffs%s' style='display:none;'>
|
||
|
<td colspan="4"><table width="100%%" border="1">""" % (self.FfsIndex, self.FfsIndex, self.FfsIndex, FfsPath, FfsName, FfsGuid, FfsOffset, FfsType, self.FfsIndex)
|
||
|
|
||
|
if self.DispatchList:
|
||
|
if FfsObj.Type in [0x04, 0x06]:
|
||
|
self.DispatchList.write("%s %s %s %s\n" % (FfsGuid, "P", FfsName, FfsPath))
|
||
|
if FfsObj.Type in [0x05, 0x07, 0x08, 0x0A]:
|
||
|
self.DispatchList.write("%s %s %s %s\n" % (FfsGuid, "D", FfsName, FfsPath))
|
||
|
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
EotGlobalData.gOP_DISPATCH_ORDER.write('%s\n' %FfsName)
|
||
|
|
||
|
if FfsObj.Depex != '':
|
||
|
Content = """ <tr>
|
||
|
<td><span id='DepexHeader%s' class="styleDepex" onclick="Display('DepexHeader%s', 'Depex%s')" onMouseOver="funOnMouseOver()" onMouseOut="funOnMouseOut()">  DEPEX expression</span></td>
|
||
|
</tr>
|
||
|
<tr id='Depex%s' style='display:none;'>
|
||
|
<td><table width="100%%" border="1">""" % (self.FfsIndex, self.FfsIndex, self.FfsIndex, self.FfsIndex)
|
||
|
self.WriteLn(Content)
|
||
|
self.GenerateDepex(FfsObj.Depex)
|
||
|
Content = """ </table></td>
|
||
|
</tr>"""
|
||
|
self.WriteLn(Content)
|
||
|
# End of DEPEX
|
||
|
|
||
|
# Find Consumed Ppi/Protocol
|
||
|
SqlCommand = """select ModuleName, ItemType, GuidName, GuidValue, GuidMacro from Report
|
||
|
where SourceFileFullPath in
|
||
|
(select Value1 from Inf where BelongsToFile =
|
||
|
(select BelongsToFile from Inf
|
||
|
where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
|
||
|
and Model = %s)
|
||
|
and ItemMode = 'Consumed' group by GuidName order by ItemType""" \
|
||
|
% (FfsGuid, 5001, 3007)
|
||
|
|
||
|
RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
|
||
|
if RecordSet != []:
|
||
|
Count = len(RecordSet)
|
||
|
Content = """ <tr>
|
||
|
<td><span id='ConsumedHeader%s' class="styleConsumed" onclick="Display('ConsumedHeader%s', 'Consumed%s')" onMouseOver="funOnMouseOver()" onMouseOut="funOnMouseOut()">  Consumed Ppis/Protocols List (%s)</span></td>
|
||
|
</tr>
|
||
|
<tr id='Consumed%s' style='display:none;'>
|
||
|
<td><table width="100%%" border="1">""" % (self.FfsIndex, self.FfsIndex, self.FfsIndex, Count, self.FfsIndex)
|
||
|
self.WriteLn(Content)
|
||
|
self.ProtocolIndex = 0
|
||
|
for Record in RecordSet:
|
||
|
self.ProtocolIndex = self.ProtocolIndex + 1
|
||
|
Name = Record[2]
|
||
|
CName = Record[4]
|
||
|
Guid = Record[3]
|
||
|
Type = Record[1]
|
||
|
self.GeneratePpiProtocol(Type, Name, Guid, 'Consumed', CName)
|
||
|
|
||
|
Content = """ </table></td>
|
||
|
</tr>"""
|
||
|
self.WriteLn(Content)
|
||
|
#End of Consumed Ppi/Protocol
|
||
|
|
||
|
# Find Produced Ppi/Protocol
|
||
|
SqlCommand = """select ModuleName, ItemType, GuidName, GuidValue, GuidMacro from Report
|
||
|
where SourceFileFullPath in
|
||
|
(select Value1 from Inf where BelongsToFile =
|
||
|
(select BelongsToFile from Inf
|
||
|
where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
|
||
|
and Model = %s)
|
||
|
and ItemMode = 'Produced' group by GuidName order by ItemType""" \
|
||
|
% (FfsGuid, 5001, 3007)
|
||
|
|
||
|
RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
|
||
|
if RecordSet != []:
|
||
|
Count = len(RecordSet)
|
||
|
Content = """ <tr>
|
||
|
<td><span id='ProducedHeader%s' class="styleProduced" onclick="Display('ProducedHeader%s', 'Produced%s')" onMouseOver="funOnMouseOver()" onMouseOut="funOnMouseOut()">  Produced Ppis/Protocols List (%s)</span></td>
|
||
|
</tr>
|
||
|
<tr id='Produced%s' style='display:none;'>
|
||
|
<td><table width="100%%" border="1">""" % (self.FfsIndex, self.FfsIndex, self.FfsIndex, Count, self.FfsIndex)
|
||
|
self.WriteLn(Content)
|
||
|
self.PpiIndex = 0
|
||
|
for Record in RecordSet:
|
||
|
self.PpiIndex = self.PpiIndex + 1
|
||
|
Name = Record[2]
|
||
|
CName = Record[4]
|
||
|
Guid = Record[3]
|
||
|
Type = Record[1]
|
||
|
self.GeneratePpiProtocol(Type, Name, Guid, 'Produced', CName)
|
||
|
|
||
|
Content = """ </table></td>
|
||
|
</tr>"""
|
||
|
self.WriteLn(Content)
|
||
|
RecordSet = None
|
||
|
# End of Produced Ppi/Protocol
|
||
|
|
||
|
Content = """ </table></td>
|
||
|
</tr>"""
|
||
|
self.WriteLn(Content)
|
||
|
|
||
|
## GenerateTail() method
|
||
|
#
|
||
|
# Generate end tags of HTML report
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
#
|
||
|
def GenerateTail(self):
|
||
|
Tail = """</table>
|
||
|
</body>
|
||
|
</html>"""
|
||
|
self.WriteLn(Tail)
|
||
|
|
||
|
## GenerateHeader() method
|
||
|
#
|
||
|
# Generate start tags of HTML report
|
||
|
#
|
||
|
# @param self: The object pointer
|
||
|
#
|
||
|
def GenerateHeader(self):
|
||
|
Header = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||
|
"http://www.w3.org/TR/html4/loose.dtd">
|
||
|
<html>
|
||
|
<head>
|
||
|
<title>Execution Order Tool Report</title>
|
||
|
<meta http-equiv="Content-Type" content="text/html">
|
||
|
<style type="text/css">
|
||
|
<!--
|
||
|
.styleFfs {
|
||
|
color: #006600;
|
||
|
font-weight: bold;
|
||
|
}
|
||
|
.styleDepex {
|
||
|
color: #FF0066;
|
||
|
font-weight: bold;
|
||
|
}
|
||
|
.styleProduced {
|
||
|
color: #0000FF;
|
||
|
font-weight: bold;
|
||
|
}
|
||
|
.styleConsumed {
|
||
|
color: #FF00FF;
|
||
|
font-weight: bold;
|
||
|
}
|
||
|
-->
|
||
|
</style>
|
||
|
<Script type="text/javascript">
|
||
|
function Display(ParentID, SubID)
|
||
|
{
|
||
|
SubItem = document.getElementById(SubID);
|
||
|
ParentItem = document.getElementById(ParentID);
|
||
|
if (SubItem.style.display == 'none')
|
||
|
{
|
||
|
SubItem.style.display = ''
|
||
|
ParentItem.style.fontWeight = 'normal'
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SubItem.style.display = 'none'
|
||
|
ParentItem.style.fontWeight = 'bold'
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
function funOnMouseOver()
|
||
|
{
|
||
|
document.body.style.cursor = "hand";
|
||
|
}
|
||
|
|
||
|
function funOnMouseOut()
|
||
|
{
|
||
|
document.body.style.cursor = "";
|
||
|
}
|
||
|
|
||
|
</Script>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
<table width="100%%" border="1">"""
|
||
|
self.WriteLn(Header)
|
||
|
|
||
|
##
|
||
|
#
|
||
|
# This acts like the main() function for the script, unless it is 'import'ed into another
|
||
|
# script.
|
||
|
#
|
||
|
if __name__ == '__main__':
|
||
|
# Initialize log system
|
||
|
FilePath = 'FVRECOVERYFLOPPY.fv'
|
||
|
if FilePath.lower().endswith(".fv"):
|
||
|
fd = open(FilePath, 'rb')
|
||
|
buf = array('B')
|
||
|
try:
|
||
|
buf.fromfile(fd, os.path.getsize(FilePath))
|
||
|
except EOFError:
|
||
|
pass
|
||
|
|
||
|
fv = FirmwareVolume("FVRECOVERY", buf, 0)
|
||
|
|
||
|
report = Report('Report.html', fv)
|
||
|
report.GenerateReport()
|