From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 134.134.136.100, mailfrom: bob.c.feng@intel.com) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by groups.io with SMTP; Mon, 10 Jun 2019 18:36:42 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 10 Jun 2019 18:36:41 -0700 X-ExtLoop1: 1 Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201]) by fmsmga007.fm.intel.com with ESMTP; 10 Jun 2019 18:36:41 -0700 Received: from fmsmsx125.amr.corp.intel.com (10.18.125.40) by FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS) id 14.3.408.0; Mon, 10 Jun 2019 18:36:41 -0700 Received: from shsmsx102.ccr.corp.intel.com (10.239.4.154) by FMSMSX125.amr.corp.intel.com (10.18.125.40) with Microsoft SMTP Server (TLS) id 14.3.408.0; Mon, 10 Jun 2019 18:36:40 -0700 Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.10]) by shsmsx102.ccr.corp.intel.com ([169.254.2.134]) with mapi id 14.03.0415.000; Tue, 11 Jun 2019 09:36:39 +0800 From: "Bob Feng" To: "Jin, Eric" , "devel@edk2.groups.io" CC: "Gao, Liming" , "Kinney, Michael D" Subject: Re: [PATCH v2 1/1] BaseTools/Capsule: Tool to Generate Windows Firmware Update Driver Thread-Topic: [PATCH v2 1/1] BaseTools/Capsule: Tool to Generate Windows Firmware Update Driver Thread-Index: AQHVGb37zcDyt8LM0kO9SW+HWS5hCqaVtOnw Date: Tue, 11 Jun 2019 01:36:38 +0000 Message-ID: <08650203BA1BD64D8AD9B6D5D74A85D16013540D@SHSMSX101.ccr.corp.intel.com> References: <20190603033923.15280-1-eric.jin@intel.com> In-Reply-To: <20190603033923.15280-1-eric.jin@intel.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Return-Path: bob.c.feng@intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi Eric, There are 2 comments on the code. + if(capture): + outr =3D PropagatingThread(target=3Dreader, args=3D(outfile, outst= ream, c.stdout,)) + outr.start() + outr.join() + c.wait() + else: + c.wait() c.wait() in both "if" and "else" block, I think it should be just called on= ce out of the if...else block. + def CapsuleGuidCheck(InputFile, Guid): + TempCapDecode =3D 'TempCapDecode.txt' + Command =3D 'python GenerateCapsule.py "' + InputFile + '" --dump-= info >' + TempCapDecode + os.system (Command) + with open(TempCapDecode, 'rb') as f: + for line in f: + if re.search(b'UpdateImageTypeId', line, re.M|re.I): + CapGuid =3D str(line).split('=3D ')[1][:-5] + break + f.close() + os.remove(TempCapDecode) + if (Guid !=3D CapGuid): + print('GenerateWindowsDriver error: Different Guid from Ca= psule') + sys.exit(1) f.close() is not necessary and I think the statements after f.close() shoul= d be out of the "with" block. Thanks, Bob -----Original Message----- From: Jin, Eric=20 Sent: Monday, June 3, 2019 11:39 AM To: devel@edk2.groups.io Cc: Feng, Bob C ; Gao, Liming ;= Kinney, Michael D Subject: [PATCH v2 1/1] BaseTools/Capsule: Tool to Generate Windows Firmwar= e Update Driver https://bugzilla.tianocore.org/show_bug.cgi?id=3D1837 The tool is designed to generate Windows Firmware Update Drivers, the input= is one drivername.cap with related parameters, the output Windows Driver p= ackage are composed by drivername.cap, drivername.inf and drivername.cat to= update the single payload in device. usage: GenerateWindowsDriver [-h] [--output-folder OUTPUTFOLDER] [--product-fmp-guid PRODUCTFMPGUID] [--capsuleversion-dotstring CAPSULEVERSION_DOTSTRING] [--capsuleversion-hexstring CAPSULEVERSION_HEXSTRING] [--product-fw-provider PRODUCTFWPROVIDER] [--product-fw-mfg-name PRODUCTFWMFGNAME] [--product-fw-desc PRODUCTFWDESC] [--capsule-file-name CAPSULEFILENAME] [--pfx-file PFXFILE] [--arch ARCH] [--operating-system-string OPERATINGSYSTEMSTRING] Cc: Bob Feng Cc: Liming Gao Cc: Kinney Michael D Signed-off-by: Eric Jin --- BaseTools/Source/Python/Capsule/CatGenerator.py | 161 +++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++ BaseTools/Source/Python/Capsule/GenerateWindowsDriver.py | 115 +++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++ BaseTools/Source/Python/Capsule/InfGenerator.py | 210 +++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++ BaseTools/Source/Python/Capsule/WindowsCapsuleSupportHelper.py | 102 +++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++ 4 files changed, 588 insertions(+) diff --git a/BaseTools/Source/Python/Capsule/CatGenerator.py b/BaseTools/So= urce/Python/Capsule/CatGenerator.py new file mode 100644 index 0000000000..77956d331d --- /dev/null +++ b/BaseTools/Source/Python/Capsule/CatGenerator.py @@ -0,0 +1,161 @@ +## @file + # Script to generate Cat files for capsule update based on supplied=20 +inf file # # Copyright (c) 2019, Microsoft Corporation # Copyright=20 +(c) 2019, Intel Corporation. All rights reserved.
#=20 +SPDX-License-Identifier: BSD-2-Clause-Patent # ## + +import os +import logging +import datetime +import subprocess +import threading + +class PropagatingThread(threading.Thread): + def run(self): + self.exc =3D None + try: + if hasattr(self, '_Thread__target'): + # Thread uses name mangling prior to Python 3. + self.ret =3D self._Thread__target(*self._Thread__args, **s= elf._Thread__kwargs) + else: + self.ret =3D self._target(*self._args, **self._kwargs) + except BaseException as e: + self.exc =3D e + def join(self, timeout=3DNone): + super(PropagatingThread, self).join() + if self.exc: + raise self.exc + return self.ret +def reader(filepath, outstream, stream): + if filepath: + try: + with open(filepath, "w") as f: + print("The file is" + filepath) + except FileNotFoundError: + print("Sorry, the file" + filepath + "does not exist.") + + while True: + s =3D stream.readline().decode() + if not s: + stream.close() + break + # write to file if caller provideds file + if filepath: + try: + with open(filepath, "a") as f: + f.write(s) + except FileNotFoundError: + print("Sorry, the file" + filepath + "does not exist.") + if(outstream is not None): + # write to stream object if caller provided object + outstream.write(s) + logging.info(s.rstrip()) + +def RunCmd(cmd, parameters, capture=3DTrue, workingdir=3DNone, outfile=3DN= one, outstream=3DNone, environ=3DNone): + cmd =3D cmd.strip('"\'') + if " " in cmd: + cmd =3D '"' + cmd + '"' + if parameters is not None: + parameters =3D parameters.strip() + cmd +=3D " " + parameters + starttime =3D datetime.datetime.now() + logging.info("Cmd to run is: " + cmd) + logging.info("------------------------------------------------") + logging.info("--------------Cmd Output Starting---------------") + logging.info("------------------------------------------------") + c =3D subprocess.Popen(cmd, stdout=3Dsubprocess.PIPE, stderr=3Dsubproc= ess.STDOUT, cwd=3Dworkingdir, shell=3DTrue, env=3Denviron) + if(capture): + outr =3D PropagatingThread(target=3Dreader, args=3D(outfile, outst= ream, c.stdout,)) + outr.start() + outr.join() + c.wait() + else: + c.wait() + + endtime =3D datetime.datetime.now() + delta =3D endtime - starttime + logging.info("------------------------------------------------") + logging.info("--------------Cmd Output Finished---------------") + logging.info("--------- Running Time (mm:ss): {0[0]:02}:{0[1]:02} ----= ------".format(divmod(delta.seconds, 60))) + logging.info("------------------------------------------------") + return c.returncode + +class CatGenerator(object): + SUPPORTED_OS =3D {'win10': '10', + '10': '10', + '10_au': '10_AU', + '10_rs2': '10_RS2', + '10_rs3': '10_RS3', + '10_rs4': '10_RS4', + 'server10': 'Server10', + 'server2016': 'Server2016', + 'serverrs2': 'ServerRS2', + 'serverrs3': 'ServerRS3', + 'serverrs4': 'ServerRS4' + } + + def __init__(self, arch, os): + self.Arch =3D arch + self.OperatingSystem =3D os + + @property + def Arch(self): + return self._arch + + @Arch.setter + def Arch(self, value): + value =3D value.lower() + if(value =3D=3D "x64") or (value =3D=3D "amd64"): # support amd64= value so INF and CAT tools can use same arch value + self._arch =3D "X64" + elif(value =3D=3D "arm"): + self._arch =3D "ARM" + elif(value =3D=3D "arm64") or (value =3D=3D "aarch64"): # support= UEFI defined aarch64 value as well + self._arch =3D "ARM64" + else: + logging.critical("Unsupported Architecture: %s", value) + raise ValueError("Unsupported Architecture") + + @property + def OperatingSystem(self): + return self._operatingsystem + + @OperatingSystem.setter + def OperatingSystem(self, value): + key =3D value.lower() + if(key not in CatGenerator.SUPPORTED_OS.keys()): + logging.critical("Unsupported Operating System: %s", key) + raise ValueError("Unsupported Operating System") + self._operatingsystem =3D CatGenerator.SUPPORTED_OS[key] + + def MakeCat(self, OutputCatFile, PathToInf2CatTool=3DNone): + # Find Inf2Cat tool + if(PathToInf2CatTool is None): + PathToInf2CatTool =3D os.path.join(os.getenv("ProgramFiles(x86= )"), "Windows Kits", "10", + "bin", "x86", "Inf2Cat.exe") + if not os.path.exists(PathToInf2CatTool): + logging.debug("Windows Kit 10 not Found....trying 8.1") + # Try 8.1 kit + PathToInf2CatTool.replace("10", "8.1") + + # check if exists + if not os.path.exists(PathToInf2CatTool): + raise Exception("Can't find Inf2Cat on this machine. Please i= nstall the Windows 10 WDK - " + =20 + "https://developer.microsoft.com/en-us/windows/hardware/windows-driver + -kit") + + # Adjust for spaces in the path (when calling the command). + if " " in PathToInf2CatTool: + PathToInf2CatTool =3D '"' + PathToInf2CatTool + '"' + + OutputFolder =3D os.path.dirname(OutputCatFile) + # Make Cat file + cmd =3D "/driver:. /os:" + self.OperatingSystem + "_" + self.Arch = + " /verbose" + ret =3D RunCmd(PathToInf2CatTool, cmd, workingdir=3DOutputFolder) + if(ret !=3D 0): + raise Exception("Creating Cat file Failed with errorcode %d" %= ret) + if(not os.path.isfile(OutputCatFile)): + raise Exception("CAT file (%s) not created" %=20 + OutputCatFile) + + return 0 diff --git a/BaseTools/Source/Python/Capsule/GenerateWindowsDriver.py b/Bas= eTools/Source/Python/Capsule/GenerateWindowsDriver.py new file mode 100644 index 0000000000..1d543b3fca --- /dev/null +++ b/BaseTools/Source/Python/Capsule/GenerateWindowsDriver.py @@ -0,0 +1,115 @@ +## @file +# Generate a capsule windows driver. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.
#=20 +SPDX-License-Identifier: BSD-2-Clause-Patent # + +''' +GenerateWindowsDriver +''' + +import sys +import argparse +import uuid +import struct +import subprocess +import os +import tempfile +import shutil +import platform +import re +import logging +from WindowsCapsuleSupportHelper import WindowsCapsuleSupportHelper + +# +# Globals for help information +# +__prog__ =3D 'GenerateWindowsDriver' +__version__ =3D '0.0' +__copyright__ =3D 'Copyright (c) 2019, Intel Corporation. All rights res= erved.' +__description__ =3D 'Generate Capsule Windows Driver.\n' + + +if __name__ =3D=3D '__main__': + def convert_arg_line_to_args(arg_line): + for arg in arg_line.split(): + if not arg.strip(): + continue + yield arg + + parser =3D argparse.ArgumentParser ( + prog =3D __prog__, + description =3D __description__ + __copyright__, + conflict_handler =3D 'resolve', + fromfile_prefix_chars =3D '@' + ) + parser.convert_arg_line_to_args =3D convert_arg_line_to_args + parser.add_argument("--output-folder", dest =3D 'OutputFolder', help = =3D "firmware resource update driver package output folder.") + parser.add_argument("--product-fmp-guid", dest =3D 'ProductFmpGuid', h= elp =3D "firmware GUID of resource update driver package") + parser.add_argument("--capsuleversion-dotstring", dest =3D 'CapsuleVer= sion_DotString', help =3D "firmware version with date on which update drive= r package is authored") + parser.add_argument("--capsuleversion-hexstring", dest =3D 'CapsuleVer= sion_HexString', help =3D "firmware version in Hex of update driver package= ") + parser.add_argument("--product-fw-provider", dest =3D 'ProductFwProvid= er', help =3D "vendor/provider of entire firmware resource update driver pa= ckage") + parser.add_argument("--product-fw-mfg-name", dest =3D 'ProductFwMfgNam= e', help =3D "manufacturer/vendor of firmware resource update driver packag= e") + parser.add_argument("--product-fw-desc", dest =3D "ProductFwDesc", hel= p =3D "description about resource update driver") + parser.add_argument("--capsule-file-name", dest =3D 'CapsuleFileName',= help =3D"firmware resource image file") + parser.add_argument("--pfx-file", dest =3D 'PfxFile', help =3D "pfx fi= le path used to sign resource update driver") + parser.add_argument("--arch", dest =3D 'Arch', help =3D "supported arc= hitecture:arm/x64/amd64/arm64/aarch64", default =3D 'amd64') + parser.add_argument("--operating-system-string", dest =3D=20 + 'OperatingSystemString', help =3D "supported operating=20 + system:win10/10/10_au/10_rs2/10_rs3/10_rs4/server10/server2016/serverr + s2/serverrs3/serverrs4", default =3D "win10") + + def ArgCheck(args): + Version =3D args.CapsuleVersion_DotString.split('.') + + if len(Version) !=3D 4: + logging.critical("Name invalid: '%s'", args.CapsuleVersion_Dot= String) + raise ValueError("Name invalid.") + for sub in Version: + if int(sub) > 65536: + logging.critical("Name invalid: '%s'", args.CapsuleVersion= _DotString) + raise ValueError("Name exceed limit 65536.") + + if not (re.compile(r'[0-9.]*$')).match(args.CapsuleVersion_DotStri= ng): + logging.critical("Name invalid: '%s'", args.CapsuleVersion_Dot= String) + raise ValueError("Name has invalid chars.") + + def CapsuleGuidCheck(InputFile, Guid): + TempCapDecode =3D 'TempCapDecode.txt' + Command =3D 'python GenerateCapsule.py "' + InputFile + '" --dump-= info >' + TempCapDecode + os.system (Command) + with open(TempCapDecode, 'rb') as f: + for line in f: + if re.search(b'UpdateImageTypeId', line, re.M|re.I): + CapGuid =3D str(line).split('=3D ')[1][:-5] + break + f.close() + os.remove(TempCapDecode) + if (Guid !=3D CapGuid): + print('GenerateWindowsDriver error: Different Guid from Ca= psule') + sys.exit(1) + + args =3D parser.parse_args() + + InputFile =3D os.path.join(args.OutputFolder, '') +=20 + args.CapsuleFileName + + ProductName =3D args.CapsuleFileName.strip('.cap') + WindowsDriver =3D WindowsCapsuleSupportHelper () + + ArgCheck(args) + CapsuleGuidCheck(InputFile, args.ProductFmpGuid) + + WindowsDriver.PackageWindowsCapsuleFiles ( + args.OutputFolder, + ProductName, + args.ProductFmpGuid, + args.CapsuleVersion_Dot= String, + args.CapsuleVersion_Hex= String, + args.ProductFwProvider, + args.ProductFwMfgName, + args.ProductFwDesc, + args.CapsuleFileName, + args.PfxFile, + None, + None, + args.Arch, + args.OperatingSystemStr= ing + ) diff --git a/BaseTools/Source/Python/Capsule/InfGenerator.py b/BaseTools/So= urce/Python/Capsule/InfGenerator.py new file mode 100644 index 0000000000..508bbed0ef --- /dev/null +++ b/BaseTools/Source/Python/Capsule/InfGenerator.py @@ -0,0 +1,210 @@ +## @file + # Script to generate inf files for capsule update based on INF=20 +TEMPLATE and # supplied information (Name, Version, ESRT Guid,=20 +Rollback, etc.) # # Copyright (c) 2019, Microsoft Corporation #=20 +Copyright (c) 2019, Intel Corporation. All rights reserved.
#=20 +SPDX-License-Identifier: BSD-2-Clause-Patent ## + +import os +import logging +import datetime +import re +import uuid + + +##### +# +##### +class InfGenerator(object): + + ### INF Template ### + TEMPLATE =3D r"""; +; {Name}.inf +; {DriverVersion} +; Copyright (C) 2019 Microsoft Corporation. All Rights Reserved. +; +[Version] +Signature=3D"$WINDOWS NT$" +Class=3DFirmware +ClassGuid=3D{{f2e7dd72-6468-4e36-b6f1-6488f42c1b52}} +Provider=3D%Provider% +DriverVer=3D{Date},{DriverVersion} +PnpLockdown=3D1 +CatalogFile=3D{Name}.cat +[Manufacturer] +%MfgName% =3D Firmware,NT{Arch} +[Firmware.NT{Arch}] +%FirmwareDesc% =3D Firmware_Install,UEFI\RES_{{{EsrtGuid}}} +[Firmware_Install.NT] +CopyFiles =3D Firmware_CopyFiles +{Rollback} +[Firmware_CopyFiles] +{FirmwareBinFile} +[Firmware_Install.NT.Hw] +AddReg =3D Firmware_AddReg +[Firmware_AddReg] +HKR,,FirmwareId,,{{{EsrtGuid}}} +HKR,,FirmwareVersion,%REG_DWORD%,{VersionHexString} +HKR,,FirmwareFilename,,{FirmwareBinFile} +[SourceDisksNames] +1 =3D %DiskName% +[SourceDisksFiles] +{FirmwareBinFile} =3D 1 +[DestinationDirs] +DefaultDestDir =3D %DIRID_WINDOWS%,Firmware ; %SystemRoot%\Firmware=20 +[Strings] ; localizable +Provider =3D "{Provider}" +MfgName =3D "{MfgName}" +FirmwareDesc =3D "{Description}" +DiskName =3D "Firmware Update" +; non-localizable +DIRID_WINDOWS =3D 10 +REG_DWORD =3D 0x00010001 +""" + + ROLLBACKTEMPLATE =3D r"""AddReg =3D Firmware_DowngradePolicy_Addreg + ;override firmware resource update policy to allow downgrade to lower=20 + version [Firmware_DowngradePolicy_Addreg] + =20 + HKLM,SYSTEM\CurrentControlSet\Control\FirmwareResources\{{{EsrtGuid}}} + ,Policy,%REG_DWORD%,1 + """ + + SUPPORTED_ARCH =3D {'amd64': 'amd64', + 'x64': 'amd64', + 'arm': 'arm', + 'arm64': 'ARM64', + 'aarch64': 'ARM64' + } + + def __init__(self, name_string, provider, esrt_guid, arch, description= _string, version_string, version_hex): + self.Name =3D name_string + self.Provider =3D provider + self.EsrtGuid =3D esrt_guid + self.Arch =3D arch + self.Description =3D description_string + self.VersionString =3D version_string + self.VersionHex =3D version_hex + self._manufacturer =3D None # default for optional feature + self._date =3D datetime.date.today() + + @property + def Name(self): + return self._name + + @Name.setter + def Name(self, value): + # test here for invalid chars + if not (re.compile(r'[\w-]*$')).match(value): + logging.critical("Name invalid: '%s'", value) + raise ValueError("Name has invalid chars.") + self._name =3D value + + @property + def Provider(self): + return self._provider + + @Provider.setter + def Provider(self, value): + self._provider =3D value + + @property + def Manufacturer(self): + if(self._manufacturer is None): + return self.Provider + + return self._manufacturer + + @Manufacturer.setter + def Manufacturer(self, value): + self._manufacturer =3D value + + @property + def Description(self): + return self._description + + @Description.setter + def Description(self, value): + self._description =3D value + + @property + def EsrtGuid(self): + return self._esrtguid + + @EsrtGuid.setter + def EsrtGuid(self, value): + uuid.UUID(value) # if this works it is valid...otherwise throws e= xception + # todo - make sure it is formatted exactly right + self._esrtguid =3D value + + @property + def VersionString(self): + return self._versionstring + + @VersionString.setter + def VersionString(self, value): + c =3D value.count(".") + if(c < 1) or (c > 3): + logging.critical("Version string in invalid format.") + raise ValueError("VersionString must be in format of xx.xx -> = xx.xx.xx.xx") + self._versionstring =3D value + + @property + def VersionHex(self): + return "0x%08X" % self._versionhex + + @VersionHex.setter + def VersionHex(self, value): + a =3D int(value, 0) + if(a > 0xFFFFFFFF): + logging.critical("VersionHex invalid: '%s'", value) + raise ValueError("VersionHex must fit within 32bit value range= for unsigned integer") + self._versionhex =3D a + + @property + def Arch(self): + return self._arch + + @Arch.setter + def Arch(self, value): + key =3D value.lower() + if(key not in InfGenerator.SUPPORTED_ARCH.keys()): + logging.critical("Arch invalid: '%s'", value) + raise ValueError("Unsupported Architecture") + self._arch =3D InfGenerator.SUPPORTED_ARCH[key] + + @property + def Date(self): + return self._date.strftime("%m/%d/%Y") + + @Date.setter + def Date(self, value): + if(not isinstance(value, datetime.date)): + raise ValueError("Date must be a datetime.date object") + self._date =3D value + + def MakeInf(self, OutputInfFilePath, FirmwareBinFileName, Rollback=3DF= alse): + RollbackString =3D "" + if(Rollback): + RollbackString =3D=20 + InfGenerator.ROLLBACKTEMPLATE.format(EsrtGuid=3Dself.EsrtGuid) + + binfilename =3D os.path.basename(FirmwareBinFileName) + + Content =3D InfGenerator.TEMPLATE.format( + Name=3Dself.Name, + Date=3Dself.Date, + Arch=3Dself.Arch, + DriverVersion=3Dself.VersionString, + EsrtGuid=3Dself.EsrtGuid, + FirmwareBinFile=3Dbinfilename, + VersionHexString=3Dself.VersionHex, + Provider=3Dself.Provider, + MfgName=3Dself.Manufacturer, + Description=3Dself.Description, + Rollback=3DRollbackString) + + with open(OutputInfFilePath, "w") as f: + f.write(Content) + + return 0 diff --git a/BaseTools/Source/Python/Capsule/WindowsCapsuleSupportHelper.py= b/BaseTools/Source/Python/Capsule/WindowsCapsuleSupportHelper.py new file mode 100644 index 0000000000..8abac3e31d --- /dev/null +++ b/BaseTools/Source/Python/Capsule/WindowsCapsuleSupportHelper.py @@ -0,0 +1,102 @@ +## +# UefiBuild Plugin that supports Window Capsule files based on the #=20 +Windows Firmware Update Platform spec. +# Creates INF, Cat, and then signs it +# +# +# Copyright (c) 2018, Microsoft Corporation # Copyright (c) 2019, Intel=20 +Corporation. All rights reserved.
# SPDX-License-Identifier:=20 +BSD-2-Clause-Patent ## + +import sys +import re +import datetime +import os +import logging +from CatGenerator import CatGenerator +from InfGenerator import InfGenerator +from CatGenerator import RunCmd + +def CatalogSignWithSignTool(SignToolPath, ToSignFilePath, PfxFilePath, Pfx= Pass=3DNone): + # check signtool path + if not os.path.exists(SignToolPath): + logging.error("Path to signtool invalid. %s" % SignToolPath) + return -1 + + # Adjust for spaces in the path (when calling the command). + if " " in SignToolPath: + SignToolPath =3D '"' + SignToolPath + '"' + + OutputDir =3D os.path.dirname(ToSignFilePath) + # Signtool docs https://docs.microsoft.com/en-us/dotnet/framework/tool= s/signtool-exe + # todo: link to catalog signing documentation + params =3D "sign /a /fd SHA256 /f " + PfxFilePath + if PfxPass is not None: + # add password if set + params =3D params + ' /p ' + PfxPass + params =3D params + ' /debug /v "' + ToSignFilePath + '" ' + ret =3D RunCmd(SignToolPath, params, workingdir=3DOutputDir) + if(ret !=3D 0): + logging.error("Signtool failed %d" % ret) + return ret + +class WindowsCapsuleSupportHelper(object): + @staticmethod + def _LocateLatestWindowsKits(): + result =3D None + + # Start with a base path and use it to start locating the ideal di= rectory. + base_path =3D os.path.join(os.getenv("ProgramFiles(x86)"),=20 + "Windows Kits") + + # Check for Win 10 kits first. + base_10_path =3D os.path.join(base_path, "10", "bin") + if os.path.isdir(base_10_path): + # If you can find one of the new kit paths, use it. + # Walk backwards to test the most recent kit first. + for sub_path in reversed(os.listdir(base_10_path)): + if sub_path.startswith("10.") and os.path.isdir(os.path.jo= in(base_10_path, sub_path, "x64")): + result =3D os.path.join(base_10_path, sub_path, "x64") + break + + # Otherwise, fall back to the legacy path. + if not result and os.path.isdir(os.path.join(base_10_path, "x6= 4")): + result =3D os.path.join(base_10_path, "x64") + # If not, fall back to Win 8.1. + elif os.path.isdir(os.path.join(base_path, "8.1", "bin", "x64")): + result =3D os.path.join(base_path, "8.1", "bin", "x64") + return result + + def RegisterHelpers(self, obj): + fp =3D os.path.abspath(__file__) + obj.Register("PackageWindowsCapsuleFiles",=20 + WindowsCapsuleSupportHelper.PackageWindowsCapsuleFiles, fp) + + + @staticmethod + def PackageWindowsCapsuleFiles(OutputFolder, ProductName, ProductFmpGu= id, CapsuleVersion_DotString,CapsuleVersion_HexString, ProductFwProvider, P= roductFwMfgName, ProductFwDesc, CapsuleFileName, PfxFile=3DNone, PfxPass=3D= None, Rollback=3DFalse, Arch=3D'amd64', OperatingSystem_String=3D'Win10'): + logging.debug("CapsulePackage: Create Windows Capsule Files") + #Make INF + InfFilePath =3D os.path.join(OutputFolder, ProductName + ".inf") + InfTool =3D InfGenerator(ProductName, ProductFwProvider, ProductFm= pGuid, Arch, ProductFwDesc, CapsuleVersion_DotString, CapsuleVersion_HexStr= ing) + InfTool.Manufacturer =3D ProductFwMfgName #optional + ret =3D InfTool.MakeInf(InfFilePath, CapsuleFileName, Rollback) + if(ret !=3D 0): + raise Exception("CreateWindowsInf Failed with errorcode %d" % = ret) + #Make CAT + CatFilePath =3D os.path.realpath(os.path.join(OutputFolder, Produc= tName + ".cat")) + CatTool =3D CatGenerator(Arch, OperatingSystem_String) + ret =3D CatTool.MakeCat(CatFilePath) + + if(ret !=3D 0): + raise Exception("Creating Cat file Failed with errorcode %d" %= ret) + if(PfxFile is not None): + #Find Signtool + WinKitsPath =3D WindowsCapsuleSupportHelper._LocateLatestWindo= wsKits() + SignToolPath =3D os.path.join(WinKitsPath, "signtool.exe") + if not os.path.exists(SignToolPath): + raise Exception("Can't find signtool on this machine.") + #dev sign the cat file + ret =3D CatalogSignWithSignTool(SignToolPath, CatFilePath, Pfx= File, PfxPass) + if(ret !=3D 0): + raise Exception("Signing Cat file Failed with errorcode %d= " % ret) + return ret -- 2.20.1.windows.1