summaryrefslogtreecommitdiff
path: root/Platform/Qemu/RiscVServerRef/Feature/Capsule/GenerateCapsule
diff options
context:
space:
mode:
Diffstat (limited to 'Platform/Qemu/RiscVServerRef/Feature/Capsule/GenerateCapsule')
-rw-r--r--Platform/Qemu/RiscVServerRef/Feature/Capsule/GenerateCapsule/GenCapsule.py354
1 files changed, 354 insertions, 0 deletions
diff --git a/Platform/Qemu/RiscVServerRef/Feature/Capsule/GenerateCapsule/GenCapsule.py b/Platform/Qemu/RiscVServerRef/Feature/Capsule/GenerateCapsule/GenCapsule.py
new file mode 100644
index 0000000000..ca64a0a430
--- /dev/null
+++ b/Platform/Qemu/RiscVServerRef/Feature/Capsule/GenerateCapsule/GenCapsule.py
@@ -0,0 +1,354 @@
+## @file
+# Generate capsules for RiscVVirt platform
+# openssl, gcab must be install and in path
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+'''
+GenCapsuleAll
+'''
+
+import os
+import sys
+import argparse
+import subprocess
+import glob
+import shutil
+import struct
+import datetime
+
+#
+# Globals for help information
+#
+__prog__ = 'GenCapsuleAll'
+__copyright__ = 'Copyright (c) 2019, Intel Corporation. All rights reserved.'
+__description__ = 'Generate RiscVVirt capsules.\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)
+
+GenerateCapsuleCommand = '''
+GenerateCapsule
+--encode
+--guid {FMP_CAPSULE_GUID}
+--fw-version {FMP_CAPSULE_VERSION}
+--lsv {FMP_CAPSULE_LSV}
+--signer-private-cert={BASE_TOOLS_PATH}/Source/Python/Pkcs7Sign/TestCert.pem
+--other-public-cert={BASE_TOOLS_PATH}/Source/Python/Pkcs7Sign/TestSub.pub.pem
+--trusted-public-cert={BASE_TOOLS_PATH}/Source/Python/Pkcs7Sign/TestRoot.pub.pem
+-o {FMP_CAPSULE_FILE}
+{FMP_CAPSULE_PAYLOAD}
+'''
+MetaInfoXmlTemplate = '''
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="firmware">
+ <id>com.intel.FMP_CAPSULE_BASE_NAME.firmware</id>
+ <name>FMP_CAPSULE_BASE_NAME</name>
+ <summary>System firmware for the FMP_CAPSULE_BASE_NAME</summary>
+ <description>
+ Description of System firmware for the FMP_CAPSULE_BASE_NAME
+ </description>
+ <provides>
+ <firmware type="flashed">FMP_CAPSULE_GUID</firmware>
+ </provides>
+ <url type="homepage">http://www.tianocore.org</url>
+ <metadata_license>CC0-1.0</metadata_license>
+ <project_license>BSD</project_license>
+ <developer_name>Tianocore</developer_name>
+ <releases>
+ <release version="FMP_CAPSULE_VERSION_DECIMAL" date="FMP_CAPSULE_DATE">
+ <description>
+ Build FMP_CAPSULE_STRING
+ </description>
+ </release>
+ </releases>
+ <!-- most OEMs do not need to do this... -->
+ <custom>
+ <value key="LVFS::InhibitDownload"/>
+ </custom>
+</component>
+'''
+
+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 (FmpCapsuleFile, (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()
+
+ Log ('openssl, gcab must be install and in path')
+
+ 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, 'firmware.metainfo.xml'))
+ RemoveFile ((CapsulesPath, 'firmware.bin'))
+
+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, AARCH64, RISCV64
+ 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
+ #
+ for Path in PathList:
+ if os.path.exists (os.path.join (Path, 'BaseTools')):
+ gBaseToolsPath = os.path.join (Path, 'BaseTools')
+ break
+
+ #
+ # Parse PLATFORM_NAME 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('PLATFORM_NAME'):
+ OutputDirectory = os.path.join ('Build', 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 ['RISCV64'] in gArgs.Arch:
+ UefiArch = 'RISCV64'
+
+ CapsulesPath = NormalizePath((EdkiiBuildDir, 'Capsules'))
+
+ CapsulesSubDir = 'TestCert' + '_' + UefiArch + '_' + gArgs.BuildTarget + '_' + gArgs.ToolChain
+
+ #
+ # Create output directories
+ #
+ try:
+ CreateDirectory ((CapsulesPath))
+ except:
+ pass
+ try:
+ CreateDirectory ((CapsulesPath, CapsulesSubDir))
+ except:
+ pass
+
+ #
+ # Copy CapsuleApp
+ #
+ Copy ((EdkiiBuildOutput, UefiArch, 'CapsuleApp.efi'), (CapsulesPath, CapsulesSubDir))
+
+ # Default firmware revision and LSV(LowestSupportedVersion)
+ FwRevision = 0x00010000
+ Lsv = 0x00000000
+
+ # Override from -D FIRMWARE_REVISION= / -D LSV= if provided
+ if gArgs.Define:
+ for define_group in gArgs.Define:
+ for item in define_group:
+ if '=' in item:
+ name, val = item.split('=', 1)
+ name = name.strip()
+ val = val.strip()
+ try:
+ if name == 'FIRMWARE_REVISION':
+ FwRevision = int(val, 0)
+ elif name == 'LSV':
+ Lsv = int(val, 0)
+ except ValueError:
+ Error('Invalid %s value: %s' % (name, val))
+
+ #
+ # Generate capsules for RiscVVirt Firmware Updates
+ #
+ CodeFW = os.path.join (EdkiiBuildOutput, 'FV', 'RISCV_SERVER_REF_CODE.fd')
+ GenCapsuleDevice('RISCVSERREF', CodeFW, '8f7a3c21-6d9e-4b85-a2f1-c7e934d1e6ab', FwRevision, Lsv, CapsulesPath, CapsulesSubDir)