## @file
|
# PreBuild operations for Vlv2TbltDevicePkg
|
#
|
# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
|
#
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
#
|
|
'''
|
PreBuild
|
'''
|
|
import os
|
import sys
|
import argparse
|
import subprocess
|
import glob
|
import shutil
|
import struct
|
import datetime
|
|
#
|
# Globals for help information
|
#
|
__prog__ = 'PreBuild'
|
__copyright__ = 'Copyright (c) 2019, Intel Corporation. All rights reserved.'
|
__description__ = 'Vlv2Tbl2DevicePkg pre-build operations.\n'
|
|
#
|
# Globals
|
#
|
gWorkspace = ''
|
gBaseToolsPath = ''
|
gArgs = None
|
|
def LogAlways(Message):
|
sys.stdout.write (__prog__ + ': ' + Message + '\n')
|
sys.stdout.flush()
|
|
def Log(Message):
|
global gArgs
|
if not gArgs.Verbose:
|
return
|
sys.stdout.write (__prog__ + ': ' + Message + '\n')
|
sys.stdout.flush()
|
|
def Error(Message, ExitValue=1):
|
sys.stderr.write (__prog__ + ': ERROR: ' + Message + '\n')
|
sys.exit (ExitValue)
|
|
def RelativePath(target):
|
global gWorkspace
|
Log('RelativePath' + target)
|
return os.path.relpath (target, gWorkspace)
|
|
def NormalizePath(target):
|
if isinstance(target, tuple):
|
return os.path.normpath (os.path.join (*target))
|
else:
|
return os.path.normpath (target)
|
|
def RemoveFile(target):
|
target = NormalizePath(target)
|
if not target or target == os.pathsep:
|
Error ('RemoveFile() invalid target')
|
if os.path.exists(target):
|
os.remove (target)
|
Log ('remove %s' % (RelativePath (target)))
|
|
def RemoveDirectory(target):
|
target = NormalizePath(target)
|
if not target or target == os.pathsep:
|
Error ('RemoveDirectory() invalid target')
|
if os.path.exists(target):
|
Log ('rmdir %s' % (RelativePath (target)))
|
shutil.rmtree(target)
|
|
def CreateDirectory(target):
|
target = NormalizePath(target)
|
if not os.path.exists(target):
|
Log ('mkdir %s' % (RelativePath (target)))
|
os.makedirs (target)
|
|
def Copy(src, dst):
|
src = NormalizePath(src)
|
dst = NormalizePath(dst)
|
for File in glob.glob(src):
|
Log ('copy %s -> %s' % (RelativePath (File), RelativePath (dst)))
|
shutil.copy (File, dst)
|
|
def GenCapsuleDevice (BaseName, PayloadFileName, Guid, Version, Lsv, CapsulesPath, CapsulesSubDir):
|
global gBaseToolsPath
|
LogAlways ('Generate Capsule: {0} {1:08x} {2:08x} {3}'.format (Guid, Version, Lsv, PayloadFileName))
|
|
VersionString = '.'.join([str(ord(x)) for x in struct.pack('>I', Version).decode()])
|
|
FmpCapsuleFile = NormalizePath ((CapsulesPath, CapsulesSubDir, BaseName + '.' + VersionString + '.cap'))
|
Command = GenerateCapsuleCommand.format (
|
FMP_CAPSULE_GUID = Guid,
|
FMP_CAPSULE_VERSION = Version,
|
FMP_CAPSULE_LSV = Lsv,
|
BASE_TOOLS_PATH = gBaseToolsPath,
|
FMP_CAPSULE_FILE = FmpCapsuleFile,
|
FMP_CAPSULE_PAYLOAD = PayloadFileName
|
)
|
Command = ' '.join(Command.splitlines()).strip()
|
if gArgs.Verbose:
|
Command = Command + ' -v'
|
|
Log (Command)
|
|
Process = subprocess.Popen(Command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
ProcessOutput = Process.communicate()
|
|
if Process.returncode == 0:
|
Log (ProcessOutput[0].decode())
|
else:
|
LogAlways (Command)
|
LogAlways (ProcessOutput[0].decode())
|
Error ('GenerateCapsule returned an error')
|
|
Copy (PayloadFileName, (CapsulesPath, 'firmware.bin'))
|
MetaInfoXml = MetaInfoXmlTemplate
|
MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_GUID', Guid)
|
MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_BASE_NAME', BaseName)
|
MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_VERSION_DECIMAL', str(Version))
|
MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_STRING', VersionString)
|
MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_DATE', str(datetime.date.today()))
|
f = open (NormalizePath ((CapsulesPath, 'firmware.metainfo.xml')), 'w')
|
f.write(MetaInfoXml)
|
f.close()
|
|
f = open (NormalizePath ((CapsulesPath, 'Lvfs.ddf')), 'w')
|
f.write(LvfsDdfTemplate)
|
f.close()
|
|
if sys.platform == "win32":
|
Command = 'makecab /f ' + NormalizePath ((CapsulesPath, 'Lvfs.ddf'))
|
else:
|
Command = 'gcab --create firmware.cab firmware.bin firmware.metainfo.xml'
|
Log (Command)
|
|
Process = subprocess.Popen(Command, cwd=CapsulesPath, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
ProcessOutput = Process.communicate()
|
|
if Process.returncode == 0:
|
Log (ProcessOutput[0].decode())
|
else:
|
LogAlways (Command)
|
LogAlways (ProcessOutput[0].decode())
|
Error ('GenerateCapsule returned an error')
|
|
FmpCabinetFile = NormalizePath ((CapsulesPath, CapsulesSubDir, BaseName + '.' + VersionString + '.cab'))
|
|
Copy ((CapsulesPath, 'firmware.cab'), FmpCabinetFile)
|
|
RemoveFile ((CapsulesPath, 'firmware.cab'))
|
RemoveFile ((CapsulesPath, 'setup.inf'))
|
RemoveFile ((CapsulesPath, 'setup.rpt'))
|
RemoveFile ((CapsulesPath, 'Lvfs.ddf'))
|
RemoveFile ((CapsulesPath, 'firmware.metainfo.xml'))
|
RemoveFile ((CapsulesPath, 'firmware.bin'))
|
|
BiosIdTemplate = '''
|
BOARD_ID = MNW2MAX
|
BOARD_REV = $BOARD_REV
|
BOARD_EXT = $ARCH
|
VERSION_MAJOR = 0090
|
BUILD_TYPE = $BUILD_TYPE
|
VERSION_MINOR = 01
|
'''
|
|
|
if __name__ == '__main__':
|
#
|
# Create command line argument parser object
|
#
|
parser = argparse.ArgumentParser (
|
prog = __prog__,
|
description = __description__ + __copyright__,
|
conflict_handler = 'resolve'
|
)
|
parser.add_argument (
|
'-a', '--arch', dest = 'Arch', nargs = '+', action = 'append',
|
required = True,
|
help = '''ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC,
|
which overrides target.txt's TARGET_ARCH definition. To
|
specify more archs, please repeat this option.'''
|
)
|
parser.add_argument (
|
'-t', '--tagname', dest = 'ToolChain', required = True,
|
help = '''Using the Tool Chain Tagname to build the platform,
|
overriding target.txt's TOOL_CHAIN_TAG definition.'''
|
)
|
parser.add_argument (
|
'-p', '--platform', dest = 'PlatformFile', required = True,
|
help = '''Build the platform specified by the DSC file name argument,
|
overriding target.txt's ACTIVE_PLATFORM definition.'''
|
)
|
parser.add_argument (
|
'-b', '--buildtarget', dest = 'BuildTarget', required = True,
|
help = '''Using the TARGET to build the platform, overriding
|
target.txt's TARGET definition.'''
|
)
|
parser.add_argument (
|
'--conf=', dest = 'ConfDirectory', required = True,
|
help = '''Specify the customized Conf directory.'''
|
)
|
parser.add_argument (
|
'-D', '--define', dest = 'Define', nargs='*', action = 'append',
|
help = '''Macro: "Name [= Value]".'''
|
)
|
parser.add_argument (
|
'-v', '--verbose', dest = 'Verbose', action = 'store_true',
|
help = '''Turn on verbose output with informational messages printed'''
|
)
|
parser.add_argument (
|
'--package', dest = 'Package', nargs = '*', action = 'append',
|
help = '''The directory name of a package of tests to copy'''
|
)
|
|
#
|
# Parse command line arguments
|
#
|
gArgs, remaining = parser.parse_known_args()
|
gArgs.BuildType = 'all'
|
for BuildType in ['all', 'fds', 'genc', 'genmake', 'clean', 'cleanall', 'modules', 'libraries', 'run']:
|
if BuildType in remaining:
|
gArgs.BuildType = BuildType
|
remaining.remove(BuildType)
|
break
|
gArgs.Remaining = ' '.join(remaining)
|
|
#
|
# Get WORKSPACE environment variable
|
#
|
try:
|
gWorkspace = os.environ['WORKSPACE']
|
except:
|
Error ('WORKSPACE environment variable not set')
|
|
#
|
# Get PACKAGES_PATH and generate prioritized list of paths
|
#
|
PathList = [gWorkspace]
|
try:
|
PathList += os.environ['PACKAGES_PATH'].split(os.pathsep)
|
except:
|
pass
|
|
#
|
# Determine full path to BaseTools
|
#
|
Vlv2Tbl2DevicePkgPath = ''
|
for Path in PathList:
|
if gBaseToolsPath == '':
|
if os.path.exists (os.path.join (Path, 'BaseTools')):
|
gBaseToolsPath = os.path.join (Path, 'BaseTools')
|
if Vlv2Tbl2DevicePkgPath == '':
|
if os.path.exists (os.path.join (Path, 'Vlv2TbltDevicePkg')):
|
Vlv2Tbl2DevicePkgPath = os.path.join (Path, 'Vlv2TbltDevicePkg')
|
if gBaseToolsPath == '':
|
Error ('Can not find BaseTools in WORKSPACE or PACKAGES_PATH')
|
if Vlv2Tbl2DevicePkgPath == '':
|
Error ('Can not find Vlv2Tbl2DevicePkg in WORKSPACE or PACKAGES_PATH')
|
|
#
|
# Parse OUTPUT_DIRECTORY from DSC file
|
#
|
for Path in PathList:
|
if os.path.exists (os.path.join (Path, gArgs.PlatformFile)):
|
Dsc = open (os.path.join (Path, gArgs.PlatformFile), 'r').readlines()
|
break
|
for Line in Dsc:
|
if Line.strip().startswith('OUTPUT_DIRECTORY'):
|
OutputDirectory = Line.strip().split('=')[1].strip()
|
break
|
|
#
|
# Determine full paths to EDK II build directory, EDK II build output
|
# directory and the CPU arch of the UEFI phase.
|
#
|
CommandDir = os.path.dirname(sys.argv[0])
|
EdkiiBuildDir = os.path.join (gWorkspace, OutputDirectory)
|
EdkiiBuildOutput = os.path.join (EdkiiBuildDir, gArgs.BuildTarget + '_' + gArgs.ToolChain)
|
UefiArch = gArgs.Arch[0][0]
|
if len (gArgs.Arch) > 1:
|
if ['X64'] in gArgs.Arch:
|
UefiArch = 'X64'
|
|
if gArgs.BuildType == 'run':
|
Error ("'run' target not supported")
|
if gArgs.BuildType == 'clean':
|
sys.exit (0)
|
|
#
|
# Create output directories to put BiosId files
|
#
|
try:
|
CreateDirectory ((gWorkspace, 'Build'))
|
except:
|
pass
|
try:
|
CreateDirectory ((EdkiiBuildDir))
|
except:
|
pass
|
try:
|
CreateDirectory ((EdkiiBuildOutput))
|
except:
|
pass
|
|
#
|
# Generate BiosId files
|
#
|
BiosId = BiosIdTemplate
|
if sys.platform == "win32":
|
# Built from a Windows Host OS
|
BiosId = BiosId.replace ('$BOARD_REV', 'W')
|
else:
|
# Built from a Linux/Unix/Mac Host OS
|
BiosId = BiosId.replace ('$BOARD_REV', 'L')
|
if UefiArch == 'X64':
|
BiosId = BiosId.replace ('$ARCH', 'X64')
|
else:
|
BiosId = BiosId.replace ('$ARCH', 'I32')
|
BiosId = BiosId.replace ('$BUILD_TYPE', gArgs.BuildTarget[0])
|
|
BiosIdFileName = NormalizePath ((EdkiiBuildOutput, 'BiosId.env'))
|
f = open (BiosIdFileName, 'w')
|
f.write(BiosId)
|
f.close()
|
|
Command = 'python ' + NormalizePath ((Vlv2Tbl2DevicePkgPath, '../Tools/GenBiosId/GenBiosId.py'))
|
Command = Command + ' -i ' + BiosIdFileName
|
Command = Command + ' -o ' + NormalizePath ((EdkiiBuildOutput, 'BiosId.bin'))
|
Command = Command + ' -ot ' + NormalizePath ((EdkiiBuildOutput, 'BiosId.txt'))
|
|
LogAlways (Command)
|
|
Process = subprocess.Popen(Command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
ProcessOutput = Process.communicate()
|
|
if Process.returncode == 0:
|
Log (ProcessOutput[0].decode())
|
else:
|
LogAlways (Command)
|
LogAlways (ProcessOutput[0].decode())
|
Error ('GenBiosId returned an error')
|