1. Add firmware volume need to check firmware volume exist or not. 2. Remove clang version check dependency. Cc: Guo Dong <guo.dong@intel.com> Cc: Sean Rhodes <sean@starlabs.systems> Cc: James Lu <james.lu@intel.com> Cc: Gua Guo <gua.guo@intel.com> Signed-off-by: BruceX Wang <brucex.wang@intel.com> Reviewed-by: Gua Guo <gua.guo@intel.com>
		
			
				
	
	
		
			278 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			278 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
## @file
 | 
						|
# This file is a script to build fit image.
 | 
						|
# It generate a dtb header and combine a binary file after this header.
 | 
						|
#
 | 
						|
# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
 | 
						|
# SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
##
 | 
						|
 | 
						|
from os.path import exists
 | 
						|
import libfdt
 | 
						|
from ctypes import *
 | 
						|
import time
 | 
						|
import os
 | 
						|
 | 
						|
class FIT_IMAGE_INFO_HEADER:
 | 
						|
    """Class for user setting data to use MakeFitImage()
 | 
						|
    """
 | 
						|
    _pack_ = 1
 | 
						|
    _fields_ = [
 | 
						|
        ('Compatible',    str),
 | 
						|
        ('UplVersion',    int),
 | 
						|
        ('Description',   str),
 | 
						|
        ('Type',          str),
 | 
						|
        ('Arch',          str),
 | 
						|
        ('Compression',   str),
 | 
						|
        ('Revision',      int),
 | 
						|
        ('BuildType',     str),
 | 
						|
        ('Capabilities',  str),
 | 
						|
        ('Producer',      str),
 | 
						|
        ('ImageId',       str),
 | 
						|
        ('DataOffset',    int),
 | 
						|
        ('DataSize',      int),
 | 
						|
        ('RelocStart',    int),
 | 
						|
        ('LoadAddr',      int),
 | 
						|
        ('Entry',         int),
 | 
						|
        ('Binary',        str),
 | 
						|
        ('TargetPath',    str),
 | 
						|
        ('UefifvPath',    str),
 | 
						|
        ('BdsfvPath',     str),
 | 
						|
        ('NetworkfvPath', str),
 | 
						|
        ('Project',       str),
 | 
						|
        ]
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.Compatible     = 'universal-payload'
 | 
						|
        self.UplVersion     = 0x0100
 | 
						|
        self.TargetPath     = 'mkimage.fit'
 | 
						|
 | 
						|
def CreatFdt(Fdt):
 | 
						|
    FdtEmptyTree = libfdt.fdt_create_empty_tree(Fdt, len(Fdt))
 | 
						|
    if FdtEmptyTree != 0:
 | 
						|
        print('\n- Failed - Create Fdt failed!')
 | 
						|
        return False
 | 
						|
    return True
 | 
						|
 | 
						|
def BuildConfNode(Fdt, ParentNode, MultiImage):
 | 
						|
    ConfNode1     = libfdt.fdt_add_subnode(Fdt, ParentNode, 'conf-1')
 | 
						|
 | 
						|
    libfdt.fdt_setprop(Fdt, ConfNode1, 'require-fit', b'', 0)
 | 
						|
    libfdt.fdt_setprop(Fdt, ConfNode1, 'firmware', bytes('tianocore', 'utf-8'), len('tianocore') + 1)
 | 
						|
 | 
						|
def BuildFvImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description):
 | 
						|
    libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize)
 | 
						|
    libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset)
 | 
						|
    libfdt.fdt_setprop(Fdt, ParentNode, 'compression', bytes('none',                'utf-8'), len('none') + 1)
 | 
						|
    libfdt.fdt_setprop(Fdt, ParentNode, 'project ',    bytes('tianocore',           'utf-8'), len('tianocore') + 1)
 | 
						|
    libfdt.fdt_setprop(Fdt, ParentNode, 'arch',        bytes('x86_64',              'utf-8'), len('x86_64') + 1)
 | 
						|
    libfdt.fdt_setprop(Fdt, ParentNode, 'type',        bytes('flat-binary',         'utf-8'), len('flat-binary') + 1)
 | 
						|
    libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description,           'utf-8'), len(Description) + 1)
 | 
						|
 | 
						|
def BuildTianoImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description):
 | 
						|
    #
 | 
						|
    # Set 'load' and 'data-offset' to reserve the memory first.
 | 
						|
    # They would be set again when Fdt completes or this function parses target binary file.
 | 
						|
    #
 | 
						|
    if InfoHeader.LoadAddr is not None:
 | 
						|
        libfdt.fdt_setprop_u64(Fdt, ParentNode, 'load', InfoHeader.LoadAddr)
 | 
						|
    if InfoHeader.Entry is not None:
 | 
						|
        libfdt.fdt_setprop_u64(Fdt, ParentNode, 'entry-start', InfoHeader.Entry)
 | 
						|
    if InfoHeader.RelocStart is not None:
 | 
						|
        libfdt.fdt_setprop_u32(Fdt, ParentNode, 'reloc-start', InfoHeader.RelocStart)
 | 
						|
    if InfoHeader.DataSize is not None:
 | 
						|
       libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize)
 | 
						|
    if InfoHeader.DataOffset is not None:
 | 
						|
        libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset)
 | 
						|
    if InfoHeader.Producer is not None:
 | 
						|
        libfdt.fdt_setprop(Fdt, ParentNode, 'producer ', bytes(InfoHeader.Producer, 'utf-8'), len(InfoHeader.Producer) + 1)
 | 
						|
    if InfoHeader.Capabilities is not None:
 | 
						|
        CapStrs = ','.join(InfoHeader.Capabilities)
 | 
						|
        libfdt.fdt_setprop(Fdt, ParentNode, 'capabilities ', bytes(CapStrs, 'utf-8'), len(CapStrs) + 1)
 | 
						|
    if InfoHeader.Type is not None:
 | 
						|
        libfdt.fdt_setprop(Fdt, ParentNode, 'type ', bytes(InfoHeader.Type, 'utf-8'), len(InfoHeader.Type) + 1)
 | 
						|
    if InfoHeader.Arch is not None:
 | 
						|
        libfdt.fdt_setprop(Fdt, ParentNode, 'arch ', bytes(InfoHeader.Arch, 'utf-8'), len(InfoHeader.Arch) + 1)
 | 
						|
    if InfoHeader.Project is not None:
 | 
						|
        libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes(InfoHeader.Project, 'utf-8'), len(InfoHeader.Project) + 1)
 | 
						|
    if InfoHeader.Description is not None:
 | 
						|
        libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1)
 | 
						|
 | 
						|
#
 | 
						|
# The subnode would be inserted from bottom to top of structure block.
 | 
						|
#
 | 
						|
def BuildFitImage(Fdt, InfoHeader):
 | 
						|
    MultiImage = [
 | 
						|
        ["tianocore",   InfoHeader.Binary,        BuildTianoImageNode , InfoHeader.Description,     None, 0 ],
 | 
						|
        ["uefi-fv",     InfoHeader.UefifvPath,    BuildFvImageNode,     "UEFI Firmware Volume",     None, 0 ],
 | 
						|
        ["bds-fv",      InfoHeader.BdsfvPath,     BuildFvImageNode ,    "BDS Firmware Volume",      None, 0 ],
 | 
						|
        ["network-fv",  InfoHeader.NetworkfvPath, BuildFvImageNode ,    "Network Firmware Volume",  None, 0 ],
 | 
						|
    ]
 | 
						|
 | 
						|
    #
 | 
						|
    # Set basic information
 | 
						|
    #
 | 
						|
    libfdt.fdt_setprop_u32(Fdt, 0, 'build-revision ', InfoHeader.Revision)
 | 
						|
    libfdt.fdt_setprop_u32(Fdt, 0, 'spec-version', InfoHeader.UplVersion)
 | 
						|
 | 
						|
    #
 | 
						|
    # Build configurations node
 | 
						|
    #
 | 
						|
    ConfNode  = libfdt.fdt_add_subnode(Fdt, 0, 'configurations')
 | 
						|
    BuildConfNode(Fdt, ConfNode, MultiImage)
 | 
						|
 | 
						|
    # Build image
 | 
						|
    DataOffset = InfoHeader.DataOffset
 | 
						|
    for Index in range (0, len (MultiImage)):
 | 
						|
        _, Path, _, _, _, _ = MultiImage[Index]
 | 
						|
        if exists(Path) == 1:
 | 
						|
            TempBinary = open(Path, 'rb')
 | 
						|
            BinaryData = TempBinary.read()
 | 
						|
            TempBinary.close()
 | 
						|
            MultiImage[Index][-2] = BinaryData
 | 
						|
            MultiImage[Index][-1] = DataOffset
 | 
						|
            DataOffset += len (BinaryData)
 | 
						|
    libfdt.fdt_setprop_u32(Fdt, 0, 'size', DataOffset)
 | 
						|
    posix_time = int(time.time())
 | 
						|
    libfdt.fdt_setprop_u32(Fdt, 0, 'timestamp', posix_time)
 | 
						|
    DescriptionFit = 'Uefi OS Loader'
 | 
						|
    libfdt.fdt_setprop(Fdt, 0, 'description', bytes(DescriptionFit, 'utf-8'), len(DescriptionFit) + 1)
 | 
						|
 | 
						|
    ImageNode = libfdt.fdt_add_subnode(Fdt, 0, 'images')
 | 
						|
    for Item in reversed (MultiImage):
 | 
						|
        Name, Path, BuildFvNode, Description, BinaryData, DataOffset = Item
 | 
						|
        if os.path.exists (Item[1]) == False:
 | 
						|
            continue
 | 
						|
        FvNode = libfdt.fdt_add_subnode(Fdt, ImageNode, Name)
 | 
						|
        BuildFvNode (Fdt, InfoHeader, FvNode, DataOffset, len(BinaryData), Description)
 | 
						|
 | 
						|
    #
 | 
						|
    # Create new image file and combine all binary.
 | 
						|
    #
 | 
						|
    DtbFile = open(InfoHeader.TargetPath, "wb")
 | 
						|
    DtbFile.truncate()
 | 
						|
    DtbFile.write(Fdt)
 | 
						|
    for Item in MultiImage:
 | 
						|
        _, FilePath, _, _, BinaryData, _ = Item
 | 
						|
        if os.path.exists (Item[1]) == False:
 | 
						|
            continue
 | 
						|
        DtbFile.write(BinaryData)
 | 
						|
    DtbFile.close()
 | 
						|
 | 
						|
    return True
 | 
						|
 | 
						|
def MakeFitImage(InfoHeader):
 | 
						|
    #
 | 
						|
    # Allocate fdt byte array.
 | 
						|
    #
 | 
						|
    Fdt = bytearray(InfoHeader.DataOffset)
 | 
						|
 | 
						|
    #
 | 
						|
    # Create fdt empty tree.
 | 
						|
    #
 | 
						|
    if CreatFdt(Fdt) is False:
 | 
						|
        return False
 | 
						|
 | 
						|
    #
 | 
						|
    # Parse args to build fit image.
 | 
						|
    #
 | 
						|
    return BuildFitImage(Fdt, InfoHeader)
 | 
						|
 | 
						|
def ReplaceFv (UplBinary, SectionFvFile, SectionName):
 | 
						|
    try:
 | 
						|
        #
 | 
						|
        # Get Original Multi Fv
 | 
						|
        #
 | 
						|
        with open (UplBinary, "rb") as File:
 | 
						|
            Dtb = File.read ()
 | 
						|
        Fit          = libfdt.Fdt (Dtb)
 | 
						|
        NewFitHeader = bytearray(Dtb[0:Fit.totalsize()])
 | 
						|
        FitSize      = len(Dtb)
 | 
						|
 | 
						|
        LoadablesList = []
 | 
						|
        ImagesNode    = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images')
 | 
						|
        FvNode        = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'uefi-fv')
 | 
						|
        NodeDepth     = libfdt.fdt_node_depth (NewFitHeader, ImagesNode)
 | 
						|
        node_name     = libfdt.fdt_get_name(NewFitHeader, FvNode)
 | 
						|
        FvNode        = libfdt.fdt_next_node(NewFitHeader, FvNode, NodeDepth)
 | 
						|
 | 
						|
        while node_name[0][-2:] == 'fv':
 | 
						|
            LoadablesList.append (node_name[0])
 | 
						|
            node_name = libfdt.fdt_get_name(NewFitHeader, FvNode[0])
 | 
						|
            FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode[0], NodeDepth)
 | 
						|
        #
 | 
						|
        # Get current Fit Binary FV data
 | 
						|
        #
 | 
						|
        MultiFvList = []
 | 
						|
        for Item in LoadablesList:
 | 
						|
            ImageNode    = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, Item)
 | 
						|
            ImageOffset  = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
 | 
						|
            ImageSize    = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big')
 | 
						|
            MultiFvList.append ([Item, Dtb[ImageOffset:ImageOffset + ImageSize]])
 | 
						|
 | 
						|
        IsFvExist = False
 | 
						|
        for Index in range (0, len (MultiFvList)):
 | 
						|
            if MultiFvList[Index][0] == SectionName:
 | 
						|
                with open (SectionFvFile, 'rb') as File:
 | 
						|
                    MultiFvList[Index][1] = File.read ()
 | 
						|
                ImageNode     = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, SectionName)
 | 
						|
                ImageSize     = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big')
 | 
						|
                ReplaceOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
 | 
						|
                OffsetDelta   = len(MultiFvList[Index][1]) - ImageSize
 | 
						|
                FitSize      += OffsetDelta
 | 
						|
                IsFvExist     = True
 | 
						|
                libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-size', len(MultiFvList[Index][1]))
 | 
						|
 | 
						|
        #
 | 
						|
        # Update new fit header
 | 
						|
        #
 | 
						|
        ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images')
 | 
						|
        if (IsFvExist == False):
 | 
						|
            with open (SectionFvFile, 'rb') as File:
 | 
						|
                SectionFvFileBinary = File.read ()
 | 
						|
            MultiFvList.append ([SectionName, SectionFvFileBinary])
 | 
						|
            FvNode = libfdt.fdt_add_subnode(NewFitHeader, ImagesNode, SectionName)
 | 
						|
            BuildFvImageNode (NewFitHeader, None, FvNode, FitSize, len(SectionFvFileBinary), SectionName + " Firmware Volume")
 | 
						|
            FitSize += len(SectionFvFileBinary)
 | 
						|
        else:
 | 
						|
            for Index in range (0, len (MultiFvList)):
 | 
						|
                ImageNode    = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0])
 | 
						|
                ImageOffset  = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
 | 
						|
                if ImageOffset > ReplaceOffset:
 | 
						|
                    libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-offset', ImageOffset + OffsetDelta)
 | 
						|
 | 
						|
        ConfNodes     = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'configurations')
 | 
						|
        libfdt.fdt_setprop(NewFitHeader, ConfNodes, 'default ', bytes('conf-1', 'utf-8'), len('conf-1') + 1)
 | 
						|
        ConfNode      = libfdt.fdt_subnode_offset(NewFitHeader, ConfNodes, 'conf-1')
 | 
						|
 | 
						|
        libfdt.fdt_setprop_u32(NewFitHeader, 0, 'size', FitSize)
 | 
						|
 | 
						|
        #
 | 
						|
        # Generate new fit image
 | 
						|
        #
 | 
						|
        ImagesNode    = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images')
 | 
						|
        TianoNode     = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'tianocore')
 | 
						|
        TianoOffset   = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-offset')[0], 'big')
 | 
						|
        TianoSize     = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-size')[0], 'big')
 | 
						|
        TianoBinary   = Dtb[TianoOffset:TianoOffset + TianoSize]
 | 
						|
 | 
						|
        print("\nGenerate new fit image:")
 | 
						|
        NewUplBinary = bytearray(FitSize)
 | 
						|
        print("Update fit header\t to 0x0\t\t ~ " + str(hex(len(NewFitHeader))))
 | 
						|
        NewUplBinary[:len(NewFitHeader)] = NewFitHeader
 | 
						|
        print("Update tiano image\t to " + str(hex(len(NewFitHeader))) + "\t ~ " + str(hex(len(NewFitHeader) + len(TianoBinary))))
 | 
						|
        NewUplBinary[len(NewFitHeader):len(NewFitHeader) + len(TianoBinary)] = TianoBinary
 | 
						|
        for Index in range (0, len (MultiFvList)):
 | 
						|
            ImageNode   = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0])
 | 
						|
            ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
 | 
						|
            ImageSize   = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big')
 | 
						|
            NewUplBinary[ImageOffset:ImageOffset + ImageSize] = MultiFvList[Index][1]
 | 
						|
            print("Update " + MultiFvList[Index][0] + "\t\t to " + str(hex(ImageOffset)) + "\t ~ " + str(hex(ImageOffset + ImageSize)))
 | 
						|
 | 
						|
        with open (UplBinary, "wb") as File:
 | 
						|
            File.write (NewUplBinary)
 | 
						|
 | 
						|
        return 0
 | 
						|
    except Exception as Ex:
 | 
						|
        print(Ex)
 | 
						|
        return 1
 |