Files
slimbootloader/BootloaderCorePkg/Tools/GenReport.py
T
Maurice Ma ea38da7599 [TOOLS] Add python3 build support
EDK II build has enabled python3 support. Since SBL has its own scripts,
it is required to port them accordingly to support python3. This patch
added python3 build support for SBL.

Signed-off-by: Maurice Ma <maurice.ma@intel.com>
2019-08-22 09:18:52 -07:00

778 lines
26 KiB
Python

## @ GenReport.py
#
# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
import os
import re
import sys
import uuid
from ctypes import *
from functools import reduce
sys.dont_write_bytecode = True
from BuildUtility import STITCH_OPS
def Bytes2Val(bytes):
return reduce(lambda x, y: (x << 8) | y, bytes[::-1])
def Val2Bytes(value, blen):
return [(value >> (i * 8) & 0xff) for i in range(blen)]
def AlignPtrUp(offset, alignment=8):
return (offset + alignment - 1) & ~(alignment - 1)
def AlignPtrDown(offset, alignment=8):
return offset & ~(alignment - 1)
def ExecAssignment (var, val):
namespace = {}
exec ('%s = %s' % (var, val), namespace)
return namespace[var]
class c_uint24(Structure):
_pack_ = 1
_fields_ = [('Data', (c_uint8 * 3))]
def __init__(self, val=0):
self.set_value(val)
def __str__(self, indent=0):
return '0x%.6x' % self.value
def __int__(self):
return self.get_value()
def set_value(self, val):
self.Data[0:3] = Val2Bytes(val, 3)
def get_value(self):
return Bytes2Val(self.Data[0:3])
value = property(get_value, set_value)
class EFI_FIRMWARE_VOLUME_HEADER(Structure):
_fields_ = [
('ZeroVector', ARRAY(c_uint8, 16)),
('FileSystemGuid', ARRAY(c_uint8, 16)),
('FvLength', c_uint64),
('Signature', ARRAY(c_char, 4)),
('Attributes', c_uint32),
('HeaderLength', c_uint16),
('Checksum', c_uint16),
('ExtHeaderOffset', c_uint16),
('Reserved', c_uint8),
('Revision', c_uint8)
]
class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure):
_fields_ = [
('FvName', ARRAY(c_uint8, 16)),
('ExtHeaderSize', c_uint32)
]
class EFI_FFS_INTEGRITY_CHECK(Structure):
_fields_ = [
('Header', c_uint8),
('File', c_uint8)
]
class EFI_FFS_FILE_HEADER(Structure):
_fields_ = [
('Name', ARRAY(c_uint8, 16)),
('IntegrityCheck', EFI_FFS_INTEGRITY_CHECK),
('Type', c_uint8),
('Attributes', c_uint8),
('Size', c_uint24),
('State', c_uint8)
]
class FSP_INFORMATION_HEADER(Structure):
_fields_ = [
('Signature', ARRAY(c_char, 4)),
('HeaderLength', c_uint32),
('Reserved1', c_uint16),
('SpecVersion', c_uint8),
('HeaderRevision', c_uint8),
('ImageRevision', c_uint32),
('ImageId', ARRAY(c_char, 8)),
('ImageSize', c_uint32),
('ImageBase', c_uint32),
('ImageAttribute', c_uint16),
('ComponentAttribute', c_uint16),
('CfgRegionOffset', c_uint32),
('CfgRegionSize', c_uint32),
('Reserved2', c_uint32),
('TempRamInitEntryOffset', c_uint32),
('Reserved3', c_uint32),
('NotifyPhaseEntryOffset', c_uint32),
('FspMemoryInitEntryOffset', c_uint32),
('TempRamExitEntryOffset', c_uint32),
('FspSiliconInitEntryOffset', c_uint32)
]
class IMG_INFO:
def __init__(self, Type, Name, Offset=0, Length=0, Base=0):
if Type == 'IMG':
self.Level = 0
elif Type == 'FD':
self.Level = 1
elif Type == 'FV' or Type == 'FSP':
self.Level = 2
elif Type == 'FFS':
self.Level = 3
else:
raise Exception('Invalid type "%s" !' % Type)
self.Name = Name
self.Type = Type
self.Offset = Offset
self.Length = Length
self.Base = Base
self.ChildList = []
def __str__(self):
Lines = []
Indent = ' ' * self.Level
Lines.append(Indent + 'Type : %s' % self.Type)
Lines.append(Indent + 'Name : %s' % self.Name)
Lines.append(Indent + 'Offset : 0x%08X' % self.Offset)
Lines.append(Indent + 'Length : 0x%08X' % self.Length)
Lines.append(Indent + 'Base : 0x%08X' % self.Base)
ChildLine = 'ChildList:'
if not len(self.ChildList):
ChildLine = ChildLine + ' []'
Lines.append(Indent + ChildLine)
else:
Lines.append(Indent + ChildLine)
for Child in self.ChildList:
Lines.append(str(Child))
Lines.append('\n')
return '\n'.join(Lines)
class REPORTER:
Cols = [4, 13, 15, 30]
def __init__(self, ImgName, RptType='FD'):
self.ImgName = ImgName
self.RptType = RptType
if RptType == 'FD':
self.Header = ['', 'FD', 'FV', 'FFS']
else:
self.Header = ['', 'Name', 'File', 'Details']
self.Layout = [[], [], [], []]
self.WordWrap = ['STAGE1', 'STAGE1A', 'STAGE1B', 'STAGE2']
self.DictDscDefines = {}
self.DictGuidNameXref = {
'1BA0062E-C779-4582-8566-336AE8F78F09': 'ResetVector',
'E08CA6D5-8D02-43AE-ABB1-952CC787C933': 'VbtBin',
'26FDAA3D-B7ED-4714-8509-EECF1593800D': 'AcmBin',
'5E2D3BE9-AD72-4D1D-AAD5-6B08AF921590': 'Logo',
'3473A022-C3C2-4964-B309-22B3DFB0B6CA': 'VerInfo',
'18EDB1DF-1DBE-4EC5-8E26-C44808B546E1': 'HashStore',
'EFAC3859-B680-4232-A159-F886F2AE0B83': 'PcdDatabase',
'CD17FF5E-7731-4D16-8441-FC7A113C392F': 'FitTable',
'3CEA8EF3-95FC-476F-ABA5-7EC5DFA1D77B': 'FlashMap',
'FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF': 'BLANK'
}
self.ColsWidth = [4, 13, 15, 30]
def GetFspType(self, Attribute):
return "XTMSXXXXOXXXXXXX" [(Attribute >> 12) & 0x0F]
def GetFfsSize(self, FvFile, FfsOffset):
FdIn = open(FvFile, "rb")
FdIn.seek(FfsOffset)
Buffer = bytearray(FdIn.read(sizeof(EFI_FFS_FILE_HEADER)))
FdIn.close()
FfsHdr = EFI_FFS_FILE_HEADER.from_buffer(Buffer)
return int(FfsHdr.Size)
def GetFvFfsList(self, FvData):
FfsList = []
FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer(FvData, 0)
if FvHdr.ExtHeaderOffset > 0:
FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer(
Buffer, FvHdr.ExtHeaderOffset)
Offset = FvHdr.ExtHeaderOffset + FvExtHdr.ExtHeaderSize
else:
Offset = FvHdr.HeaderLength
while Offset < FvHdr.FvLength:
Offset = AlignPtrUp(Offset)
FfsHdr = EFI_FFS_FILE_HEADER.from_buffer(FvData, Offset)
FfsName = str(uuid.UUID(bytes_le=bytes(bytearray(FfsHdr.Name)))).upper()
Ffs = IMG_INFO('FFS', FfsName, Offset, int(FfsHdr.Size))
if bytearray(FfsHdr.Name) == b'\xff' * 16:
if (int(FfsHdr.Size) == 0xFFFFFF):
Ffs.Length = FvHdr.FvLength - Offset
Offset += Ffs.Length
FfsList.append(Ffs)
return FfsList
def ParseFdFile(self, FdFile):
FdSize = os.path.getsize(FdFile)
if FdSize < sizeof(EFI_FIRMWARE_VOLUME_HEADER):
return None
Fd = IMG_INFO('FD', os.path.basename(FdFile), 0, FdSize)
FvOffset = 0
FdIn = open(FdFile, "rb")
FdData = bytearray(FdIn.read())
FdIn.close()
while FvOffset < FdSize:
FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer(FdData, FvOffset)
if b'_FVH' != FvHdr.Signature:
raise Exception("ERROR: Invalid FV header in FD '%s' !" %
FdFile)
FspHdr = FSP_INFORMATION_HEADER.from_buffer(FdData,
FvOffset + 0x94)
OldOffset = FvOffset
if b'FSPH' == FspHdr.Signature:
FvOffset += FspHdr.ImageSize
Fv = IMG_INFO(
'FSP', 'FSP-' + self.GetFspType(FspHdr.ComponentAttribute),
0, FspHdr.ImageSize, FspHdr.ImageBase)
Ffs = IMG_INFO('FFS', Fv.Name, 0, Fv.Length)
Fv.ChildList = [Ffs]
else:
FvOffset += FvHdr.FvLength
Fv = IMG_INFO('FV', 'UNKNOWN', 0, FvHdr.FvLength)
Fv.ChildList = self.GetFvFfsList(FdData[OldOffset:])
FirstFfs = Fv.ChildList[0]
FirstFfsName = self.GuidToModuleName(FirstFfs.Name)
if FirstFfsName.upper() == 'ACMBIN':
# For ACM FV, it contains ACM, BPM, KM, etc
# so let ACM occupy the full FV and ignore all other FFS
while len(Fv.ChildList) > 1:
Fv.ChildList.pop()
Fv.ChildList[0].Offset = 0
Fv.ChildList[0].Length = Fv.Length
if Fd.Name.startswith('STAGE2.'):
if ('STAGE2_LOAD_HIGH' in self.DictDscDefines) and \
(int(self.DictDscDefines['STAGE2_LOAD_HIGH'], 16) == 1):
# Mark FV/FSP will be loaded dynamically
Fv.Base = 0xFFFFFFFF
Fv.Offset = OldOffset
Fd.ChildList.append(Fv)
if FvOffset != FdSize:
raise Exception('Invalid FD format !')
return Fd
def ParseFvTxtFile(self, FvTxtFile):
FvName = os.path.basename(FvTxtFile)[0:-7].upper()
Fv = IMG_INFO('FV', FvName + '.FV')
FdIn = open(FvTxtFile, "r")
Lines = FdIn.readlines()
FdIn.close()
for Line in Lines:
Match = re.match("EFI_FV_TOTAL_SIZE\s+=\s+(0x[a-fA-F0-9]+)", Line)
if Match is not None:
Fv.Length = int(Match.group(1), 16)
continue
Match = re.match("(0x[a-fA-F0-9]+)\s([0-9a-fA-F\-]+)", Line)
if Match is not None:
Ffs = IMG_INFO('FFS', Match.group(2).upper())
Ffs.Offset = int(Match.group(1), 16)
Ffs.Length = self.GetFfsSize(FvTxtFile[:-4], Ffs.Offset)
Fv.ChildList.append(Ffs)
FdIn = open(FvTxtFile[0:-7] + '.inf', "r")
Lines = FdIn.readlines()
FdIn.close()
for Line in Lines:
Match = re.match("EFI_BASE_ADDRESS\s+=\s+(0x[a-fA-F0-9]+)", Line)
if Match is not None:
# Update base if it is not dynamic loading
if Fv.Base != 0xFFFFFFFF:
Fv.Base = int(Match.group(1), 16)
break
return Fv
def ParseGuidXrefFile(self, XrefFile):
FdIn = open(XrefFile, "r")
Lines = FdIn.readlines()
FdIn.close()
for Line in Lines:
Match = re.match("([0-9a-fA-F\-]+)\s(.+)", Line)
if Match:
Guid = Match.group(1).upper()
if Guid not in self.DictGuidNameXref:
Path = Match.group(2).strip()
Name = os.path.basename(Path)
self.DictGuidNameXref[Match.group(1).upper()] = Name
def ParseDscParameter(self, DefineDscFile):
FdIn = open(DefineDscFile, "r")
Lines = FdIn.readlines()
FdIn.close()
IsDefSection = False
for Line in Lines:
Line = Line.strip()
if Line.startswith('#'):
continue
if Line.startswith('['):
if Line.upper().startswith('[DEFINES]'):
IsDefSection = True
else:
IsDefSection = False
if IsDefSection:
Match = re.match("^DEFINE\s+([_\w]+)\s*=\s*([_\w]+)", Line)
if Match is not None:
self.DictDscDefines[Match.group(1).upper()] = Match.group(
2)
def GuidToModuleName(self, Guid):
if Guid in self.DictGuidNameXref:
return self.DictGuidNameXref[Guid]
else:
if len(Guid) < 0x24:
return Guid
else:
return '????'
def Report(self, FdList, CellHeight=3):
Cols = self.ColsWidth
LineHeight = CellHeight
def Center(Idx, ValueIn, Pattern):
Value = ValueIn.strip()
if Value == '':
Value = Pattern[2 * Idx + 1] * (REPORTER.Cols[Idx] - 1)
Space = REPORTER.Cols[Idx] - 1
Blank = Space - len(Value)
if Blank < 0:
Blank = 0
Value = Value[:Space]
Lead = Blank // 2
Tail = Blank - Lead
return ' ' * Lead + Value + ' ' * Tail + Pattern[2 * Idx + 2]
def OutSplitter(Pattern='+-+-+-+-+', Value=['', '', '', '']):
Lines = []
Lines.append(Pattern[0])
for i, j in enumerate(REPORTER.Cols):
Lines.append(Center(i, Value[i], Pattern))
return ' ' + ''.join(Lines)
def FillTable(Table, Base, TotalRow, Col, InputLine):
Lines = InputLine.split('!')
Count = TotalRow - len(Lines)
if Count < 0:
Start = 0
else:
Start = Base + (Count >> 1)
for Line in Lines:
if Start + 1 >= len(Table[Col]):
break
Table[Col][Start] = Line
Start += 1
def GetPattern(Layout, LineIdx):
Pattern = [ord(i) for i in '| + + + |']
for Col in range(len(Layout)):
Cnt = 0
Idx = Col * 2 + 1
for Val in Layout[Col]:
Cnt += Val
if LineIdx == Cnt - 1:
Pattern[Idx] = ord('-')
break
if LineIdx == sum(Layout[0]) - 1:
# Last line
Pattern[0] = ord('+')
Pattern[-1] = ord('+')
for Idx, Char in enumerate(Pattern):
if Char == ord('+') and Idx > 0 and Idx < len(Pattern) - 1:
# Check orphan in a row
if Pattern[Idx - 1] == ord(' ') and Pattern[Idx + 1] == ord(' '):
Pattern[Idx] = ord('|')
Pattern = ''.join(chr(i) for i in Pattern)
return Pattern
def Normalize(Com):
if Com.Type == 'FFS':
Name = self.GuidToModuleName(Com.Name)
else:
Name = Com.Name
if Com.Type in ['FV', 'FSP']:
if Com.Base == 0xFFFFFFFF:
Display = 'DYNAMIC'
else:
Display = '0x%X' % Com.Base
Name = '%s!(0x%X)!%s' % (Name, Com.Length, Display)
else:
Name = '%s!(0x%X)' % (Name, Com.Length)
Lines = Name.split('!')
Output = []
for Line in Lines:
Part = Line.split('.')[0]
Part = Part.replace(',', '.')
if len(Part) + 1 >= REPORTER.Cols[Com.Level]:
Idx = 0
for Word in self.WordWrap:
if Part.startswith(Word):
Idx = len(Word)
break
if Idx == 0:
Idx = len(Part) // 2
Part = '%s!%s' % (Part[:Idx], Part[Idx:])
Output.append(Part)
return '!'.join(Output)
def CalcRows(Image):
Layout = [[], [], [], []]
Idx1 = 0
for Img, FdList in Image:
Idx2 = 0
for Fd, FvList in FdList:
for Fv, FfsList in FvList:
FfsNum = 0
for Ffs in FfsList:
if Ffs.startswith('FSP'):
Adjust = 4
else:
Adjust = LineHeight
FfsNum += Adjust
Layout[3].append(Adjust)
Layout[2].append(FfsNum)
Layout[1].append(sum(Layout[2][Idx2:]))
Idx2 = len(Layout[2])
Layout[0].append(sum(Layout[1][Idx1:]))
Idx1 = len(Layout[1])
Count = sum(Layout[0])
self.Layout = Layout
Table = [[' ' for i in range(Count)] for i in range(len(Layout))]
Index = 0
FfsIdx = 0
FvIdx = 0
FdIdx = 0
for Idx0, (Img, FdList) in enumerate(Image):
FillTable(Table, Index, Layout[0][Idx0], 0, Img)
for Idx1, (Fd, FvList) in enumerate(FdList):
FillTable(Table, Index, Layout[1][FdIdx], 1, Fd)
for Idx2, (Fv, FfsList) in enumerate(FvList):
FillTable(Table, Index, Layout[2][FvIdx], 2, Fv)
for Idx3, Ffs in enumerate(FfsList):
FillTable(Table, Index, Layout[3][FfsIdx], 3, Ffs)
Index += Layout[3][FfsIdx]
FfsIdx += 1
FvIdx += 1
FdIdx += 1
return Table, Layout
def GetComponentLineIdx(Level, ObjIdx):
LineIdx = 0
LineLen = 0
for Idx, Each in enumerate(self.Layout[Level]):
if Idx == ObjIdx:
LineLen = Each
break
LineIdx += Each
return LineIdx, LineLen
def MarkFvInfo(Fv, FvIdx, Lines):
LineIdx, LineNum = GetComponentLineIdx(2, FvIdx)
Index = LineIdx + LineNum
Lines[Index] = Lines[Index] + ' %08X' % Fv.Base
Name = '!'.join(self.ImgName)
Tree = [(Name, [])]
FdParent = Tree[0][1]
for Fd in FdList:
FdParent.append((Normalize(Fd), []))
FvParent = FdParent[-1][1]
for Fv in Fd.ChildList:
FvParent.append((Normalize(Fv), []))
FfsParent = FvParent[-1][1]
for Ffs in Fv.ChildList:
FfsParent.append(Normalize(Ffs))
Table, Layout = CalcRows(Tree)
Rows = len(Table[0])
Lines = []
Header = OutSplitter(' ', self.Header)
Lines.append(OutSplitter())
for Idx in range(Rows):
Pattern = GetPattern(Layout, Idx)
Line = OutSplitter(Pattern, [Table[i][Idx] for i in range(4)])
Lines.append(Line)
FfsIdx = 0
ImgSize = 0
for Fd in FdList:
ImgSize += Fd.Length
Offset = ImgSize
TopOffset = Offset
LineIdx, LineNum = GetComponentLineIdx(3, 0)
Lines[LineIdx] += ' %08X' % (TopOffset)
for Fd in FdList:
for Fv in Fd.ChildList:
for Ffs in Fv.ChildList:
LineIdx, LineNum = GetComponentLineIdx(3, FfsIdx)
Index = LineIdx + LineNum
Offset -= Ffs.Length
Offset = AlignPtrDown(Offset)
if Ffs == Fv.ChildList[-1]:
if Fv.Type == 'FV':
Offset -= Ffs.Offset
Lines[Index] = Lines[Index] + ' %08X' % (Offset)
FfsIdx += 1
Lines.insert(0, Header)
print('\n'.join(Lines))
def ReportFd(FvDir, Title, FdNames):
# Parse all xref
Reporter = REPORTER(Title)
Reporter.ParseGuidXrefFile(os.path.join(FvDir, 'Guid.xref'))
Reporter.ParseDscParameter(os.path.join(
os.path.dirname(sys.argv[0]), '../Platform.dsc'))
# Get FVs
FvList = []
for File in os.listdir(FvDir):
if not File.lower().endswith('fv.txt'):
continue
Fv = Reporter.ParseFvTxtFile(os.path.join(FvDir, File))
FvList.append(Fv)
# Get FDs
FdList = []
for File in FdNames:
Fd = Reporter.ParseFdFile(os.path.join(FvDir, File + '.fd'))
if Fd is not None:
FdList.append(Fd)
# Reverse FD/FV/FFS
if True:
FdList.reverse()
for Fd in FdList:
Fd.ChildList.reverse()
for Fv in Fd.ChildList:
Fv.ChildList.reverse()
# Match FV binary into its FV Name/Base
for Fd in FdList:
for FvIndex, Fv1 in enumerate(Fd.ChildList):
if Fv1.Type == 'FSP':
continue
Found = False
for Fv2 in FvList:
if Fv2.Type != Fv1.Type or Fv2.Length != Fv1.Length:
continue
Match = 0
for FfsIndex, Child2 in enumerate(Fv2.ChildList):
for Child1 in Fv1.ChildList:
if Child1.Name == Child2.Name:
Match += 1
break
if Match == FfsIndex + 1:
Found = True
break
if Found:
if Fv1.Base != 0xFFFFFFFF:
Fv1.Base = Fv2.Base
Fv1.Name = Fv2.Name
else:
raise Exception("FV in FD could not be identified !")
if len(FdList):
Reporter.Report(FdList)
print('\n')
def ReportImageLayout(FvDir, ImgPath, ImgList, ImgStart, TopDown):
Name = os.path.splitext(os.path.basename(ImgPath))[0]
Name = Name.upper().replace('_', ' ')
Reporter = REPORTER(Name, 'IMG')
FdList = []
Offset = 0
FfsNum = 0
for Name, Algo, Val, Mode, Pos in ImgList:
BaseName = os.path.splitext(Name)[0]
Fd = IMG_INFO('FD', BaseName)
if Algo:
FileName = BaseName + '.lz'
Compressed = True
else:
FileName = Name
Compressed = False
OrgName = FileName
OrgSize = Val if Name == 'EMPTY' else os.path.getsize(os.path.join(FvDir, FileName))
if OrgSize == 0:
continue
if Mode != STITCH_OPS.MODE_FILE_NOP:
Padded = True
FileName = BaseName + '.pad'
else:
Padded = False
Fd.Offset = Offset
Fd.Length = Val if Name == 'EMPTY' else os.path.getsize(os.path.join(FvDir, FileName))
Offset += Fd.Length
FvName = FileName.replace('.', ',')
Fv = IMG_INFO('FV', FvName)
Fv.Offset = 0
Fv.Length = Fd.Length
FileSize = Fd.Length
OrgSize = AlignPtrUp(OrgSize, 8)
FfsName = OrgName.replace('.', ',')
NameList = [FfsName, 'BLANK']
if Compressed:
NameList[0] = 'Compressed!' + NameList[0]
elif Padded:
pass
else:
del NameList[1]
if NameList is None:
NameList = ['IMAGE', 'BLANK']
if Pos == STITCH_OPS.MODE_POS_HEAD:
if FileSize != OrgSize:
NameList.reverse()
OrgSize = FileSize - OrgSize
for Idx, Name in enumerate(NameList):
if Idx == 0:
Len = OrgSize
Ffs = IMG_INFO('FFS', Name, 0, Len)
else:
Len = FileSize - OrgSize
Ffs = IMG_INFO('FFS', Name, OrgSize, Len)
if Len:
Fv.ChildList.append(Ffs)
FfsNum += 1
Fd.ChildList.append(Fv)
FdList.append(Fd)
FinalSize = os.path.getsize(ImgPath)
if Offset < FinalSize:
Length = FinalSize - Offset
Fd = IMG_INFO('FD', 'BLANK', 0, Length)
Fv = IMG_INFO('FV', 'BLANK', 0, Length)
Ffs = IMG_INFO('FFS', 'BLANK', 0, Length)
Fv.ChildList.append(Ffs)
Fd.ChildList.append(Fv)
if TopDown:
FdList.insert(0, Fd)
else:
FdList.append(Fd)
FfsNum += 1
Base = None
for Fd in FdList:
for Fv in Fd.ChildList:
if Base is None:
if TopDown:
Base = ImgStart - FinalSize
else:
Base = ImgStart
Fv.Base = Base
Base += Fv.Length
# Reverse FD/FV/FFS
FdList.reverse()
for Fd in FdList:
Fd.ChildList.reverse()
for Fv in Fd.ChildList:
Fv.ChildList.reverse()
FfsHeight = 6
MinHeight = len(Reporter.ImgName) + 2
if FfsNum * FfsHeight <= MinHeight:
FfsHeight = (MinHeight + FfsNum - 1) // FfsNum
Reporter.Report(FdList, FfsHeight)
def Usage():
print("Usage: \n\tGenReport FvBuildDir [StitchInput]")
def Main():
if len(sys.argv) < 2:
Usage()
return 1
if len(sys.argv) < 3:
StitchInput = 'ImgStitch.txt'
else:
StitchInput = sys.argv[2]
FvDir = sys.argv[1]
ImgLayoutPath = os.path.join(FvDir, StitchInput)
if not os.path.exists(ImgLayoutPath):
raise Exception("No layout file '%s' found !" % StitchInput)
return 0
FdIn = open(ImgLayoutPath, 'r')
Lines = FdIn.readlines()
FdIn.close()
FdReported = False
FdNames = ['STAGE2', 'STAGE1B', 'STAGE1A']
for Line in Lines:
Line = Line.strip()
Parts = Line.split('=')
if len(Parts) == 2:
if Parts[0].strip() == 'BOARD_INFO':
BrdInfo = ExecAssignment ('BrdInfo', Parts[1])
Title = 'Flash Layout for Board %s' % BrdInfo[0]
Padding = (sum(REPORTER.Cols) - len(Title)) // 2
if Padding < 0:
Padding = 0
print('')
print(' %s%s' % (' ' * Padding, Title))
print(' %s%s' % (' ' * Padding, '=' * len(Title)))
if Parts[0].strip() == 'IMAGE_INFO':
ImgInfo = ExecAssignment ('ImgInfo', Parts[1])
ImgPath = os.path.join(FvDir, ImgInfo[0])
Start = ImgInfo[1]
TopDown = ImgInfo[2]
if not FdReported:
for Name in FdNames:
ReportFd(FvDir, '', [Name])
FdReported = True
elif Parts[0].strip() == 'IMAGE_LIST':
ImgList = ExecAssignment ('ImgList', Parts[1])
ReportImageLayout(FvDir, ImgPath, ImgList, Start, TopDown)
print('\n')
return 0
if __name__ == '__main__':
sys.exit(Main())