slimbootloader/BootloaderCorePkg/Tools/GenReport.py

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())