diff --git a/.azurepipelines/Ubuntu-GCC5.yml b/.azurepipelines/Ubuntu-GCC5.yml new file mode 100644 index 00000000000..a26a3a2cb2e --- /dev/null +++ b/.azurepipelines/Ubuntu-GCC5.yml @@ -0,0 +1,18 @@ +## @file +# Azure Pipeline build file for a build using ubuntu and GCC5 +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +trigger: +- master +pr: +- master + +jobs: +- template: templates/pr-gate-build-job.yml + parameters: + tool_chain_tag: 'GCC5' + vm_image: 'ubuntu-latest' + arch_list: "IA32,X64,ARM,AARCH64" + diff --git a/.azurepipelines/Ubuntu-PatchCheck.yml b/.azurepipelines/Ubuntu-PatchCheck.yml new file mode 100644 index 00000000000..dff8f579b67 --- /dev/null +++ b/.azurepipelines/Ubuntu-PatchCheck.yml @@ -0,0 +1,35 @@ +## @file +# Azure Pipielines YML file that evalues the patch series in a PR using the +# python script BaseTools/Scripts/PatchCheck.py. +# +# NOTE: This example monitors pull requests against the edk2-ci branch. Most +# environments would replace 'edk2-ci' with 'master'. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# https://github.com/tianocore +# +## + +trigger: none + +pr: +- master + +pool: + vmImage: 'ubuntu-latest' + +steps: +- checkout: self + clean: true + +- task: UsePythonVersion@0 + inputs: + versionSpec: '3.7.x' + architecture: 'x64' + +- script: | + git fetch origin $(System.PullRequest.TargetBranch):$(System.PullRequest.TargetBranch) + python BaseTools/Scripts/PatchCheck.py $(System.PullRequest.TargetBranch)..$(System.PullRequest.SourceCommitId) + displayName: 'Use PatchCheck.py to verify patch series in pull request' diff --git a/.azurepipelines/Windows-VS2019.yml b/.azurepipelines/Windows-VS2019.yml new file mode 100644 index 00000000000..d6b879cd989 --- /dev/null +++ b/.azurepipelines/Windows-VS2019.yml @@ -0,0 +1,18 @@ +## @file +# Azure Pipeline build file for a build using Windows and VS2019 +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +trigger: +- master + +pr: +- master + +jobs: +- template: templates/pr-gate-build-job.yml + parameters: + tool_chain_tag: 'VS2019' + vm_image: 'windows-latest' + arch_list: "IA32,X64" diff --git a/.azurepipelines/templates/basetools-build-steps.yml b/.azurepipelines/templates/basetools-build-steps.yml new file mode 100644 index 00000000000..d8c108c6e21 --- /dev/null +++ b/.azurepipelines/templates/basetools-build-steps.yml @@ -0,0 +1,37 @@ +## @file +# File templates/basetools-build-job.yml +# +# template file to build basetools +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +parameters: + tool_chain_tag: '' + +steps: +- ${{ if contains(parameters.tool_chain_tag, 'GCC') }}: + - bash: sudo apt-get update + displayName: Update apt + condition: and(gt(variables.pkg_count, 0), succeeded()) + + - bash: sudo apt-get install gcc g++ make uuid-dev + displayName: Install required tools + condition: and(gt(variables.pkg_count, 0), succeeded()) + +- task: CmdLine@1 + displayName: Build Base Tools from source + inputs: + filename: python + arguments: BaseTools/Edk2ToolsBuild.py -t ${{ parameters.tool_chain_tag }} + condition: and(gt(variables.pkg_count, 0), succeeded()) + +- task: CopyFiles@2 + displayName: "Copy base tools build log" + inputs: + targetFolder: '$(Build.ArtifactStagingDirectory)' + SourceFolder: 'BaseTools/BaseToolsBuild' + contents: | + BASETOOLS_BUILD*.* + flattenFolders: true + condition: and(gt(variables.pkg_count, 0), succeededOrFailed()) diff --git a/.azurepipelines/templates/pr-gate-build-job.yml b/.azurepipelines/templates/pr-gate-build-job.yml new file mode 100644 index 00000000000..61868554d43 --- /dev/null +++ b/.azurepipelines/templates/pr-gate-build-job.yml @@ -0,0 +1,80 @@ +## @file +# File templates/pr-gate-build-job.yml +# +# template file used to build supported packages. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +parameters: + tool_chain_tag: '' + vm_image: '' + arch_list: '' + +# Build step +jobs: + +- job: Build_${{ parameters.tool_chain_tag }} + + #Use matrix to speed up the build process + strategy: + matrix: + TARGET_MDE_CPU: + Build.Pkgs: 'MdePkg,UefiCpuPkg' + Build.Targets: 'DEBUG,RELEASE,NO-TARGET,NOOPT' + TARGET_MDEMODULE_DEBUG: + Build.Pkgs: 'MdeModulePkg' + Build.Targets: 'DEBUG,NOOPT' + TARGET_MDEMODULE_RELEASE: + Build.Pkgs: 'MdeModulePkg' + Build.Targets: 'RELEASE,NO-TARGET' + TARGET_NETWORK: + Build.Pkgs: 'NetworkPkg' + Build.Targets: 'DEBUG,RELEASE,NO-TARGET' + TARGET_OTHER: + Build.Pkgs: 'PcAtChipsetPkg,ShellPkg' + Build.Targets: 'DEBUG,RELEASE,NO-TARGET' + TARGET_FMP_FAT_TEST: + Build.Pkgs: 'FmpDevicePkg,FatPkg,UnitTestFrameworkPkg' + Build.Targets: 'DEBUG,RELEASE,NO-TARGET,NOOPT' + TARGET_CRYPTO: + Build.Pkgs: 'CryptoPkg' + Build.Targets: 'DEBUG,RELEASE,NO-TARGET' + TARGET_SECURITY: + Build.Pkgs: 'SecurityPkg' + Build.Targets: 'DEBUG,RELEASE,NO-TARGET' + + workspace: + clean: all + + pool: + vmImage: ${{ parameters.vm_image }} + + steps: + - template: pr-gate-steps.yml + parameters: + tool_chain_tag: ${{ parameters.tool_chain_tag }} + build_pkgs: $(Build.Pkgs) + build_targets: $(Build.Targets) + build_archs: ${{ parameters.arch_list }} + +- job: FINISHED + dependsOn: Build_${{ parameters.tool_chain_tag }} + condition: succeeded() + steps: + - checkout: none + - script: | + echo FINISHED + sleep 10 + displayName: FINISHED + +- job: FAILED + dependsOn: Build_${{ parameters.tool_chain_tag }} + condition: failed() + steps: + - checkout: none + - script: | + echo FAILED + sleep 10 + displayName: FAILED diff --git a/.azurepipelines/templates/pr-gate-steps.yml b/.azurepipelines/templates/pr-gate-steps.yml new file mode 100644 index 00000000000..a969661dea1 --- /dev/null +++ b/.azurepipelines/templates/pr-gate-steps.yml @@ -0,0 +1,130 @@ +## @file +# File templates/pr-gate-steps.yml +# +# template file containing the steps to build +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +parameters: + tool_chain_tag: '' + build_pkgs: '' + build_targets: '' + build_archs: '' + +steps: +- checkout: self + clean: true + fetchDepth: 1 + +- task: UsePythonVersion@0 + inputs: + versionSpec: '3.7.x' + architecture: 'x64' + +- script: pip install -r pip-requirements.txt --upgrade + displayName: 'Install/Upgrade pip modules' + +# Set default +- bash: | + echo "##vso[task.setvariable variable=pkgs_to_build]${{ parameters.build_pkgs }}" + echo "##vso[task.setvariable variable=pkg_count]${{ 1 }}" + +# trim the package list if this is a PR +- task: CmdLine@1 + displayName: Check if ${{ parameters.build_pkgs }} need testing + inputs: + filename: stuart_pr_eval + arguments: -c .pytool/CISettings.py -p ${{ parameters.build_pkgs }} --pr-target origin/$(System.PullRequest.targetBranch) --output-csv-format-string "##vso[task.setvariable variable=pkgs_to_build;isOutpout=true]{pkgcsv}" --output-count-format-string "##vso[task.setvariable variable=pkg_count;isOutpout=true]{pkgcount}" + condition: eq(variables['Build.Reason'], 'PullRequest') + +# build basetools +- template: basetools-build-steps.yml + parameters: + tool_chain_tag: ${{ parameters.tool_chain_tag }} + +# install spell check prereqs +- template: spell-check-prereq-steps.yml + +# Build repo +- task: CmdLine@1 + displayName: Setup ${{ parameters.build_pkgs }} ${{ parameters.build_archs}} + inputs: + filename: stuart_setup + arguments: -c .pytool/CISettings.py -p $(pkgs_to_build) -t ${{ parameters.build_targets}} -a ${{ parameters.build_archs}} TOOL_CHAIN_TAG=${{ parameters.tool_chain_tag}} + condition: and(gt(variables.pkg_count, 0), succeeded()) + +- task: CmdLine@1 + displayName: Update ${{ parameters.build_pkgs }} ${{ parameters.build_archs}} + inputs: + filename: stuart_update + arguments: -c .pytool/CISettings.py -p $(pkgs_to_build) -t ${{ parameters.build_targets}} -a ${{ parameters.build_archs}} TOOL_CHAIN_TAG=${{ parameters.tool_chain_tag}} + condition: and(gt(variables.pkg_count, 0), succeeded()) + +- task: CmdLine@1 + displayName: Build and Test ${{ parameters.build_pkgs }} ${{ parameters.build_archs}} + inputs: + filename: stuart_ci_build + arguments: -c .pytool/CISettings.py -p $(pkgs_to_build) -t ${{ parameters.build_targets}} -a ${{ parameters.build_archs}} TOOL_CHAIN_TAG=${{ parameters.tool_chain_tag}} + condition: and(gt(variables.pkg_count, 0), succeeded()) + +# Publish Test Results to Azure Pipelines/TFS +- task: PublishTestResults@2 + displayName: 'Publish junit test results' + continueOnError: true + condition: and( succeededOrFailed(),gt(variables.pkg_count, 0)) + inputs: + testResultsFormat: 'JUnit' # Options: JUnit, NUnit, VSTest, xUnit + testResultsFiles: 'Build/TestSuites.xml' + #searchFolder: '$(System.DefaultWorkingDirectory)' # Optional + mergeTestResults: true # Optional + testRunTitle: $(System.JobName) # Optional + #buildPlatform: # Optional + #buildConfiguration: # Optional + publishRunAttachments: true # Optional + +# Publish Test Results to Azure Pipelines/TFS +- task: PublishTestResults@2 + displayName: 'Publish host based test results for $(System.JobName)' + continueOnError: true + condition: and( succeededOrFailed(), gt(variables.pkg_count, 0)) + inputs: + testResultsFormat: 'JUnit' # Options: JUnit, NUnit, VSTest, xUnit + testResultsFiles: 'Build/**/*.result.xml' + #searchFolder: '$(System.DefaultWorkingDirectory)' # Optional + mergeTestResults: false # Optional + testRunTitle: ${{ parameters.build_pkgs }} # Optional + #buildPlatform: # Optional + #buildConfiguration: # Optional + publishRunAttachments: true # Optional + +# Copy the build logs to the artifact staging directory +- task: CopyFiles@2 + displayName: "Copy build logs" + inputs: + targetFolder: '$(Build.ArtifactStagingDirectory)' + SourceFolder: 'Build' + contents: | + BUILDLOG_*.txt + BUILDLOG_*.md + CI_*.txt + CI_*.md + CISETUP.txt + SETUPLOG.txt + UPDATE_LOG.txt + PREVALLOG.txt + TestSuites.xml + **/BUILD_TOOLS_REPORT.html + **/OVERRIDELOG.TXT + flattenFolders: true + condition: succeededOrFailed() + +# Publish build artifacts to Azure Artifacts/TFS or a file share +- task: PublishBuildArtifacts@1 + continueOnError: true + displayName: "Publish build logs" + inputs: + pathtoPublish: '$(Build.ArtifactStagingDirectory)' + artifactName: 'Build Logs $(System.JobName)' + condition: succeededOrFailed() diff --git a/.azurepipelines/templates/spell-check-prereq-steps.yml b/.azurepipelines/templates/spell-check-prereq-steps.yml new file mode 100644 index 00000000000..e1570d4f2aa --- /dev/null +++ b/.azurepipelines/templates/spell-check-prereq-steps.yml @@ -0,0 +1,22 @@ +## @file +# File templates/spell-check-prereq-steps.yml +# +# template file used to install spell checking prerequisits +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +parameters: + none: '' + +steps: +- task: NodeTool@0 + inputs: + versionSpec: '10.x' + #checkLatest: false # Optional + condition: and(gt(variables.pkg_count, 0), succeeded()) + +- script: npm install -g cspell + displayName: 'Install cspell npm' + condition: and(gt(variables.pkg_count, 0), succeeded()) diff --git a/.gitignore b/.gitignore index 97f22c348c1..ca67689b60b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ Build/ -tags/ .DS_Store +*_extdep/ +*.pyc +__pycache__/ +tags/ +.vscode/ + +# Dependencies diff --git a/.gitmodules b/.gitmodules index 508f0c18287..b30f5bf136b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "SoftFloat"] path = ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3 url = https://github.com/ucb-bar/berkeley-softfloat-3.git +[submodule "UnitTestFrameworkPkg/Library/CmockaLib/cmocka"] + path = UnitTestFrameworkPkg/Library/CmockaLib/cmocka + url = https://git.cryptomilk.org/projects/cmocka.git diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000000..ae179b0886c --- /dev/null +++ b/.mailmap @@ -0,0 +1,72 @@ +# +# This list is used by git-shortlog to fix a few botched name translations +# in the git archive, either because the author's full name was messed up +# and/or not always written the same way, making contributions from the +# same person appearing not to be so or badly displayed. +# +# Please keep this file sorted alphabetically, and email in lowercase. +# The format used is: +# +# Firstname Lastname +# + +Aaron Li +Antoine Cœur +Antoine Cœur +Ard Biesheuvel +Ashley DeSimone +Baraneedharan Anbazhagan +Chasel Chiu +Christopher J Zurcher +Eric Dong +Eric Dong Eric Dong +Eric Dong +Eric Dong +Erik Bjorge +Hao A Wu +Hao A Wu +Hot Tian +Hot Tian +Jiewen Yao +Jiewen Yao +Jiewen Yao +Jiewen Yao +Jiewen Yao +Jiewen Yao +Jim Dailey +Jim Dailey +Laszlo Ersek +Laszlo Ersek +Liming Gao +Liming Gao +Liming Gao +Liming Gao +Maciej Rabeda +Marc-André Lureau +Marvin Häuser +Marvin Häuser edk2-devel +Marvin Häuser +Maurice Ma +Michael Kubacki +Michael Kubacki +Ming Tan +Nikolai Saoukh +Philippe Mathieu-Daudé +Ray Ni +Ray Ni +Ray Ni +Ray Ni +Ray Ni +Ray Ni +Ray Ni +Samer El-Haj-Mahmoud +Samer El-Haj-Mahmoud +Shenglei Zhang +Star Zeng +Star Zeng +Star Zeng +Vitaly Cheptsov Vitaly Cheptsov via Groups.Io +Vladimir Olovyannikov Vladimir Olovyannikov via edk2-devel +Yonghong Zhu +Yonghong Zhu +Yu-Chen Lin diff --git a/.mergify/config.yml b/.mergify/config.yml new file mode 100644 index 00000000000..26583de0f63 --- /dev/null +++ b/.mergify/config.yml @@ -0,0 +1,97 @@ +## @file +# Mergify YML file that automatically merges a GitHub pull request against +# edk2-ci if all of the GitHub branch protections have passed. It also +# contains rules to: +# * auto close branches that are not from an EDK II Maintainer +# * post a comment on pull requests that have merge conflicts. +# * post a comment on pull requests that have PatchCheck.py errors. +# +# Configuration Notes: +# * Update the 'base=edk2-ci' statements with the name of the branch to merge +# pull requests. +# +# * Update the 'status-failure' statement with the name of the name of the Azure +# Pipelines Build that performs the EDK II Maintainer check. +# +# * This file must be checked into the 'default' branch of a repo. Copies +# of this file on other branches of a repo are ignored by Mergify. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# https://github.com/apps/mergify +# https://doc.mergify.io/ +# +## + +pull_request_rules: + + - name: Automatically merge a PR when all required checks pass and 'push' label is present + conditions: + - base=master + - label=push + - author=@tianocore/edk-ii-maintainers + - status-success=tianocore.PatchCheck + - status-success=Ubuntu GCC5 PR + - status-success=Windows VS2019 PR + actions: + merge: + strict: true + method: rebase + + - name: Automatically close a PR when all required checks pass and 'push' label is not present + conditions: + - base=master + - -label=push + - -closed + - status-success=tianocore.PatchCheck + - status-success=Ubuntu GCC5 PR + - status-success=Windows VS2019 PR + - status-success=Ubuntu GCC5 PR (FINISHED) + - status-success=Windows VS2019 PR (FINISHED) + actions: + close: + message: All checks passed. Auto close personal build. + + - name: Post a comment on a PR that can not be merged due to a merge conflict + conditions: + - base=master + - conflict + actions: + comment: + message: PR can not be merged due to conflict. Please rebase and resubmit + + - name: Automatically close a PR that fails the EDK II Maintainers membership check and 'push' label is present + conditions: + - base=master + - label=push + - -author=@tianocore/edk-ii-maintainers + actions: + close: + message: PR submitter is not a member of the Tianocore EDK II Maintainers team + + - name: Post a comment on a PR if PatchCheck fails + conditions: + - base=master + - status-failure=tianocore.PatchCheck + actions: + comment: + message: PR can not be merged due to a PatchCheck failure. Please resolve and resubmit + + - name: Post a comment on a PR if Ubuntu GCC5 fails + conditions: + - base=master + - status-failure=Ubuntu GCC5 PR + - status-success=Ubuntu GCC5 PR (FAILED) + actions: + comment: + message: PR can not be merged due to an Ubuntu GCC5 failure. Please resolve and resubmit + + - name: Post a comment on a PR if Windows VS2019 fails + conditions: + - base=master + - status-failure=Windows VS2019 PR + - status-success=Windows VS2019 PR (FAILED) + actions: + comment: + message: PR can not be merged due to a Windows VS2019 failure. Please resolve and resubmit diff --git a/.pytool/CISettings.py b/.pytool/CISettings.py new file mode 100644 index 00000000000..79593d9dc51 --- /dev/null +++ b/.pytool/CISettings.py @@ -0,0 +1,181 @@ +# @file +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import os +import logging +from edk2toolext.environment import shell_environment +from edk2toolext.invocables.edk2_ci_build import CiBuildSettingsManager +from edk2toolext.invocables.edk2_setup import SetupSettingsManager, RequiredSubmodule +from edk2toolext.invocables.edk2_update import UpdateSettingsManager +from edk2toolext.invocables.edk2_pr_eval import PrEvalSettingsManager +from edk2toollib.utility_functions import GetHostInfo + + +class Settings(CiBuildSettingsManager, UpdateSettingsManager, SetupSettingsManager, PrEvalSettingsManager): + + def __init__(self): + self.ActualPackages = [] + self.ActualTargets = [] + self.ActualArchitectures = [] + self.ActualToolChainTag = "" + + # ####################################################################################### # + # Extra CmdLine configuration # + # ####################################################################################### # + + def AddCommandLineOptions(self, parserObj): + pass + + def RetrieveCommandLineOptions(self, args): + pass + + # ####################################################################################### # + # Default Support for this Ci Build # + # ####################################################################################### # + + def GetPackagesSupported(self): + ''' return iterable of edk2 packages supported by this build. + These should be edk2 workspace relative paths ''' + + return ("MdePkg", + "MdeModulePkg", + "NetworkPkg", + "PcAtChipsetPkg", + "SecurityPkg", + "UefiCpuPkg", + "FmpDevicePkg", + "ShellPkg", + "FatPkg", + "CryptoPkg", + "UnitTestFrameworkPkg" + ) + + def GetArchitecturesSupported(self): + ''' return iterable of edk2 architectures supported by this build ''' + return ("IA32", + "X64", + "ARM", + "AARCH64") + + def GetTargetsSupported(self): + ''' return iterable of edk2 target tags supported by this build ''' + return ("DEBUG", "RELEASE", "NO-TARGET", "NOOPT") + + # ####################################################################################### # + # Verify and Save requested Ci Build Config # + # ####################################################################################### # + + def SetPackages(self, list_of_requested_packages): + ''' Confirm the requested package list is valid and configure SettingsManager + to build the requested packages. + + Raise UnsupportedException if a requested_package is not supported + ''' + unsupported = set(list_of_requested_packages) - \ + set(self.GetPackagesSupported()) + if(len(unsupported) > 0): + logging.critical( + "Unsupported Package Requested: " + " ".join(unsupported)) + raise Exception("Unsupported Package Requested: " + + " ".join(unsupported)) + self.ActualPackages = list_of_requested_packages + + def SetArchitectures(self, list_of_requested_architectures): + ''' Confirm the requests architecture list is valid and configure SettingsManager + to run only the requested architectures. + + Raise Exception if a list_of_requested_architectures is not supported + ''' + unsupported = set(list_of_requested_architectures) - \ + set(self.GetArchitecturesSupported()) + if(len(unsupported) > 0): + logging.critical( + "Unsupported Architecture Requested: " + " ".join(unsupported)) + raise Exception( + "Unsupported Architecture Requested: " + " ".join(unsupported)) + self.ActualArchitectures = list_of_requested_architectures + + def SetTargets(self, list_of_requested_target): + ''' Confirm the request target list is valid and configure SettingsManager + to run only the requested targets. + + Raise UnsupportedException if a requested_target is not supported + ''' + unsupported = set(list_of_requested_target) - \ + set(self.GetTargetsSupported()) + if(len(unsupported) > 0): + logging.critical( + "Unsupported Targets Requested: " + " ".join(unsupported)) + raise Exception("Unsupported Targets Requested: " + + " ".join(unsupported)) + self.ActualTargets = list_of_requested_target + + # ####################################################################################### # + # Actual Configuration for Ci Build # + # ####################################################################################### # + + def GetActiveScopes(self): + ''' return tuple containing scopes that should be active for this process ''' + scopes = ("cibuild", "edk2-build", "host-based-test") + + self.ActualToolChainTag = shell_environment.GetBuildVars().GetValue("TOOL_CHAIN_TAG", "") + + if GetHostInfo().os.upper() == "WINDOWS": + scopes += ('host-test-win',) + + if GetHostInfo().os.upper() == "LINUX" and self.ActualToolChainTag.upper().startswith("GCC"): + if "AARCH64" in self.ActualArchitectures: + scopes += ("gcc_aarch64_linux",) + if "ARM" in self.ActualArchitectures: + scopes += ("gcc_arm_linux",) + + return scopes + + def GetRequiredSubmodules(self): + ''' return iterable containing RequiredSubmodule objects. + If no RequiredSubmodules return an empty iterable + ''' + rs = [] + rs.append(RequiredSubmodule( + "ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3", False)) + rs.append(RequiredSubmodule( + "CryptoPkg/Library/OpensslLib/openssl", False)) + rs.append(RequiredSubmodule( + "UnitTestFrameworkPkg/Library/CmockaLib/cmocka", False)) + return rs + + def GetName(self): + return "Edk2" + + def GetDependencies(self): + return [ + ] + + def GetPackagesPath(self): + return () + + def GetWorkspaceRoot(self): + ''' get WorkspacePath ''' + return os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + def FilterPackagesToTest(self, changedFilesList: list, potentialPackagesList: list) -> list: + ''' Filter potential packages to test based on changed files. ''' + build_these_packages = [] + possible_packages = potentialPackagesList.copy() + for f in changedFilesList: + # split each part of path for comparison later + nodes = f.split("/") + + # python file change in .pytool folder causes building all + if f.endswith(".py") and ".pytool" in nodes: + build_these_packages = possible_packages + break + + # BaseTools files that might change the build + if "BaseTools" in nodes: + if os.path.splitext(f) not in [".txt", ".md"]: + build_these_packages = possible_packages + break + return build_these_packages diff --git a/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py b/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py new file mode 100644 index 00000000000..1496e1f2493 --- /dev/null +++ b/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py @@ -0,0 +1,118 @@ +# @file CharEncodingCheck.py +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +import os +import logging +from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin +from edk2toolext.environment.var_dict import VarDict + +## +# map +## +EcodingMap = { + ".md": 'utf-8', + ".dsc": 'utf-8', + ".dec": 'utf-8', + ".c": 'utf-8', + ".h": 'utf-8', + ".asm": 'utf-8', + ".masm": 'utf-8', + ".nasm": 'utf-8', + ".s": 'utf-8', + ".inf": 'utf-8', + ".asl": 'utf-8', + ".uni": 'utf-8', + ".py": 'utf-8' +} + + +class CharEncodingCheck(ICiBuildPlugin): + """ + A CiBuildPlugin that scans each file in the code tree and confirms the encoding is correct. + + Configuration options: + "CharEncodingCheck": { + "IgnoreFiles": [] + } + """ + + def GetTestName(self, packagename: str, environment: VarDict) -> tuple: + """ Provide the testcase name and classname for use in reporting + testclassname: a descriptive string for the testcase can include whitespace + classname: should be patterned .. + + Args: + packagename: string containing name of package to build + environment: The VarDict for the test to run in + Returns: + a tuple containing the testcase name and the classname + (testcasename, classname) + """ + return ("Check for valid file encoding for " + packagename, packagename + ".CharEncodingCheck") + + ## + # External function of plugin. This function is used to perform the task of the ci_build_plugin Plugin + # + # - package is the edk2 path to package. This means workspace/packagepath relative. + # - edk2path object configured with workspace and packages path + # - PkgConfig Object (dict) for the pkg + # - EnvConfig Object + # - Plugin Manager Instance + # - Plugin Helper Obj Instance + # - Junit Logger + # - output_stream the StringIO output stream from this plugin via logging + def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None): + overall_status = 0 + files_tested = 0 + + abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename) + + if abs_pkg_path is None: + tc.SetSkipped() + tc.LogStdError("No Package folder {0}".format(abs_pkg_path)) + return 0 + + for (ext, enc) in EcodingMap.items(): + files = self.WalkDirectoryForExtension([ext], abs_pkg_path) + files = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) for x in files] # make edk2relative path so can process ignores + + if "IgnoreFiles" in pkgconfig: + for a in pkgconfig["IgnoreFiles"]: + a = a.replace(os.sep, "/") + try: + tc.LogStdOut("Ignoring File {0}".format(a)) + files.remove(a) + except: + tc.LogStdError("CharEncodingCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a)) + logging.info("CharEncodingCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a)) + + files = [Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(x) for x in files] + for a in files: + files_tested += 1 + if(self.TestEncodingOk(a, enc)): + logging.debug("File {0} Passed Encoding Check {1}".format(a, enc)) + else: + tc.LogStdError("Encoding Failure in {0}. Not {1}".format(a, enc)) + overall_status += 1 + + tc.LogStdOut("Tested Encoding on {0} files".format(files_tested)) + if overall_status != 0: + tc.SetFailed("CharEncoding {0} Failed. Errors {1}".format(packagename, overall_status), "CHAR_ENCODING_CHECK_FAILED") + else: + tc.SetSuccess() + return overall_status + + def TestEncodingOk(self, apath, encodingValue): + try: + with open(apath, "rb") as fobj: + fobj.read().decode(encodingValue) + except Exception as exp: + logging.error("Encoding failure: file: {0} type: {1}".format(apath, encodingValue)) + logging.debug("EXCEPTION: while processing {1} - {0}".format(exp, apath)) + return False + + return True diff --git a/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck_plug_in.yaml b/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck_plug_in.yaml new file mode 100644 index 00000000000..f3ce0b3b3de --- /dev/null +++ b/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck_plug_in.yaml @@ -0,0 +1,11 @@ +## @file +# CiBuildPlugin used to check char encoding +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "cibuild", + "name": "Char Encoding Check Test", + "module": "CharEncodingCheck" +} diff --git a/.pytool/Plugin/CharEncodingCheck/Readme.md b/.pytool/Plugin/CharEncodingCheck/Readme.md new file mode 100644 index 00000000000..47486e5c3cb --- /dev/null +++ b/.pytool/Plugin/CharEncodingCheck/Readme.md @@ -0,0 +1,18 @@ +# Character Encoding Check Plugin + +This CiBuildPlugin scans all the files in a package to make sure each file is +correctly encoded and all characters can be read. Improper encoding causes +tools to fail in some situations especially in different locals. + +## Configuration + +The plugin can be configured to ignore certain files. + +``` yaml +"CharEncodingCheck": { + "IgnoreFiles": [] +} +``` +### IgnoreFiles + +OPTIONAL List of file to ignore. diff --git a/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py b/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py new file mode 100644 index 00000000000..e8657940d71 --- /dev/null +++ b/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py @@ -0,0 +1,102 @@ +# @file CompilerPlugin.py +## +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +import logging +import os +import re +from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser +from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin +from edk2toolext.environment.uefi_build import UefiBuilder +from edk2toolext import edk2_logging +from edk2toolext.environment.var_dict import VarDict + + +class CompilerPlugin(ICiBuildPlugin): + """ + A CiBuildPlugin that compiles the package dsc + from the package being tested. + + Configuration options: + "CompilerPlugin": { + "DscPath": "" + } + """ + + def GetTestName(self, packagename: str, environment: VarDict) -> tuple: + """ Provide the testcase name and classname for use in reporting + + Args: + packagename: string containing name of package to build + environment: The VarDict for the test to run in + Returns: + a tuple containing the testcase name and the classname + (testcasename, classname) + """ + target = environment.GetValue("TARGET") + return ("Compile " + packagename + " " + target, packagename + ".Compiler." + target) + + def RunsOnTargetList(self): + return ["DEBUG", "RELEASE"] + + ## + # External function of plugin. This function is used to perform the task of the ICiBuildPlugin Plugin + # + # - package is the edk2 path to package. This means workspace/packagepath relative. + # - edk2path object configured with workspace and packages path + # - PkgConfig Object (dict) for the pkg + # - EnvConfig Object + # - Plugin Manager Instance + # - Plugin Helper Obj Instance + # - Junit Logger + # - output_stream the StringIO output stream from this plugin via logging + def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None): + self._env = environment + + # Parse the config for required DscPath element + if "DscPath" not in pkgconfig: + tc.SetSkipped() + tc.LogStdError("DscPath not found in config file. Nothing to compile.") + return -1 + + AP = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename) + + APDSC = os.path.join(AP, pkgconfig["DscPath"].strip()) + AP_Path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(APDSC) + if AP is None or AP_Path is None or not os.path.isfile(APDSC): + tc.SetSkipped() + tc.LogStdError("Package Dsc not found.") + return -1 + + logging.info("Building {0}".format(AP_Path)) + self._env.SetValue("ACTIVE_PLATFORM", AP_Path, "Set in Compiler Plugin") + + # Parse DSC to check for SUPPORTED_ARCHITECTURES + dp = DscParser() + dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath) + dp.SetPackagePaths(Edk2pathObj.PackagePathList) + dp.ParseFile(AP_Path) + if "SUPPORTED_ARCHITECTURES" in dp.LocalVars: + SUPPORTED_ARCHITECTURES = dp.LocalVars["SUPPORTED_ARCHITECTURES"].split('|') + TARGET_ARCHITECTURES = environment.GetValue("TARGET_ARCH").split(' ') + + # Skip if there is no intersection between SUPPORTED_ARCHITECTURES and TARGET_ARCHITECTURES + if len(set(SUPPORTED_ARCHITECTURES) & set(TARGET_ARCHITECTURES)) == 0: + tc.SetSkipped() + tc.LogStdError("No supported architecutres to build") + return -1 + + uefiBuilder = UefiBuilder() + # do all the steps + # WorkSpace, PackagesPath, PInHelper, PInManager + ret = uefiBuilder.Go(Edk2pathObj.WorkspacePath, os.pathsep.join(Edk2pathObj.PackagePathList), PLMHelper, PLM) + if ret != 0: # failure: + tc.SetFailed("Compile failed for {0}".format(packagename), "Compile_FAILED") + tc.LogStdError("{0} Compile failed with error code {1} ".format(AP_Path, ret)) + return 1 + + else: + tc.SetSuccess() + return 0 diff --git a/.pytool/Plugin/CompilerPlugin/Compiler_plug_in.yaml b/.pytool/Plugin/CompilerPlugin/Compiler_plug_in.yaml new file mode 100644 index 00000000000..4d7ca326c79 --- /dev/null +++ b/.pytool/Plugin/CompilerPlugin/Compiler_plug_in.yaml @@ -0,0 +1,11 @@ +## @file +# CiBuildPlugin used to compile each package +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "cibuild", + "name": "Compiler Plugin", + "module": "CompilerPlugin" +} diff --git a/.pytool/Plugin/CompilerPlugin/Readme.md b/.pytool/Plugin/CompilerPlugin/Readme.md new file mode 100644 index 00000000000..44e6a2c8d97 --- /dev/null +++ b/.pytool/Plugin/CompilerPlugin/Readme.md @@ -0,0 +1,17 @@ +# Compiler Plugin + +This CiBuildPlugin compiles the package DSC from the package being tested. + +## Configuration + +The package relative path of the DSC file to build. + +``` yaml +"CompilerPlugin": { + "DscPath": "" +} +``` + +### DscPath + +Package relative path to the DSC file to build. diff --git a/.pytool/Plugin/DependencyCheck/DependencyCheck.py b/.pytool/Plugin/DependencyCheck/DependencyCheck.py new file mode 100644 index 00000000000..db154d769a3 --- /dev/null +++ b/.pytool/Plugin/DependencyCheck/DependencyCheck.py @@ -0,0 +1,120 @@ +# @file dependency_check.py +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +import logging +import os +from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin +from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser +from edk2toolext.environment.var_dict import VarDict + + +class DependencyCheck(ICiBuildPlugin): + """ + A CiBuildPlugin that finds all modules (inf files) in a package and reviews the packages used + to confirm they are acceptable. This is to help enforce layering and identify improper + dependencies between packages. + + Configuration options: + "DependencyCheck": { + "AcceptableDependencies": [], # Package dec files that are allowed in all INFs. Example: MdePkg/MdePkg.dec + "AcceptableDependencies-": [], # OPTIONAL Package dependencies for INFs that are HOST_APPLICATION + "AcceptableDependencies-HOST_APPLICATION": [], # EXAMPLE Package dependencies for INFs that are HOST_APPLICATION + "IgnoreInf": [] # Ignore INF if found in filesystem + } + """ + + def GetTestName(self, packagename: str, environment: VarDict) -> tuple: + """ Provide the testcase name and classname for use in reporting + + Args: + packagename: string containing name of package to build + environment: The VarDict for the test to run in + Returns: + a tuple containing the testcase name and the classname + (testcasename, classname) + testclassname: a descriptive string for the testcase can include whitespace + classname: should be patterned .. + """ + return ("Test Package Dependencies for modules in " + packagename, packagename + ".DependencyCheck") + + ## + # External function of plugin. This function is used to perform the task of the MuBuild Plugin + # + # - package is the edk2 path to package. This means workspace/packagepath relative. + # - edk2path object configured with workspace and packages path + # - PkgConfig Object (dict) for the pkg + # - EnvConfig Object + # - Plugin Manager Instance + # - Plugin Helper Obj Instance + # - Junit Logger + # - output_stream the StringIO output stream from this plugin via logging + def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None): + overall_status = 0 + + # Get current platform + abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename) + + # Get INF Files + INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path) + INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) for x in INFFiles] # make edk2relative path so can compare with Ignore List + + # Remove ignored INFs + if "IgnoreInf" in pkgconfig: + for a in pkgconfig["IgnoreInf"]: + a = a.replace(os.sep, "/") ## convert path sep in case ignore list is bad. Can't change case + try: + INFFiles.remove(a) + tc.LogStdOut("IgnoreInf {0}".format(a)) + except: + logging.info("DependencyConfig.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a)) + tc.LogStdError("DependencyConfig.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a)) + + + # Get the AccpetableDependencies list + if "AcceptableDependencies" not in pkgconfig: + logging.info("DependencyCheck Skipped. No Acceptable Dependencies defined.") + tc.LogStdOut("DependencyCheck Skipped. No Acceptable Dependencies defined.") + tc.SetSkipped() + return -1 + + # Log dependencies + for k in pkgconfig.keys(): + if k.startswith("AcceptableDependencies"): + pkgstring = "\n".join(pkgconfig[k]) + if ("-" in k): + _, _, mod_type = k.partition("-") + tc.LogStdOut(f"Additional dependencies for MODULE_TYPE {mod_type}:\n {pkgstring}") + else: + tc.LogStdOut(f"Acceptable Dependencies:\n {pkgstring}") + + # For each INF file + for file in INFFiles: + ip = InfParser() + logging.debug("Parsing " + file) + ip.SetBaseAbsPath(Edk2pathObj.WorkspacePath).SetPackagePaths(Edk2pathObj.PackagePathList).ParseFile(file) + + if("MODULE_TYPE" not in ip.Dict): + tc.LogStdOut("Ignoring INF. Missing key for MODULE_TYPE {0}".format(file)) + continue + + mod_type = ip.Dict["MODULE_TYPE"].upper() + for p in ip.PackagesUsed: + if p not in pkgconfig["AcceptableDependencies"]: + # If not in the main acceptable dependencies list then check module specific + mod_specific_key = "AcceptableDependencies-" + mod_type + if mod_specific_key in pkgconfig and p in pkgconfig[mod_specific_key]: + continue + + logging.error("Dependency Check: Invalid Dependency INF: {0} depends on pkg {1}".format(file, p)) + tc.LogStdError("Dependency Check: Invalid Dependency INF: {0} depends on pkg {1}".format(file, p)) + overall_status += 1 + + # If XML object exists, add results + if overall_status != 0: + tc.SetFailed("Failed with {0} errors".format(overall_status), "DEPENDENCYCHECK_FAILED") + else: + tc.SetSuccess() + return overall_status diff --git a/.pytool/Plugin/DependencyCheck/DependencyCheck_plug_in.yaml b/.pytool/Plugin/DependencyCheck/DependencyCheck_plug_in.yaml new file mode 100644 index 00000000000..c9834697162 --- /dev/null +++ b/.pytool/Plugin/DependencyCheck/DependencyCheck_plug_in.yaml @@ -0,0 +1,13 @@ +## @file +# CiBuildPlugin used to check all infs within a package +# to confirm the packagesdependency are on the configured list of acceptable +# dependencies. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "cibuild", + "name": "Dependency Check Test", + "module": "DependencyCheck" +} diff --git a/.pytool/Plugin/DependencyCheck/Readme.md b/.pytool/Plugin/DependencyCheck/Readme.md new file mode 100644 index 00000000000..62612f69652 --- /dev/null +++ b/.pytool/Plugin/DependencyCheck/Readme.md @@ -0,0 +1,31 @@ +# Depdendency Check Plugin + +A CiBuildPlugin that finds all modules (inf files) in a package and reviews the +packages used to confirm they are acceptable. This is to help enforce layering +and identify improper dependencies between packages. + +## Configuration + +The plugin must be configured with the acceptabe package dependencies for the +package. + +``` yaml +"DependencyCheck": { + "AcceptableDependencies": [], + "AcceptableDependencies-": [], + "IgnoreInf": [] +} +``` + +### AcceptableDependencies + +Package dec files that are allowed in all INFs. Example: MdePkg/MdePkg.dec + +### AcceptableDependencies- + +OPTIONAL Package dependencies for INFs that have module type . +Example: AcceptableDependencies-HOST_APPLICATION. + +### IgnoreInf + +OPTIONAL list of INFs to ignore for this dependency check. diff --git a/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py b/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py new file mode 100644 index 00000000000..c613cd52334 --- /dev/null +++ b/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py @@ -0,0 +1,133 @@ +# @file DscCompleteCheck.py +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import logging +import os +from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin +from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser +from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser +from edk2toolext.environment.var_dict import VarDict + + +class DscCompleteCheck(ICiBuildPlugin): + """ + A CiBuildPlugin that scans the package dsc file and confirms all modules (inf files) are + listed in the components sections. + + Configuration options: + "DscCompleteCheck": { + "DscPath": "" + "IgnoreInf": [] # Ignore INF if found in filesystem by not dsc + } + """ + + def GetTestName(self, packagename: str, environment: VarDict) -> tuple: + """ Provide the testcase name and classname for use in reporting + + Args: + packagename: string containing name of package to build + environment: The VarDict for the test to run in + Returns: + a tuple containing the testcase name and the classname + (testcasename, classname) + testclassname: a descriptive string for the testcase can include whitespace + classname: should be patterned .. + """ + return ("Check the " + packagename + " DSC for a being complete", packagename + ".DscCompleteCheck") + + ## + # External function of plugin. This function is used to perform the task of the MuBuild Plugin + # + # - package is the edk2 path to package. This means workspace/packagepath relative. + # - edk2path object configured with workspace and packages path + # - PkgConfig Object (dict) for the pkg + # - VarDict containing the shell environment Build Vars + # - Plugin Manager Instance + # - Plugin Helper Obj Instance + # - Junit Logger + # - output_stream the StringIO output stream from this plugin via logging + def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None): + overall_status = 0 + + # Parse the config for required DscPath element + if "DscPath" not in pkgconfig: + tc.SetSkipped() + tc.LogStdError( + "DscPath not found in config file. Nothing to check.") + return -1 + + abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath( + packagename) + abs_dsc_path = os.path.join(abs_pkg_path, pkgconfig["DscPath"].strip()) + wsr_dsc_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath( + abs_dsc_path) + + if abs_dsc_path is None or wsr_dsc_path == "" or not os.path.isfile(abs_dsc_path): + tc.SetSkipped() + tc.LogStdError("Package Dsc not found") + return 0 + + # Get INF Files + INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path) + INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath( + x) for x in INFFiles] # make edk2relative path so can compare with DSC + + # remove ignores + + if "IgnoreInf" in pkgconfig: + for a in pkgconfig["IgnoreInf"]: + a = a.replace(os.sep, "/") + try: + tc.LogStdOut("Ignoring INF {0}".format(a)) + INFFiles.remove(a) + except: + tc.LogStdError( + "DscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a)) + logging.info( + "DscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a)) + + # DSC Parser + dp = DscParser() + dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath) + dp.SetPackagePaths(Edk2pathObj.PackagePathList) + dp.SetInputVars(environment.GetAllBuildKeyValues()) + dp.ParseFile(wsr_dsc_path) + + # Check if INF in component section + for INF in INFFiles: + if not any(INF.strip() in x for x in dp.ThreeMods) and \ + not any(INF.strip() in x for x in dp.SixMods) and \ + not any(INF.strip() in x for x in dp.OtherMods): + + infp = InfParser().SetBaseAbsPath(Edk2pathObj.WorkspacePath) + infp.SetPackagePaths(Edk2pathObj.PackagePathList) + infp.ParseFile(INF) + if("MODULE_TYPE" not in infp.Dict): + tc.LogStdOut( + "Ignoring INF. Missing key for MODULE_TYPE {0}".format(INF)) + continue + + if(infp.Dict["MODULE_TYPE"] == "HOST_APPLICATION"): + tc.LogStdOut( + "Ignoring INF. Module type is HOST_APPLICATION {0}".format(INF)) + continue + + if len(infp.SupportedPhases) == 1 and \ + "HOST_APPLICATION" in infp.SupportedPhases: + tc.LogStdOut( + "Ignoring Library INF due to only supporting type HOST_APPLICATION {0}".format(INF)) + continue + + logging.critical(INF + " not in " + wsr_dsc_path) + tc.LogStdError("{0} not in {1}".format(INF, wsr_dsc_path)) + overall_status = overall_status + 1 + + # If XML object exists, add result + if overall_status != 0: + tc.SetFailed("DscCompleteCheck {0} Failed. Errors {1}".format( + wsr_dsc_path, overall_status), "CHECK_FAILED") + else: + tc.SetSuccess() + return overall_status diff --git a/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck_plug_in.yaml b/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck_plug_in.yaml new file mode 100644 index 00000000000..215b8b76a95 --- /dev/null +++ b/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck_plug_in.yaml @@ -0,0 +1,12 @@ +## @file +# CiBuildPlugin used to confirm all INFs are listed in +# the components section of package dsc +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "cibuild", + "name": "Dsc Complete Check Test", + "module": "DscCompleteCheck" +} diff --git a/.pytool/Plugin/DscCompleteCheck/Readme.md b/.pytool/Plugin/DscCompleteCheck/Readme.md new file mode 100644 index 00000000000..8aaa4f76ee0 --- /dev/null +++ b/.pytool/Plugin/DscCompleteCheck/Readme.md @@ -0,0 +1,32 @@ +# Dsc Complete Check Plugin + +This CiBuildPlugin scans all INF files from a package and confirms they are +listed in the package level DSC file. The test considers it an error if any INF +does not appear in the `Components` section of the package-level DSC (indicating +that it would not be built if the package were built). This is critical because +much of the CI infrastructure assumes that all modules will be listed in the DSC +and compiled. + +This test will ignore INFs in the following cases: + +1. When MODULE_TYPE = HOST_APPLICATION +2. When a Library instance **only** supports the HOST_APPLICATION environment + +## Configuration + +The plugin has a few configuration options to support the UEFI codebase. + +``` yaml +"DscCompleteCheck": { + "DscPath": "", # Path to dsc from root of package + "IgnoreInf": [] # Ignore INF if found in filesystem but not dsc + } +``` + +### DscPath + +Path to DSC to consider platform dsc + +### IgnoreInf + +Ignore error if Inf file is not listed in DSC file diff --git a/.pytool/Plugin/GuidCheck/GuidCheck.py b/.pytool/Plugin/GuidCheck/GuidCheck.py new file mode 100644 index 00000000000..61fdc779112 --- /dev/null +++ b/.pytool/Plugin/GuidCheck/GuidCheck.py @@ -0,0 +1,251 @@ +# @file GuidCheck.py +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import logging +from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin +from edk2toollib.uefi.edk2.guid_list import GuidList +from edk2toolext.environment.var_dict import VarDict + + +class GuidCheck(ICiBuildPlugin): + """ + A CiBuildPlugin that scans the code tree and looks for duplicate guids + from the package being tested. + + Configuration options: + "GuidCheck": { + "IgnoreGuidName": [], # provide in format guidname=guidvalue or just guidname + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [] # Provide in format guidname=guidname=guidname... + } + """ + + def GetTestName(self, packagename: str, environment: VarDict) -> tuple: + """ Provide the testcase name and classname for use in reporting + + Args: + packagename: string containing name of package to build + environment: The VarDict for the test to run in + Returns: + a tuple containing the testcase name and the classname + (testcasename, classname) + testclassname: a descriptive string for the testcase can include whitespace + classname: should be patterned .. + """ + return ("Confirm GUIDs are unique in " + packagename, packagename + ".GuidCheck") + + def _FindConflictingGuidValues(self, guidlist: list) -> list: + """ Find all duplicate guids by guid value and report them as errors + """ + # Sort the list by guid + guidsorted = sorted( + guidlist, key=lambda x: x.guid.upper(), reverse=True) + + previous = None # Store previous entry for comparison + error = None + errors = [] + for index in range(len(guidsorted)): + i = guidsorted[index] + if(previous is not None): + if i.guid == previous.guid: # Error + if(error is None): + # Catch errors with more than 1 conflict + error = ErrorEntry("guid") + error.entries.append(previous) + errors.append(error) + error.entries.append(i) + else: + # no match. clear error + error = None + previous = i + return errors + + def _FindConflictingGuidNames(self, guidlist: list) -> list: + """ Find all duplicate guids by name and if they are not all + from inf files report them as errors. It is ok to have + BASE_NAME duplication. + + Is this useful? It would catch two same named guids in dec file + that resolve to different values. + """ + # Sort the list by guid + namesorted = sorted(guidlist, key=lambda x: x.name.upper()) + + previous = None # Store previous entry for comparison + error = None + errors = [] + for index in range(len(namesorted)): + i = namesorted[index] + if(previous is not None): + # If name matches + if i.name == previous.name: + if(error is None): + # Catch errors with more than 1 conflict + error = ErrorEntry("name") + error.entries.append(previous) + errors.append(error) + error.entries.append(i) + else: + # no match. clear error + error = None + previous = i + + # Loop thru and remove any errors where all files are infs as it is ok if + # they have the same inf base name. + for e in errors[:]: + if len( [en for en in e.entries if not en.absfilepath.lower().endswith(".inf")]) == 0: + errors.remove(e) + + return errors + + ## + # External function of plugin. This function is used to perform the task of the MuBuild Plugin + # + # - package is the edk2 path to package. This means workspace/packagepath relative. + # - edk2path object configured with workspace and packages path + # - PkgConfig Object (dict) for the pkg + # - EnvConfig Object + # - Plugin Manager Instance + # - Plugin Helper Obj Instance + # - Junit Logger + # - output_stream the StringIO output stream from this plugin via logging + + def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None): + Errors = [] + + abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath( + packagename) + + if abs_pkg_path is None: + tc.SetSkipped() + tc.LogStdError("No package {0}".format(packagename)) + return -1 + + All_Ignores = ["/Build", "/Conf"] + # Parse the config for other ignores + if "IgnoreFoldersAndFiles" in pkgconfig: + All_Ignores.extend(pkgconfig["IgnoreFoldersAndFiles"]) + + # Parse the workspace for all GUIDs + gs = GuidList.guidlist_from_filesystem( + Edk2pathObj.WorkspacePath, ignore_lines=All_Ignores) + + # Remove ignored guidvalue + if "IgnoreGuidValue" in pkgconfig: + for a in pkgconfig["IgnoreGuidValue"]: + try: + tc.LogStdOut("Ignoring Guid {0}".format(a.upper())) + for b in gs[:]: + if b.guid == a.upper(): + gs.remove(b) + except: + tc.LogStdError("GuidCheck.IgnoreGuid -> {0} not found. Invalid ignore guid".format(a.upper())) + logging.info("GuidCheck.IgnoreGuid -> {0} not found. Invalid ignore guid".format(a.upper())) + + # Remove ignored guidname + if "IgnoreGuidName" in pkgconfig: + for a in pkgconfig["IgnoreGuidName"]: + entry = a.split("=") + if(len(entry) > 2): + tc.LogStdError("GuidCheck.IgnoreGuidName -> {0} Invalid Format.".format(a)) + logging.info("GuidCheck.IgnoreGuidName -> {0} Invalid Format.".format(a)) + continue + try: + tc.LogStdOut("Ignoring Guid {0}".format(a)) + for b in gs[:]: + if b.name == entry[0]: + if(len(entry) == 1): + gs.remove(b) + elif(len(entry) == 2 and b.guid.upper() == entry[1].upper()): + gs.remove(b) + else: + c.LogStdError("GuidCheck.IgnoreGuidName -> {0} incomplete match. Invalid ignore guid".format(a)) + + except: + tc.LogStdError("GuidCheck.IgnoreGuidName -> {0} not found. Invalid ignore name".format(a)) + logging.info("GuidCheck.IgnoreGuidName -> {0} not found. Invalid ignore name".format(a)) + + # Find conflicting Guid Values + Errors.extend(self._FindConflictingGuidValues(gs)) + + # Check if there are expected duplicates and remove it from the error list + if "IgnoreDuplicates" in pkgconfig: + for a in pkgconfig["IgnoreDuplicates"]: + names = a.split("=") + if len(names) < 2: + tc.LogStdError("GuidCheck.IgnoreDuplicates -> {0} invalid format".format(a)) + logging.info("GuidCheck.IgnoreDuplicates -> {0} invalid format".format(a)) + continue + + for b in Errors[:]: + if b.type != "guid": + continue + ## Make a list of the names that are not in the names list. If there + ## are any in the list then this error should not be ignored. + t = [x for x in b.entries if x.name not in names] + if(len(t) == len(b.entries)): + ## did not apply to any entry + continue + elif(len(t) == 0): + ## full match - ignore duplicate + tc.LogStdOut("GuidCheck.IgnoreDuplicates -> {0}".format(a)) + Errors.remove(b) + elif(len(t) < len(b.entries)): + ## partial match + tc.LogStdOut("GuidCheck.IgnoreDuplicates -> {0} incomplete match".format(a)) + logging.info("GuidCheck.IgnoreDuplicates -> {0} incomplete match".format(a)) + else: + tc.LogStdOut("GuidCheck.IgnoreDuplicates -> {0} unknown error.".format(a)) + logging.info("GuidCheck.IgnoreDuplicates -> {0} unknown error".format(a)) + + + + # Find conflicting Guid Names + Errors.extend(self._FindConflictingGuidNames(gs)) + + # Log errors for anything within the package under test + for er in Errors[:]: + InMyPackage = False + for a in er.entries: + if abs_pkg_path in a.absfilepath: + InMyPackage = True + break + if(not InMyPackage): + Errors.remove(er) + else: + logging.error(str(er)) + tc.LogStdError(str(er)) + + # add result to test case + overall_status = len(Errors) + if overall_status != 0: + tc.SetFailed("GuidCheck {0} Failed. Errors {1}".format( + packagename, overall_status), "CHECK_FAILED") + else: + tc.SetSuccess() + return overall_status + + +class ErrorEntry(): + """ Custom/private class for reporting errors in the GuidList + """ + + def __init__(self, errortype): + self.type = errortype # 'guid' or 'name' depending on error type + self.entries = [] # GuidListEntry that are in error condition + + def __str__(self): + a = f"Error Duplicate {self.type}: " + if(self.type == "guid"): + a += f" {self.entries[0].guid}" + elif(self.type == "name"): + a += f" {self.entries[0].name}" + + a += f" ({len(self.entries)})\n" + + for e in self.entries: + a += "\t" + str(e) + "\n" + return a diff --git a/.pytool/Plugin/GuidCheck/GuidCheck_plug_in.yaml b/.pytool/Plugin/GuidCheck/GuidCheck_plug_in.yaml new file mode 100644 index 00000000000..b16f6c16b67 --- /dev/null +++ b/.pytool/Plugin/GuidCheck/GuidCheck_plug_in.yaml @@ -0,0 +1,11 @@ +## @file +# CiBuildPlugin used to check guid uniqueness +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "cibuild", + "name": "Guid Check Test", + "module": "GuidCheck" +} diff --git a/.pytool/Plugin/GuidCheck/Readme.md b/.pytool/Plugin/GuidCheck/Readme.md new file mode 100644 index 00000000000..4e2c353cc44 --- /dev/null +++ b/.pytool/Plugin/GuidCheck/Readme.md @@ -0,0 +1,80 @@ +# Guid Check Plugin + +This CiBuildPlugin scans all the files in a code tree to find all the GUID +definitions. After collection it will then look for duplication in the package +under test. Uniqueness of all GUIDs are critical within the UEFI environment. +Duplication can cause numerous issues including locating the wrong data +structure, calling the wrong function, or decoding the wrong data members. + +Currently Scanned: + +* INF files are scanned for there Module guid +* DEC files are scanned for all of their Protocols, PPIs, and Guids as well as + the one package GUID. + +Any GUID value being equal to two names or even just defined in two files is +considered an error unless in the ignore list. + +Any GUID name that is found more than once is an error unless all occurrences +are Module GUIDs. Since the Module GUID is assigned to the Module name it is +common to have numerous versions of the same module named the same. + +## Configuration + +The plugin has numerous configuration options to support the UEFI codebase. + +``` yaml +"GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [] + } +``` + +### IgnoreGuidName + +This list allows strings in two formats. + +* _GuidName_ + * This will remove any entry with this GuidName from the list of GUIDs + therefore ignoring any error associated with this name. +* _GuidName=GuidValue_ + * This will also ignore the GUID by name but only if the value equals the + GuidValue. + * GuidValue should be in registry format. + * This is the suggested format to use as it will limit the ignore to only the + defined case. + +### IgnoreGuidValue + +This list allows strings in guid registry format _GuidValue_. + +* This will remove any entry with this GuidValue from the list of GUIDs + therefore ignoring any error associated with this value. +* GuidValue must be in registry format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + +### IgnoreFoldersAndFiles + +This supports .gitignore file and folder matching strings including wildcards + +* Any folder or file ignored will not be parsed and therefore any GUID defined + will be ignored. +* The plugin will always ignores the following ["/Build", "/Conf"] + +### IgnoreDuplicates + +This supports strings in the format of _GuidName_=_GuidName_=_GuidName_ + +* For the error with the GuidNames to be ignored the list must match completely + with what is found during the code scan. + * For example if there are two GUIDs that are by design equal within the code + tree then it should be _GuidName_=_GuidName_ + * If instead there are three GUIDs then it must be + _GuidName_=_GuidName_=_GuidName_ +* This is the best ignore list to use because it is the most strict and will + catch new problems when new conflicts are introduced. +* There are numerous places in the UEFI specification in which two GUID names + are assigned the same value. These names should be set in this ignore list so + that they don't cause an error but any additional duplication would still be + caught. diff --git a/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompilerPlugin.py b/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompilerPlugin.py new file mode 100644 index 00000000000..389088a7605 --- /dev/null +++ b/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompilerPlugin.py @@ -0,0 +1,149 @@ +# @file HostUnitTestCompilerPlugin.py +## +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +import logging +import os +import re +from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser +from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin +from edk2toolext.environment.uefi_build import UefiBuilder +from edk2toolext import edk2_logging +from edk2toolext.environment.var_dict import VarDict +from edk2toollib.utility_functions import GetHostInfo + + +class HostUnitTestCompilerPlugin(ICiBuildPlugin): + """ + A CiBuildPlugin that compiles the dsc for host based unit test apps. + An IUefiBuildPlugin may be attached to this plugin that will run the + unit tests and collect the results after successful compilation. + + Configuration options: + "HostUnitTestCompilerPlugin": { + "DscPath": "" + } + """ + + def GetTestName(self, packagename: str, environment: VarDict) -> tuple: + """ Provide the testcase name and classname for use in reporting + testclassname: a descriptive string for the testcase can include whitespace + classname: should be patterned .. + + Args: + packagename: string containing name of package to build + environment: The VarDict for the test to run in + Returns: + a tuple containing the testcase name and the classname + (testcasename, classname) + """ + num,types = self.__GetHostUnitTestArch(environment) + types = types.replace(" ", "_") + + return ("Compile and Run Host-Based UnitTests for " + packagename + " on arch " + types, + packagename + ".HostUnitTestCompiler." + types) + + def RunsOnTargetList(self): + return ["NOOPT"] + + # + # Find the intersection of application types that can run on this host + # and the TARGET_ARCH being build in this request. + # + # return tuple with (number of UEFI arch types, space separated string) + def __GetHostUnitTestArch(self, environment): + requested = environment.GetValue("TARGET_ARCH").split(' ') + host = [] + if GetHostInfo().arch == 'x86': + #assume 64bit can handle 64 and 32 + #assume 32bit can only handle 32 + ## change once IA32 issues resolved host.append("IA32") + if GetHostInfo().bit == '64': + host.append("X64") + elif GetHostInfo().arch == 'ARM': + if GetHostInfo().bit == '64': + host.append("AARCH64") + elif GetHostInfo().bit == '32': + host.append("ARM") + + willrun = set(requested) & set(host) + return (len(willrun), " ".join(willrun)) + + + ## + # External function of plugin. This function is used to perform the task of the ICiBuildPlugin Plugin + # + # - package is the edk2 path to package. This means workspace/packagepath relative. + # - edk2path object configured with workspace and packages path + # - PkgConfig Object (dict) for the pkg + # - EnvConfig Object + # - Plugin Manager Instance + # - Plugin Helper Obj Instance + # - Junit Logger + # - output_stream the StringIO output stream from this plugin via logging + def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None): + self._env = environment + environment.SetValue("CI_BUILD_TYPE", "host_unit_test", "Set in HostUnitTestCompilerPlugin") + + # Parse the config for required DscPath element + if "DscPath" not in pkgconfig: + tc.SetSkipped() + tc.LogStdError("DscPath not found in config file. Nothing to compile for HostBasedUnitTests.") + return -1 + + AP = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename) + + APDSC = os.path.join(AP, pkgconfig["DscPath"].strip()) + AP_Path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(APDSC) + if AP is None or AP_Path is None or not os.path.isfile(APDSC): + tc.SetSkipped() + tc.LogStdError("Package HostBasedUnitTest Dsc not found.") + return -1 + + logging.info("Building {0}".format(AP_Path)) + self._env.SetValue("ACTIVE_PLATFORM", AP_Path, "Set in Compiler Plugin") + num, RUNNABLE_ARCHITECTURES = self.__GetHostUnitTestArch(environment) + if(num == 0): + tc.SetSkipped() + tc.LogStdError("No host architecture compatibility") + return -1 + + if not environment.SetValue("TARGET_ARCH", + RUNNABLE_ARCHITECTURES, + "Update Target Arch based on Host Support"): + #use AllowOverride function since this is a controlled attempt to change + environment.AllowOverride("TARGET_ARCH") + if not environment.SetValue("TARGET_ARCH", + RUNNABLE_ARCHITECTURES, + "Update Target Arch based on Host Support"): + raise RuntimeError("Can't Change TARGET_ARCH as required") + + # Parse DSC to check for SUPPORTED_ARCHITECTURES + dp = DscParser() + dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath) + dp.SetPackagePaths(Edk2pathObj.PackagePathList) + dp.ParseFile(AP_Path) + if "SUPPORTED_ARCHITECTURES" in dp.LocalVars: + SUPPORTED_ARCHITECTURES = dp.LocalVars["SUPPORTED_ARCHITECTURES"].split('|') + TARGET_ARCHITECTURES = environment.GetValue("TARGET_ARCH").split(' ') + + # Skip if there is no intersection between SUPPORTED_ARCHITECTURES and TARGET_ARCHITECTURES + if len(set(SUPPORTED_ARCHITECTURES) & set(TARGET_ARCHITECTURES)) == 0: + tc.SetSkipped() + tc.LogStdError("No supported architecutres to build for host unit tests") + return -1 + + uefiBuilder = UefiBuilder() + # do all the steps + # WorkSpace, PackagesPath, PInHelper, PInManager + ret = uefiBuilder.Go(Edk2pathObj.WorkspacePath, os.pathsep.join(Edk2pathObj.PackagePathList), PLMHelper, PLM) + if ret != 0: # failure: + tc.SetFailed("Compile failed for {0}".format(packagename), "Compile_FAILED") + tc.LogStdError("{0} Compile failed with error code {1} ".format(AP_Path, ret)) + return 1 + + else: + tc.SetSuccess() + return 0 diff --git a/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompiler_plug_in.yaml b/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompiler_plug_in.yaml new file mode 100644 index 00000000000..6c9fa9d6998 --- /dev/null +++ b/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompiler_plug_in.yaml @@ -0,0 +1,12 @@ +## +# CiBuildPlugin used to build anything that identifies +# as a unit test. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "host-based-test", + "name": "Host Unit Test Compiler Plugin", + "module": "HostUnitTestCompilerPlugin" +} \ No newline at end of file diff --git a/.pytool/Plugin/HostUnitTestCompilerPlugin/Readme.md b/.pytool/Plugin/HostUnitTestCompilerPlugin/Readme.md new file mode 100644 index 00000000000..f0def4c55c1 --- /dev/null +++ b/.pytool/Plugin/HostUnitTestCompilerPlugin/Readme.md @@ -0,0 +1,24 @@ +# Host UnitTest Compiler Plugin + +A CiBuildPlugin that compiles the dsc for host based unit test apps. +An IUefiBuildPlugin may be attached to this plugin that will run the unit tests and collect the results after successful compilation. + +## Configuration + +The package relative path of the DSC file to build. + +``` yaml +"HostUnitTestCompilerPlugin": { + "DscPath": "" +} +``` + +### DscPath + +Package relative path to the DSC file to build. + +## Copyright + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + diff --git a/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCompleteCheck.py b/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCompleteCheck.py new file mode 100644 index 00000000000..79dffe8f7de --- /dev/null +++ b/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCompleteCheck.py @@ -0,0 +1,140 @@ +# @file HostUnitTestDscCompleteCheck.py +# +# This is a copy of DscCompleteCheck with different filtering logic. +# It should be discussed if this should be one plugin +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import logging +import os +from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin +from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser +from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser +from edk2toolext.environment.var_dict import VarDict + + +class HostUnitTestDscCompleteCheck(ICiBuildPlugin): + """ + A CiBuildPlugin that scans the package Host Unit Test dsc file and confirms all Host application modules (inf files) are + listed in the components sections. + + Configuration options: + "HostUnitTestDscCompleteCheck": { + "DscPath": "", # Path to Host based unit test DSC file + "IgnoreInf": [] # Ignore INF if found in filesystem but not dsc + } + """ + + def GetTestName(self, packagename: str, environment: VarDict) -> tuple: + """ Provide the testcase name and classname for use in reporting + + Args: + packagename: string containing name of package to build + environment: The VarDict for the test to run in + Returns: + a tuple containing the testcase name and the classname + (testcasename, classname) + testclassname: a descriptive string for the testcase can include whitespace + classname: should be patterned .. + """ + return ("Check the " + packagename + " Host Unit Test DSC for a being complete", packagename + ".HostUnitTestDscCompleteCheck") + + ## + # External function of plugin. This function is used to perform the task of the MuBuild Plugin + # + # - package is the edk2 path to package. This means workspace/packagepath relative. + # - edk2path object configured with workspace and packages path + # - PkgConfig Object (dict) for the pkg + # - VarDict containing the shell environment Build Vars + # - Plugin Manager Instance + # - Plugin Helper Obj Instance + # - Junit Logger + # - output_stream the StringIO output stream from this plugin via logging + def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None): + overall_status = 0 + + # Parse the config for required DscPath element + if "DscPath" not in pkgconfig: + tc.SetSkipped() + tc.LogStdError( + "DscPath not found in config file. Nothing to check.") + return -1 + + abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath( + packagename) + abs_dsc_path = os.path.join(abs_pkg_path, pkgconfig["DscPath"].strip()) + wsr_dsc_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath( + abs_dsc_path) + + if abs_dsc_path is None or wsr_dsc_path == "" or not os.path.isfile(abs_dsc_path): + tc.SetSkipped() + tc.LogStdError("Package Host Unit Test Dsc not found") + return 0 + + # Get INF Files + INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path) + INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath( + x) for x in INFFiles] # make edk2relative path so can compare with DSC + + # remove ignores + + if "IgnoreInf" in pkgconfig: + for a in pkgconfig["IgnoreInf"]: + a = a.replace(os.sep, "/") + try: + tc.LogStdOut("Ignoring INF {0}".format(a)) + INFFiles.remove(a) + except: + tc.LogStdError( + "HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a)) + logging.info( + "HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a)) + + # DSC Parser + dp = DscParser() + dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath) + dp.SetPackagePaths(Edk2pathObj.PackagePathList) + dp.SetInputVars(environment.GetAllBuildKeyValues()) + dp.ParseFile(wsr_dsc_path) + + # Check if INF in component section + for INF in INFFiles: + if not any(INF.strip() in x for x in dp.ThreeMods) and \ + not any(INF.strip() in x for x in dp.SixMods) and \ + not any(INF.strip() in x for x in dp.OtherMods): + + infp = InfParser().SetBaseAbsPath(Edk2pathObj.WorkspacePath) + infp.SetPackagePaths(Edk2pathObj.PackagePathList) + infp.ParseFile(INF) + if("MODULE_TYPE" not in infp.Dict): + tc.LogStdOut( + "Ignoring INF. Missing key for MODULE_TYPE {0}".format(INF)) + continue + + if(infp.Dict["MODULE_TYPE"] == "HOST_APPLICATION"): + # should compile test a library that is declared type HOST_APPLICATION + pass + + elif len(infp.SupportedPhases) > 0 and \ + "HOST_APPLICATION" in infp.SupportedPhases: + # should compile test a library that supports HOST_APPLICATION but + # require it to be an explicit opt-in + pass + + else: + tc.LogStdOut( + "Ignoring INF. MODULE_TYPE or suppored phases not HOST_APPLICATION {0}".format(INF)) + continue + + logging.critical(INF + " not in " + wsr_dsc_path) + tc.LogStdError("{0} not in {1}".format(INF, wsr_dsc_path)) + overall_status = overall_status + 1 + + # If XML object exists, add result + if overall_status != 0: + tc.SetFailed("HostUnitTestDscCompleteCheck {0} Failed. Errors {1}".format( + wsr_dsc_path, overall_status), "CHECK_FAILED") + else: + tc.SetSuccess() + return overall_status diff --git a/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCompleteCheck_plug_in.yaml b/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCompleteCheck_plug_in.yaml new file mode 100644 index 00000000000..a93e8f43c67 --- /dev/null +++ b/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCompleteCheck_plug_in.yaml @@ -0,0 +1,12 @@ +## +# CiBuildPlugin used to confirm all INFs are listed in +# the components section of package dsc +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "host-based-test", + "name": "Host Unit Test Dsc Complete Check Test", + "module": "HostUnitTestDscCompleteCheck" + } \ No newline at end of file diff --git a/.pytool/Plugin/HostUnitTestDscCompleteCheck/Readme.md b/.pytool/Plugin/HostUnitTestDscCompleteCheck/Readme.md new file mode 100644 index 00000000000..d77a1f2af18 --- /dev/null +++ b/.pytool/Plugin/HostUnitTestDscCompleteCheck/Readme.md @@ -0,0 +1,32 @@ +# Host Unit Test Dsc Complete Check Plugin + +This CiBuildPlugin scans all INF files from a package for those related to host +based unit tests confirms they are listed in the unit test DSC file for the package. +The test considers it an error if any INF meeting the requirements does not appear +in the `Components` section of the unit test DSC. This is critical because +much of the CI infrastructure assumes that modules will be listed in the DSC +and compiled. + +This test will only require INFs in the following cases: + +1. When MODULE_TYPE = HOST_APPLICATION +2. When a Library instance supports the HOST_APPLICATION environment + +## Configuration + +The plugin has a few configuration options to support the UEFI codebase. + +``` yaml +"HostUnitTestDscCompleteCheck": { + "DscPath": "", # Path to Host based unit test DSC file + "IgnoreInf": [] # Ignore INF if found in filesystem but not dsc +} +``` + +### DscPath + +Path to DSC to consider platform dsc + +### IgnoreInf + +Ignore error if Inf file is not listed in DSC file diff --git a/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py b/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py new file mode 100644 index 00000000000..20d87f13f52 --- /dev/null +++ b/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py @@ -0,0 +1,153 @@ +# @file LibraryClassCheck.py +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import logging +import os +from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin +from edk2toollib.uefi.edk2.parsers.dec_parser import DecParser +from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser +from edk2toolext.environment.var_dict import VarDict + + +class LibraryClassCheck(ICiBuildPlugin): + """ + A CiBuildPlugin that scans the code tree and library classes for undeclared + files + + Configuration options: + "LibraryClassCheck": { + IgnoreHeaderFile: [], # Ignore a file found on disk + IgnoreLibraryClass: [] # Ignore a declaration found in dec file + } + """ + + def GetTestName(self, packagename: str, environment: VarDict) -> tuple: + """ Provide the testcase name and classname for use in reporting + testclassname: a descriptive string for the testcase can include whitespace + classname: should be patterned .. + + Args: + packagename: string containing name of package to build + environment: The VarDict for the test to run in + Returns: + a tuple containing the testcase name and the classname + (testcasename, classname) + """ + return ("Check library class declarations in " + packagename, packagename + ".LibraryClassCheck") + + def __GetPkgDec(self, rootpath): + try: + allEntries = os.listdir(rootpath) + for entry in allEntries: + if entry.lower().endswith(".dec"): + return(os.path.join(rootpath, entry)) + except Exception: + logging.error("Unable to find DEC for package:{0}".format(rootpath)) + + return None + + ## + # External function of plugin. This function is used to perform the task of the MuBuild Plugin + # + # - package is the edk2 path to package. This means workspace/packagepath relative. + # - edk2path object configured with workspace and packages path + # - PkgConfig Object (dict) for the pkg + # - EnvConfig Object + # - Plugin Manager Instance + # - Plugin Helper Obj Instance + # - Junit Logger + # - output_stream the StringIO output stream from this plugin via logging + def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None): + overall_status = 0 + LibraryClassIgnore = [] + + abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename) + abs_dec_path = self.__GetPkgDec(abs_pkg_path) + wsr_dec_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(abs_dec_path) + + if abs_dec_path is None or wsr_dec_path == "" or not os.path.isfile(abs_dec_path): + tc.SetSkipped() + tc.LogStdError("No DEC file {0} in package {1}".format(abs_dec_path, abs_pkg_path)) + return -1 + + # Get all include folders + dec = DecParser() + dec.SetBaseAbsPath(Edk2pathObj.WorkspacePath).SetPackagePaths(Edk2pathObj.PackagePathList) + dec.ParseFile(wsr_dec_path) + + AllHeaderFiles = [] + + for includepath in dec.IncludePaths: + ## Get all header files in the library folder + AbsLibraryIncludePath = os.path.join(abs_pkg_path, includepath, "Library") + if(not os.path.isdir(AbsLibraryIncludePath)): + continue + + hfiles = self.WalkDirectoryForExtension([".h"], AbsLibraryIncludePath) + hfiles = [os.path.relpath(x,abs_pkg_path) for x in hfiles] # make package root relative path + hfiles = [x.replace("\\", "/") for x in hfiles] # make package relative path + + AllHeaderFiles.extend(hfiles) + + if len(AllHeaderFiles) == 0: + tc.SetSkipped() + tc.LogStdError(f"No Library include folder in any Include path") + return -1 + + # Remove ignored paths + if "IgnoreHeaderFile" in pkgconfig: + for a in pkgconfig["IgnoreHeaderFile"]: + try: + tc.LogStdOut("Ignoring Library Header File {0}".format(a)) + AllHeaderFiles.remove(a) + except: + tc.LogStdError("LibraryClassCheck.IgnoreHeaderFile -> {0} not found. Invalid Header File".format(a)) + logging.info("LibraryClassCheck.IgnoreHeaderFile -> {0} not found. Invalid Header File".format(a)) + + if "IgnoreLibraryClass" in pkgconfig: + LibraryClassIgnore = pkgconfig["IgnoreLibraryClass"] + + + ## Attempt to find library classes + for lcd in dec.LibraryClasses: + ## Check for correct file path separator + if "\\" in lcd.path: + tc.LogStdError("LibraryClassCheck.DecFilePathSeparator -> {0} invalid.".format(lcd.path)) + logging.error("LibraryClassCheck.DecFilePathSeparator -> {0} invalid.".format(lcd.path)) + overall_status += 1 + continue + + if lcd.name in LibraryClassIgnore: + tc.LogStdOut("Ignoring Library Class Name {0}".format(lcd.name)) + LibraryClassIgnore.remove(lcd.name) + continue + + logging.debug(f"Looking for Library Class {lcd.path}") + try: + AllHeaderFiles.remove(lcd.path) + + except ValueError: + tc.LogStdError(f"Library {lcd.name} with path {lcd.path} not found in package filesystem") + logging.error(f"Library {lcd.name} with path {lcd.path} not found in package filesystem") + overall_status += 1 + + ## any remaining AllHeaderFiles are not described in DEC + for h in AllHeaderFiles: + tc.LogStdError(f"Library Header File {h} not declared in package DEC {wsr_dec_path}") + logging.error(f"Library Header File {h} not declared in package DEC {wsr_dec_path}") + overall_status += 1 + + ## Warn about any invalid library class names in the ignore list + for r in LibraryClassIgnore: + tc.LogStdError("LibraryClassCheck.IgnoreLibraryClass -> {0} not found. Library Class not found".format(r)) + logging.info("LibraryClassCheck.IgnoreLibraryClass -> {0} not found. Library Class not found".format(r)) + + + # If XML object exists, add result + if overall_status != 0: + tc.SetFailed("LibraryClassCheck {0} Failed. Errors {1}".format(wsr_dec_path, overall_status), "CHECK_FAILED") + else: + tc.SetSuccess() + return overall_status diff --git a/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml b/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml new file mode 100644 index 00000000000..f90eec32ff6 --- /dev/null +++ b/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml @@ -0,0 +1,11 @@ +## @file +# CiBuildPlugin used to check that all library classes are declared correctly in dec file +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "cibuild", + "name": "Library Class Check Test", + "module": "LibraryClassCheck" +} diff --git a/.pytool/Plugin/LibraryClassCheck/Readme.md b/.pytool/Plugin/LibraryClassCheck/Readme.md new file mode 100644 index 00000000000..7fa2b202f24 --- /dev/null +++ b/.pytool/Plugin/LibraryClassCheck/Readme.md @@ -0,0 +1,25 @@ +# Library Class Check Plugin + +This CiBuildPlugin scans at all library header files found in the `Library` +folders in all of the package's declared include directories and ensures that +all files have a matching LibraryClass declaration in the DEC file for the +package. Any missing declarations will cause a failure. + +## Configuration + +The plugin has a few configuration options to support the UEFI codebase. + +``` yaml +"LibraryClassCheck": { + IgnoreHeaderFile: [], # Ignore a file found on disk + IgnoreLibraryClass: [] # Ignore a declaration found in dec file +} +``` + +### IgnoreHeaderFile + +Ignore a file found on disk + +### IgnoreLibraryClass + +Ignore a declaration found in dec file diff --git a/.pytool/Plugin/SpellCheck/Readme.md b/.pytool/Plugin/SpellCheck/Readme.md new file mode 100644 index 00000000000..394bb8effc8 --- /dev/null +++ b/.pytool/Plugin/SpellCheck/Readme.md @@ -0,0 +1,127 @@ +# Spell Check Plugin + +This CiBuildPlugin scans all the files in a given package and checks for +spelling errors. + +This plugin requires NodeJs and cspell. If the plugin doesn't find its required +tools then it will mark the test as skipped. + +* NodeJS: https://nodejs.org/en/ +* cspell: https://www.npmjs.com/package/cspell + * Src and doc available: https://github.com/streetsidesoftware/cspell + +## Configuration + +The plugin has a few configuration options to support the UEFI codebase. + +``` yaml + "SpellCheck": { + "AuditOnly": False, # If True, log all errors and then mark as skipped + "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files + "ExtendWords": [], # words to extend to the dictionary for this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + } +``` + +### AuditOnly + +Boolean - Default is False. +If True run the test in an Audit only mode which will log all errors but instead +of failing the build it will set the test as skipped. This allows visibility +into the failures without breaking the build. + +### IgnoreFiles + +This supports .gitignore file and folder matching strings including wildcards + +* All files will be parsed regardless but then any spelling errors found within + ignored files will not be reported as an error. +* Errors in ignored files will still be output to the test results as + informational comments. + +### ExtendWords + +This list allows words to be added to the dictionary for the spell checker when +this package is tested. These follow the rules of the cspell config words field. + +### IgnoreStandardPaths + +This plugin by default will check the below standard paths. If the package +would like to ignore any of them list that here. + +```python +[ +# C source +"*.c", +"*.h", + +# Assembly files +"*.nasm", +"*.asm", +"*.masm", +"*.s", + +# ACPI source language +"*.asl", + +# Edk2 build files +"*.dsc", "*.dec", "*.fdf", "*.inf", + +# Documentation files +"*.md", "*.txt" +] +``` + +### AdditionalIncludePaths + +If the package would to add additional path patterns to be included in +spellchecking they can be defined here. + +## Other configuration + +In the cspell.base.json there are numerous other settings configured. There is +no support to override these on a per package basis but future features could +make this available. One interesting configuration option is `minWordLength`. +Currently it is set to _5_ which means all 2,3, and 4 letter words will be +ignored. This helps minimize the number of technical acronyms, register names, +and other UEFI specific values that must be ignored. + +## False positives + +The cspell dictionary is not perfect and there are cases where technical words +or acronyms are not found in the dictionary. There are three ways to resolve +false positives and the choice for which method should be based on how broadly +the word should be accepted. + +### CSpell Base Config file + +If the change should apply to all UEFI code and documentation then it should be +added to the base config file `words` section. The base config file is adjacent +to this file and titled `cspell.base.json`. This is a list of accepted words +for all spell checking operations on all packages. + +### Package Config + +In the package `*.ci.yaml` file there is a `SpellCheck` config section. This +section allows files to be ignored as well as words that should be considered +valid for all files within this package. Add the desired words to the +"ExtendedWords" member. + +### In-line File + +CSpell supports numerous methods to annotate your files to ignore words, +sections, etc. This can be found in CSpell documentation. Suggestion here is +to use a c-style comment at the top of the file to add words that should be +ignored just for this file. Obviously this has the highest maintenance cost so +it should only be used for file unique words. + +``` c +// spell-checker:ignore unenroll, word2, word3 +``` + +or + +```ini +# spell-checker:ignore unenroll, word2, word3 +``` diff --git a/.pytool/Plugin/SpellCheck/SpellCheck.py b/.pytool/Plugin/SpellCheck/SpellCheck.py new file mode 100644 index 00000000000..43365441b91 --- /dev/null +++ b/.pytool/Plugin/SpellCheck/SpellCheck.py @@ -0,0 +1,216 @@ +# @file SpellCheck.py +# +# An edk2-pytool based plugin wrapper for cspell +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import logging +import json +import yaml +from io import StringIO +import os +from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin +from edk2toollib.utility_functions import RunCmd +from edk2toolext.environment.var_dict import VarDict +from edk2toollib.gitignore_parser import parse_gitignore_lines +from edk2toolext.environment import version_aggregator + + +class SpellCheck(ICiBuildPlugin): + """ + A CiBuildPlugin that uses the cspell node module to scan the files + from the package being tested for spelling errors. The plugin contains + the base cspell.json file then thru the configuration options other settings + can be changed or extended. + + Configuration options: + "SpellCheck": { + "AuditOnly": False, # Don't fail the build if there are errors. Just log them + "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files + "ExtendWords": [], # words to extend to the dictionary for this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + } + """ + + # + # A package can remove any of these using IgnoreStandardPaths + # + STANDARD_PLUGIN_DEFINED_PATHS = ["*.c", "*.h", + "*.nasm", "*.asm", "*.masm", "*.s", + "*.asl", + "*.dsc", "*.dec", "*.fdf", "*.inf", + "*.md", "*.txt" + ] + + def GetTestName(self, packagename: str, environment: VarDict) -> tuple: + """ Provide the testcase name and classname for use in reporting + + Args: + packagename: string containing name of package to build + environment: The VarDict for the test to run in + Returns: + a tuple containing the testcase name and the classname + (testcasename, classname) + testclassname: a descriptive string for the testcase can include whitespace + classname: should be patterned .. + """ + return ("Spell check files in " + packagename, packagename + ".SpellCheck") + + ## + # External function of plugin. This function is used to perform the task of the CiBuild Plugin + # + # - package is the edk2 path to package. This means workspace/packagepath relative. + # - edk2path object configured with workspace and packages path + # - PkgConfig Object (dict) for the pkg + # - EnvConfig Object + # - Plugin Manager Instance + # - Plugin Helper Obj Instance + # - Junit Logger + # - output_stream the StringIO output stream from this plugin via logging + + def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None): + Errors = [] + + abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath( + packagename) + + if abs_pkg_path is None: + tc.SetSkipped() + tc.LogStdError("No package {0}".format(packagename)) + return -1 + + # check for node + return_buffer = StringIO() + ret = RunCmd("node", "--version", outstream=return_buffer) + if (ret != 0): + tc.SetSkipped() + tc.LogStdError("NodeJs not installed. Test can't run") + logging.warning("NodeJs not installed. Test can't run") + return -1 + node_version = return_buffer.getvalue().strip() # format vXX.XX.XX + tc.LogStdOut(f"Node version: {node_version}") + version_aggregator.GetVersionAggregator().ReportVersion( + "NodeJs", node_version, version_aggregator.VersionTypes.INFO) + + # Check for cspell + return_buffer = StringIO() + ret = RunCmd("cspell", "--version", outstream=return_buffer) + if (ret != 0): + tc.SetSkipped() + tc.LogStdError("cspell not installed. Test can't run") + logging.warning("cspell not installed. Test can't run") + return -1 + cspell_version = return_buffer.getvalue().strip() # format XX.XX.XX + tc.LogStdOut(f"CSpell version: {cspell_version}") + version_aggregator.GetVersionAggregator().ReportVersion( + "CSpell", cspell_version, version_aggregator.VersionTypes.INFO) + + package_relative_paths_to_spell_check = SpellCheck.STANDARD_PLUGIN_DEFINED_PATHS + + # + # Allow the ci.yaml to remove any of the above standard paths + # + if("IgnoreStandardPaths" in pkgconfig): + for a in pkgconfig["IgnoreStandardPaths"]: + if(a in package_relative_paths_to_spell_check): + tc.LogStdOut( + f"ignoring standard path due to ci.yaml ignore: {a}") + package_relative_paths_to_spell_check.remove(a) + else: + tc.LogStdOut(f"Invalid IgnoreStandardPaths value: {a}") + + # + # check for any additional include paths defined by package config + # + if("AdditionalIncludePaths" in pkgconfig): + package_relative_paths_to_spell_check.extend( + pkgconfig["AdditionalIncludePaths"]) + + # + # Make the path string for cspell to check + # + relpath = os.path.relpath(abs_pkg_path) + cpsell_paths = " ".join( + [f"{relpath}/**/{x}" for x in package_relative_paths_to_spell_check]) + + # Make the config file + config_file_path = os.path.join( + Edk2pathObj.WorkspacePath, "Build", packagename, "cspell_actual_config.json") + mydir = os.path.dirname(os.path.abspath(__file__)) + # load as yaml so it can have comments + base = os.path.join(mydir, "cspell.base.yaml") + with open(base, "r") as i: + config = yaml.safe_load(i) + + if("ExtendWords" in pkgconfig): + config["words"].extend(pkgconfig["ExtendWords"]) + with open(config_file_path, "w") as o: + json.dump(config, o) # output as json so compat with cspell + + All_Ignores = [] + # Parse the config for other ignores + if "IgnoreFiles" in pkgconfig: + All_Ignores.extend(pkgconfig["IgnoreFiles"]) + + # spell check all the files + ignore = parse_gitignore_lines(All_Ignores, os.path.join( + abs_pkg_path, "nofile.txt"), abs_pkg_path) + + # result is a list of strings like this + # C:\src\sp-edk2\edk2\FmpDevicePkg\FmpDevicePkg.dec:53:9 - Unknown word (Capule) + EasyFix = [] + results = self._check_spelling(cpsell_paths, config_file_path) + for r in results: + path, _, word = r.partition(" - Unknown word ") + if len(word) == 0: + # didn't find pattern + continue + + pathinfo = path.rsplit(":", 2) # remove the line no info + if(ignore(pathinfo[0])): # check against ignore list + tc.LogStdOut(f"ignoring error due to ci.yaml ignore: {r}") + continue + + # real error + EasyFix.append(word.strip().strip("()")) + Errors.append(r) + + # Log all errors tc StdError + for l in Errors: + tc.LogStdError(l.strip()) + + # Helper - Log the syntax needed to add these words to dictionary + if len(EasyFix) > 0: + EasyFix = sorted(set(a.lower() for a in EasyFix)) + tc.LogStdOut("\n Easy fix:") + OneString = "If these are not errors add this to your ci.yaml file.\n" + OneString += '"SpellCheck": {\n "ExtendWords": [' + for a in EasyFix: + tc.LogStdOut(f'\n"{a}",') + OneString += f'\n "{a}",' + logging.info(OneString.rstrip(",") + '\n ]\n}') + + # add result to test case + overall_status = len(Errors) + if overall_status != 0: + if "AuditOnly" in pkgconfig and pkgconfig["AuditOnly"]: + # set as skipped if AuditOnly + tc.SetSkipped() + return -1 + else: + tc.SetFailed("SpellCheck {0} Failed. Errors {1}".format( + packagename, overall_status), "CHECK_FAILED") + else: + tc.SetSuccess() + return overall_status + + def _check_spelling(self, abs_file_to_check: str, abs_config_file_to_use: str) -> []: + output = StringIO() + ret = RunCmd( + "cspell", f"--config {abs_config_file_to_use} {abs_file_to_check}", outstream=output) + if ret == 0: + return [] + else: + return output.getvalue().strip().splitlines() diff --git a/.pytool/Plugin/SpellCheck/SpellCheck_plug_in.yaml b/.pytool/Plugin/SpellCheck/SpellCheck_plug_in.yaml new file mode 100644 index 00000000000..d438199f609 --- /dev/null +++ b/.pytool/Plugin/SpellCheck/SpellCheck_plug_in.yaml @@ -0,0 +1,11 @@ +## @file +# CiBuildPlugin used to check spelling +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "cibuild", + "name": "Spell Check Test", + "module": "SpellCheck" +} diff --git a/.pytool/Plugin/SpellCheck/cspell.base.yaml b/.pytool/Plugin/SpellCheck/cspell.base.yaml new file mode 100644 index 00000000000..53000fc3814 --- /dev/null +++ b/.pytool/Plugin/SpellCheck/cspell.base.yaml @@ -0,0 +1,165 @@ +## @file +# CSpell configuration +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "version": "0.1", + "language": "en", + "dictionaries": [ + "companies ", + "softwareTerms", + "python", + "cpp" + ], + "ignorePaths": [ + "*.pdb", + "**/*_extdep/**", + "*.pdf", + "*.exe", + "*.jpg" + ], + "minWordLength": 5, + "allowCompoundWords": false, + "ignoreWords": [ + "muchange" + ], + "words": [ + "MTRRs", + "Microarchitecture", + "Goldmont", + "cpuid", + "mwait", + "cstate", + "smram", + "scrtm", + "smbus", + "selftest", + "socket", + "MMRAM", + "qword", + "ENDBR", + "SMBASE", + "FXSAVE", + "FXRSTOR", + "RDRAND", + "IOAPIC", + "ATAPI", + "movsb", + "iretw", + "XENSTORE", + "cdrom", + "oprom", + "oproms", + "varstore", + "EKU", + "ascii", + "nmake", + "NVDIMM", + "nasmb", + "Mtftp", + "Hypercall", + "hypercalls", + "IOMMU", + "QEMU", + "qemus", + "OVMF", + "tiano", + "tianocore", + "edkii", + "coreboot", + "uefipayload", + "bootloader", + "bootloaders", + "mdepkg", + "skuid", + "dxefv", + "toolchain", + "libraryclass", + "preboot", + "pythonpath", + "cygpath", + "nuget", + "basetools", + "prepi", + "OPTEE", + "stringid", + "peims", + "memmap", + "guids", + "uuids", + "smbios", + "certdb", + "certdbv", + "EfiSigList", + "depex", + "IHANDLE", + "Virtio", + "Mbytes", + "Citrix", + "initrd", + "semihost", + "Semihosting", + "Trustzone", + "Fastboot", + "framebuffer", + "genfw", + "TTYTERM", + "miniport", + "LFENCE", + "PCANSI", + "submodule", + "submodules", + "brotli", + "PCCTS", + "softfloat", + "whitepaper", + "ACPICA", + "plugfest", + "bringup", + "formset", #VFR + "ideqvallist", + "numberof", + "oneof", + "endformset", + "endnumeric", + "endoneof", + "disableif", + "guidid", + "classguid", + "efivarstore", + "formsetguid", + "formid", + "suppressif", + "grayoutif", + "ideqval", + "endform", + "endcheckbox", + "questionid", + "questionref", + "enddate", + "endstring", + "guidop", + "endguidop", + "langdef", + "dynamicex", + "tokenspace", + "tokenguid", + "pcd's", #seems like cspell bug + "peim's", + "autogen", + "Disasm", + "Torito", + "SRIOV", + "MRIOV", + "UARTs", + "Consplitter", # common module in UEFI + "FIFOs", + "ACPINVS", + "Endof", # due to of not being uppercase + "bootability", + "Sdhci", + "inmodule", + ] +} diff --git a/.pytool/Readme.md b/.pytool/Readme.md new file mode 100644 index 00000000000..135d283fe22 --- /dev/null +++ b/.pytool/Readme.md @@ -0,0 +1,223 @@ +# Edk2 Continuous Integration + +## Basic Status + +| Package | Windows VS2019 (IA32/X64)| Ubuntu GCC (IA32/X64/ARM/AARCH64) | Known Issues | +| :---- | :----- | :---- | :--- | +| ArmPkg | +| ArmPlatformPkg | +| ArmVirtPkg | +| CryptoPkg | :heavy_check_mark: | :heavy_check_mark: | Spell checking in audit mode +| DynamicTablesPkg | +| EmbeddedPkg | +| EmulatorPkg | +| FatPkg | :heavy_check_mark: | :heavy_check_mark: | +| FmpDevicePkg | :heavy_check_mark: | :heavy_check_mark: | +| IntelFsp2Pkg | +| IntelFsp2WrapperPkg | +| MdeModulePkg | :heavy_check_mark: | :heavy_check_mark: | DxeIpl dependency on ArmPkg, Depends on StandaloneMmPkg, Spell checking in audit mode +| MdePkg | :heavy_check_mark: | :heavy_check_mark: | Spell checking in audit mode +| NetworkPkg | :heavy_check_mark: | :heavy_check_mark: | Spell checking in audit mode +| OvmfPkg | +| PcAtChipsetPkg | :heavy_check_mark: | :heavy_check_mark: | +| SecurityPkg | :heavy_check_mark: | :heavy_check_mark: | Spell checking in audit mode +| ShellPkg | :heavy_check_mark: | :heavy_check_mark: | Spell checking in audit mode, 3 modules are not being built by DSC +| SignedCapsulePkg | +| SourceLevelDebugPkg | +| StandaloneMmPkg | +| UefiCpuPkg | :heavy_check_mark: | :heavy_check_mark: | Spell checking in audit mode, 2 binary modules not being built by DSC +| UefiPayloadPkg | + +For more detailed status look at the test results of the latest CI run on the +repo readme. + +## Background + +This Continuous integration and testing infrastructure leverages the TianoCore EDKII Tools PIP modules: +[library](https://pypi.org/project/edk2-pytool-library/) and +[extensions](https://pypi.org/project/edk2-pytool-extensions/) (with repos +located [here](https://github.com/tianocore/edk2-pytool-library) and +[here](https://github.com/tianocore/edk2-pytool-extensions)). + +The primary execution flows can be found in the +`.azurepipelines/Windows-VS2019.yml` and `.azurepipelines/Ubuntu-GCC5.yml` +files. These YAML files are consumed by the Azure Dev Ops Build Pipeline and +dictate what server resources should be used, how they should be configured, and +what processes should be run on them. An overview of this schema can be found +[here](https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema). + +Inspection of these files reveals the EDKII Tools commands that make up the +primary processes for the CI build: 'stuart_setup', 'stuart_update', and +'stuart_ci_build'. These commands come from the EDKII Tools PIP modules and are +configured as described below. More documentation on the tools can be +found [here](https://github.com/tianocore/edk2-pytool-extensions/blob/master/docs/using.md) +and [here](https://github.com/tianocore/edk2-pytool-extensions/blob/master/docs/features/feature_invocables.md). + +## Configuration + +Configuration of the CI process consists of (in order of precedence): + +* command-line arguments passed in via the Pipeline YAML +* a per-package configuration file (e.g. `.ci.yaml`) that is + detected by the CI system in EDKII Tools. +* a global configuration Python module (e.g. `CISetting.py`) passed in via the + command-line + +The global configuration file is described in +[this readme](https://github.com/tianocore/edk2-pytool-extensions/blob/master/docs/usability/using_settings_manager.md) +from the EDKII Tools documentation. This configuration is written as a Python +module so that decisions can be made dynamically based on command line +parameters and codebase state. + +The per-package configuration file can override most settings in the global +configuration file, but is not dynamic. This file can be used to skip or +customize tests that may be incompatible with a specific package. Each test generally requires +per package configuration which comes from this file. + +## Running CI locally + +The EDKII Tools environment (and by extension the ci) is designed to support +easily and consistantly running locally and in a cloud ci environment. To do +that a few steps should be followed. Details of EDKII Tools can be found in the +[docs folder here](https://github.com/tianocore/edk2-pytool-extensions/tree/master/docs) + +### Prerequisets + +1. A supported toolchain (others might work but this is what is tested and validated) + * Windows 10: + * VS 2017 or VS 2019 + * Windows SDK (for rc) + * Windows WDK (for capsules) + * Ubuntu 16.04 + * GCC5 + * Easy to add more but this is the current state +2. Python 3.7.x or newer on path +3. git on path +4. Recommended to setup and activate a python virtual environment +5. Install the requirements `pip install --upgrade pip-requirements.txt` + +### Running CI + +1. clone your edk2 repo +2. Activate your python virtual environment in cmd window +3. Get code dependencies (done only when submodules change) + * `stuart_setup -c .pytool/CISettings.py TOOL_CHAIN_TAG=` +4. Update other dependencies (done more often) + * `stuart_update -c .pytool/CISettings.py TOOL_CHAIN_TAG=` +5. Run CI build (--help will give you options) + * `stuart_ci_build -c .pytool/CISettings.py TOOL_CHAIN_TAG=` + * -p : To build only certain packages use a CSV list + * -a : To run only certain architectures use a CSV list + * -t : To run only tests related to certain targets use a + CSV list + * By default all tests are opted in. Then given a package.ci.yaml file those + tests can be configured for a package. Finally setting the check to the + value `skip` will skip that plugin. Examples: + * `CompilerPlugin=skip` skip the build test + * `GuidCheck=skip` skip the Guid check + * `SpellCheck=skip` skip the spell checker + * etc +6. Detailed reports and logs per package are captured in the `Build` directory + +## Current PyTool Test Capabilities + +All CI tests are instances of EDKII Tools plugins. Documentation on the plugin +system can be found [here](https://github.com/tianocore/edk2-pytool-extensions/blob/master/docs/usability/using_plugin_manager.md) +and [here](https://github.com/tianocore/edk2-pytool-extensions/blob/master/docs/features/feature_plugin_manager.md). +Upon invocation, each plugin will be passed the path to the current package +under test and a dictionary containing its targeted configuration, as assembled +from the command line, per-package configuration, and global configuration. + +Note: CI plugins are considered unique from build plugins and helper plugins, +even though some CI plugins may execute steps of a build. + +In the example, these plugins live alongside the code under test (in the +`.pytool/Plugin` directory), but may be moved to the 'edk2-test' repo if that +location makes more sense for the community. + +### Module Inclusion Test - DscCompleteCheck + +This test scans all available modules (via INF files) and compares them to the +package-level DSC file for the package each module is contained within. The test +considers it an error if any module does not appear in the `Components` section +of at least one package-level DSC (indicating that it would not be built if the +package were built). + +### Code Compilation Test - CompilerPlugin + +Once the Module Inclusion Test has verified that all modules would be built if +all package-level DSCs were built, the Code Compilation Test simply runs through +and builds every package-level DSC on every toolchain and for every architecture +that is supported. Any module that fails to build is considered an error. + +### GUID Uniqueness Test - GuidCheck + +This test works on the collection of all packages rather than an individual +package. It looks at all FILE_GUIDs and GUIDs declared in DEC files and ensures +that they are unique for the codebase. This prevents, for example, accidental +duplication of GUIDs when using an existing INF as a template for a new module. + +### Cross-Package Dependency Test - DependencyCheck + +This test compares the list of all packages used in INFs files for a given +package against a list of "allowed dependencies" in plugin configuration for +that package. Any module that depends on a disallowed package will cause a test +failure. + +### Library Declaration Test - LibraryClassCheck + +This test scans at all library header files found in the `Library` folders in +all of the package's declared include directories and ensures that all files +have a matching LibraryClass declaration in the DEC file for the package. Any +missing declarations will cause a failure. + +### Invalid Character Test - CharEncodingCheck + +This test scans all files in a package to make sure that there are no invalid +Unicode characters that may cause build errors in some character +sets/localizations. + +### Spell Checking - cspell + +This test runs a spell checker on all files within the package. This is done +using the NodeJs cspell tool. For details check `.pytool/Plugin/SpellCheck`. +For this plugin to run during ci you must install nodejs and cspell and have +both available to the command line when running your CI. + +Install + +* Install nodejs from https://nodejs.org/en/ +* Install cspell + 1. Open cmd prompt with access to node and npm + 2. Run `npm install -g cspell` + + More cspell info: https://github.com/streetsidesoftware/cspell + +## PyTool Scopes + +Scopes are how the PyTool ext_dep, path_env, and plugins are activated. Meaning +that if an invocable process has a scope active then those ext_dep and path_env +will be active. To allow easy integration of PyTools capabilities there are a +few standard scopes. + +| Scope | Invocable | Description | +| :---- | :----- | :---- | +| global | edk2_invocable++ - should be base_abstract_invocable | Running an invocables | +| global-win | edk2_invocable++ | Running on Microsoft Windows | +| global-nix | edk2_invocable++ | Running on Linux based OS | +| edk2-build | | This indicates that an invocable is building EDK2 based UEFI code | +| cibuild | set in .pytool/CISettings.py | Suggested target for edk2 continuous integration builds. Tools used for CiBuilds can use this scope. Example: asl compiler | + +## Future investments + +* PatchCheck tests as plugins +* MacOS/xcode support +* Clang/LLVM support +* Visual Studio AARCH64 and ARM support +* BaseTools C tools CI/PR and binary release process +* BaseTools Python tools CI/PR process +* Host based unit testing +* Extensible private/closed source platform reporting +* Platform builds, validation +* UEFI SCTs +* Other automation diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec index 39ff339c956..eaf1072d9ef 100644 --- a/ArmPkg/ArmPkg.dec +++ b/ArmPkg/ArmPkg.dec @@ -78,10 +78,6 @@ # Define if the GICv3 controller should use the GICv2 legacy gArmTokenSpaceGuid.PcdArmGicV3WithV2Legacy|FALSE|BOOLEAN|0x00000042 - # Whether to implement warm reboot for capsule update using a jump back to the - # PEI entry point with caches and interrupts disabled. - gArmTokenSpaceGuid.PcdArmReenterPeiForCapsuleWarmReboot|FALSE|BOOLEAN|0x0000001F - [PcdsFeatureFlag.ARM] # Whether to map normal memory as non-shareable. FALSE is the safe choice, but # TRUE may be appropriate to fix performance problems if you don't care about diff --git a/ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.c b/ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.c index d06dcc4d208..5f52afa0fed 100644 --- a/ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.c +++ b/ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.c @@ -259,6 +259,43 @@ GetMmCompatibility () return Status; } +STATIC EFI_GUID* CONST mGuidedEventGuid[] = { + &gEfiEndOfDxeEventGroupGuid, + &gEfiEventExitBootServicesGuid, + &gEfiEventReadyToBootGuid, +}; + +STATIC EFI_EVENT mGuidedEvent[ARRAY_SIZE (mGuidedEventGuid)]; + +/** + Event notification that is fired when GUIDed Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +STATIC +VOID +EFIAPI +MmGuidedEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_MM_COMMUNICATE_HEADER Header; + UINTN Size; + + // + // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure + // + CopyGuid (&Header.HeaderGuid, Context); + Header.MessageLength = 1; + Header.Data[0] = 0; + + Size = sizeof (Header); + MmCommunicationCommunicate (&mMmCommunication, &Header, &Size); +} + /** The Entry Point for MM Communication @@ -281,6 +318,7 @@ MmCommunicationInitialize ( ) { EFI_STATUS Status; + UINTN Index; // Check if we can make the MM call Status = GetMmCompatibility (); @@ -345,8 +383,13 @@ MmCommunicationInitialize ( NULL, &mSetVirtualAddressMapEvent ); - if (Status == EFI_SUCCESS) { - return Status; + ASSERT_EFI_ERROR (Status); + + for (Index = 0; Index < ARRAY_SIZE (mGuidedEventGuid); Index++) { + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + MmGuidedEventNotify, mGuidedEventGuid[Index], + mGuidedEventGuid[Index], &mGuidedEvent[Index]); + ASSERT_EFI_ERROR (Status); } gBS->UninstallProtocolInterface ( diff --git a/ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf b/ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf index 450fc9bb541..505228704ea 100644 --- a/ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf +++ b/ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf @@ -42,6 +42,11 @@ [Protocols] gEfiMmCommunicationProtocolGuid ## PRODUCES +[Guids] + gEfiEndOfDxeEventGroupGuid + gEfiEventExitBootServicesGuid + gEfiEventReadyToBootGuid + [Pcd.common] gArmTokenSpaceGuid.PcdMmBufferBase gArmTokenSpaceGuid.PcdMmBufferSize diff --git a/ArmPkg/Library/ArmSmcPsciResetSystemLib/AArch64/Reset.S b/ArmPkg/Library/ArmSmcPsciResetSystemLib/AArch64/Reset.S deleted file mode 100644 index d0d908b7d70..00000000000 --- a/ArmPkg/Library/ArmSmcPsciResetSystemLib/AArch64/Reset.S +++ /dev/null @@ -1,24 +0,0 @@ -/** @file - ResetSystemLib implementation using PSCI calls - - Copyright (c) 2018, Linaro Ltd. All rights reserved.
- - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include - -ASM_FUNC(DisableMmuAndReenterPei) - stp x29, x30, [sp, #-16]! - mov x29, sp - - bl ArmDisableMmu - - // no memory accesses after MMU and caches have been disabled - - MOV64 (x0, FixedPcdGet64 (PcdFvBaseAddress)) - blr x0 - - // never returns - nop diff --git a/ArmPkg/Library/ArmSmcPsciResetSystemLib/AArch64/Reset.asm b/ArmPkg/Library/ArmSmcPsciResetSystemLib/AArch64/Reset.asm deleted file mode 100644 index 752df072511..00000000000 --- a/ArmPkg/Library/ArmSmcPsciResetSystemLib/AArch64/Reset.asm +++ /dev/null @@ -1,29 +0,0 @@ -;/** @file -; ResetSystemLib implementation using PSCI calls -; -; Copyright (c) 2018, Linaro Ltd. All rights reserved.
-; -; SPDX-License-Identifier: BSD-2-Clause-Patent -; -;**/ - - AREA Reset, CODE, READONLY - - EXPORT DisableMmuAndReenterPei - IMPORT ArmDisableMmu - -DisableMmuAndReenterPei - stp x29, x30, [sp, #-16]! - mov x29, sp - - bl ArmDisableMmu - - ; no memory accesses after MMU and caches have been disabled - - movl x0, FixedPcdGet64 (PcdFvBaseAddress) - blr x0 - - ; never returns - nop - - END diff --git a/ArmPkg/Library/ArmSmcPsciResetSystemLib/Arm/Reset.S b/ArmPkg/Library/ArmSmcPsciResetSystemLib/Arm/Reset.S deleted file mode 100644 index c0c5bcf1972..00000000000 --- a/ArmPkg/Library/ArmSmcPsciResetSystemLib/Arm/Reset.S +++ /dev/null @@ -1,23 +0,0 @@ -/** @file - ResetSystemLib implementation using PSCI calls - - Copyright (c) 2018, Linaro Ltd. All rights reserved.
- - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include - -ASM_FUNC(DisableMmuAndReenterPei) - push {lr} - - bl ArmDisableMmu - - // no memory accesses after MMU and caches have been disabled - - MOV32 (r0, FixedPcdGet64 (PcdFvBaseAddress)) - blx r0 - - // never returns - nop diff --git a/ArmPkg/Library/ArmSmcPsciResetSystemLib/Arm/Reset.asm b/ArmPkg/Library/ArmSmcPsciResetSystemLib/Arm/Reset.asm deleted file mode 100644 index ab7519a5a92..00000000000 --- a/ArmPkg/Library/ArmSmcPsciResetSystemLib/Arm/Reset.asm +++ /dev/null @@ -1,28 +0,0 @@ -;/** @file -; ResetSystemLib implementation using PSCI calls -; -; Copyright (c) 2018, Linaro Ltd. All rights reserved.
-; -; SPDX-License-Identifier: BSD-2-Clause-Patent -; -;**/ - - INCLUDE AsmMacroExport.inc - PRESERVE8 - - IMPORT ArmDisableMmu - -RVCT_ASM_EXPORT DisableMmuAndReenterPei - push {lr} - - bl ArmDisableMmu - - ; no memory accesses after MMU and caches have been disabled - - mov32 r0, FixedPcdGet64 (PcdFvBaseAddress) - blx r0 - - ; never returns - nop - - END diff --git a/ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.c b/ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.c index b2dde9bfc13..8b5ff5c27e4 100644 --- a/ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.c +++ b/ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.c @@ -10,13 +10,10 @@ #include -#include #include #include #include #include -#include -#include #include @@ -76,79 +73,6 @@ ResetShutdown ( ArmCallSmc (&ArmSmcArgs); } -VOID DisableMmuAndReenterPei (VOID); - -/** - This function causes the system to enter S3 and then wake up immediately. - - If this function returns, it means that the system does not support S3 feature. -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ) -{ - EFI_PHYSICAL_ADDRESS Alloc; - EFI_MEMORY_DESCRIPTOR *MemMap; - UINTN MemMapSize; - UINTN MapKey, DescriptorSize; - UINT32 DescriptorVersion; - EFI_STATUS Status; - - if (FeaturePcdGet (PcdArmReenterPeiForCapsuleWarmReboot) && - !EfiAtRuntime ()) { - // - // At boot time, we are the only core running, so we can implement the - // immediate wake (which is used by capsule update) by disabling the MMU - // and interrupts, and jumping to the PEI entry point. - // - - // - // Obtain the size of the memory map - // - MemMapSize = 0; - MemMap = NULL; - Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, - &DescriptorVersion); - ASSERT (Status == EFI_BUFFER_TOO_SMALL); - - // - // Add some slack to the allocation to cater for changes in the memory - // map if ExitBootServices () fails the first time around. - // - MemMapSize += SIZE_4KB; - Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, - EFI_SIZE_TO_PAGES (MemMapSize), &Alloc); - ASSERT_EFI_ERROR (Status); - - MemMap = (EFI_MEMORY_DESCRIPTOR *)(UINTN)Alloc; - - Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, - &DescriptorVersion); - ASSERT_EFI_ERROR (Status); - - Status = gBS->ExitBootServices (gImageHandle, MapKey); - if (EFI_ERROR (Status)) { - // - // ExitBootServices () may fail the first time around if an event fired - // right after the call to GetMemoryMap() which allocated or freed memory. - // Since that first call to ExitBootServices () will disarm the timer, - // this is guaranteed not to happen again, so one additional attempt - // should suffice. - // - Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, - &DescriptorVersion); - ASSERT_EFI_ERROR (Status); - - Status = gBS->ExitBootServices (gImageHandle, MapKey); - ASSERT_EFI_ERROR (Status); - } - - DisableMmuAndReenterPei (); - } -} - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.inf b/ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.inf index fa19bf64913..c17b28cfac7 100644 --- a/ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.inf +++ b/ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.inf @@ -15,14 +15,6 @@ VERSION_STRING = 1.0 LIBRARY_CLASS = ResetSystemLib -[Sources.AARCH64] - AArch64/Reset.S | GCC - AArch64/Reset.asm | MSFT - -[Sources.ARM] - Arm/Reset.S | GCC - Arm/Reset.asm | RVCT - [Sources] ArmSmcPsciResetSystemLib.c @@ -32,15 +24,6 @@ MdePkg/MdePkg.dec [LibraryClasses] - ArmMmuLib ArmSmcLib BaseLib DebugLib - UefiBootServicesTableLib - UefiRuntimeLib - -[FeaturePcd] - gArmTokenSpaceGuid.PcdArmReenterPeiForCapsuleWarmReboot - -[FixedPcd] - gArmTokenSpaceGuid.PcdFvBaseAddress diff --git a/ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c b/ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c index 39b892a4b29..e6e788e0f10 100644 --- a/ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c +++ b/ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c @@ -2,7 +2,7 @@ Implementation for PlatformBootManagerLib library class interfaces. Copyright (C) 2015-2016, Red Hat, Inc. - Copyright (c) 2014, ARM Ltd. All rights reserved.
+ Copyright (c) 2014 - 2019, ARM Ltd. All rights reserved.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
Copyright (c) 2016, Linaro Ltd. All rights reserved.
@@ -549,6 +549,11 @@ PlatformBootManagerBeforeConsole ( // EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid); + // + // Dispatch deferred images after EndOfDxe event. + // + EfiBootManagerDispatchDeferredImages (); + // // Locate the PCI root bridges and make the PCI bus driver connect each, // non-recursively. This will produce a number of child handles with PciIo on diff --git a/ArmPlatformPkg/PrePeiCore/PrePeiCore.c b/ArmPlatformPkg/PrePeiCore/PrePeiCore.c index 4911f67577a..4f691d62cf3 100644 --- a/ArmPlatformPkg/PrePeiCore/PrePeiCore.c +++ b/ArmPlatformPkg/PrePeiCore/PrePeiCore.c @@ -77,6 +77,11 @@ CEntryPoint ( ASSERT (((UINTN)PeiVectorTable & ARM_VECTOR_TABLE_ALIGNMENT) == 0); ArmWriteVBar ((UINTN)PeiVectorTable); + // Enable Floating Point + if (FixedPcdGet32 (PcdVFPEnabled)) { + ArmEnableVFP (); + } + //Note: The MMU will be enabled by MemoryPeim. Only the primary core will have the MMU on. // If not primary Jump to Secondary Main diff --git a/ArmPlatformPkg/PrePeiCore/PrePeiCoreMPCore.inf b/ArmPlatformPkg/PrePeiCore/PrePeiCoreMPCore.inf index f2ac45d171b..104c7da5331 100644 --- a/ArmPlatformPkg/PrePeiCore/PrePeiCoreMPCore.inf +++ b/ArmPlatformPkg/PrePeiCore/PrePeiCoreMPCore.inf @@ -62,6 +62,7 @@ [FixedPcd] gArmTokenSpaceGuid.PcdFvBaseAddress gArmTokenSpaceGuid.PcdFvSize + gArmTokenSpaceGuid.PcdVFPEnabled gArmPlatformTokenSpaceGuid.PcdCPUCoresStackBase gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize diff --git a/ArmPlatformPkg/PrePeiCore/PrePeiCoreUniCore.inf b/ArmPlatformPkg/PrePeiCore/PrePeiCoreUniCore.inf index 84c319c3679..ceb173d34f5 100644 --- a/ArmPlatformPkg/PrePeiCore/PrePeiCoreUniCore.inf +++ b/ArmPlatformPkg/PrePeiCore/PrePeiCoreUniCore.inf @@ -60,6 +60,7 @@ [FixedPcd] gArmTokenSpaceGuid.PcdFvBaseAddress gArmTokenSpaceGuid.PcdFvSize + gArmTokenSpaceGuid.PcdVFPEnabled gArmPlatformTokenSpaceGuid.PcdCPUCoresStackBase gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize diff --git a/ArmVirtPkg/Library/ArmVirtPsciResetSystemLib/ArmVirtPsciResetSystemLib.c b/ArmVirtPkg/Library/ArmVirtPsciResetSystemLib/ArmVirtPsciResetSystemLib.c index fdf49e1d9c7..9e5b70e2c54 100644 --- a/ArmVirtPkg/Library/ArmVirtPsciResetSystemLib/ArmVirtPsciResetSystemLib.c +++ b/ArmVirtPkg/Library/ArmVirtPsciResetSystemLib/ArmVirtPsciResetSystemLib.c @@ -145,20 +145,6 @@ ResetShutdown ( } } -/** - This function causes the system to enter S3 and then wake up immediately. - - If this function returns, it means that the system does not support S3 feature. -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ) -{ - // not implemented -} - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/BaseTools/Bin/gcc_aarch64_linux_ext_dep.yaml b/BaseTools/Bin/gcc_aarch64_linux_ext_dep.yaml new file mode 100644 index 00000000000..e81223fd9ad --- /dev/null +++ b/BaseTools/Bin/gcc_aarch64_linux_ext_dep.yaml @@ -0,0 +1,21 @@ +## @file +# Download GCC AARCH64 compiler from Linaro's release site +# Set shell variable GCC5_AARCH64_INSTALL to this folder +# +# This is only downloaded when a build activates scope gcc_aarch64_linux +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "gcc_aarch64_linux", + "type": "web", + "name": "gcc_aarch64_linux", + "source": "http://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/aarch64-linux-gnu/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz", + "version": "7.4.1", + "sha256": "27f1dc2c491ed61ae8f0d4b0c11de59cd2f7dd9c94761ee7153006fcac1bf9ab", + "compression_type": "tar", + "internal_path": "/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu/", + "flags": ["set_shell_var", ], + "var_name": "GCC5_AARCH64_INSTALL" +} diff --git a/BaseTools/Bin/gcc_arm_linux_ext_dep.yaml b/BaseTools/Bin/gcc_arm_linux_ext_dep.yaml new file mode 100644 index 00000000000..09481ceae05 --- /dev/null +++ b/BaseTools/Bin/gcc_arm_linux_ext_dep.yaml @@ -0,0 +1,21 @@ +## @file +# Download GCC ARM compiler from Linaro's release site +# Set shell variable GCC5_ARM_INSTALL to this folder +# +# This is only downloaded when a build activates scope gcc_arm_linux +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "gcc_arm_linux", + "type": "web", + "name": "gcc_arm_linux", + "source": "https://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/arm-linux-gnueabihf/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz", + "version": "7.4.1", + "sha256": "3C951CF1941D0FA06D64CC0D5E88612B209D8123B273FA26C16D70BD7BC6B163", + "compression_type": "tar", + "internal_path": "/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/", + "flags": ["set_shell_var", ], + "var_name": "GCC5_ARM_INSTALL" +} diff --git a/BaseTools/Bin/iasl_ext_dep.yaml b/BaseTools/Bin/iasl_ext_dep.yaml new file mode 100644 index 00000000000..1d81e89cf3a --- /dev/null +++ b/BaseTools/Bin/iasl_ext_dep.yaml @@ -0,0 +1,21 @@ +## @file +# Download iasl executable tool from a nuget.org package +# - package contains different binaries based on host +# Add the folder with the tool to the path +# +# This is only downloaded for scope cibuild thus +# should have no impact on the asl compiler used by any +# given platform to build. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "id": "iasl-ci-1", + "scope": "cibuild", + "type": "nuget", + "name": "iasl", + "source": "https://api.nuget.org/v3/index.json", + "version": "20190215.0.0", + "flags": ["set_path", "host_specific"] +} diff --git a/BaseTools/Bin/nasm_ext_dep.yaml b/BaseTools/Bin/nasm_ext_dep.yaml new file mode 100644 index 00000000000..60b1f71b56a --- /dev/null +++ b/BaseTools/Bin/nasm_ext_dep.yaml @@ -0,0 +1,18 @@ +## @file +# Download nasm x86 assembler executable tool from a nuget.org package +# - package contains different binaries based on host +# Put on the tool on the path +# +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "id": "nasm-1", + "scope": "edk2-build", + "type": "nuget", + "name": "mu_nasm", + "source": "https://api.nuget.org/v3/index.json", + "version": "2.14.02", + "flags": ["set_path", "host_specific"] +} diff --git a/BaseTools/BinWrappers/PosixLike/posix_path_env.yaml b/BaseTools/BinWrappers/PosixLike/posix_path_env.yaml new file mode 100644 index 00000000000..8b32e010bb1 --- /dev/null +++ b/BaseTools/BinWrappers/PosixLike/posix_path_env.yaml @@ -0,0 +1,10 @@ +## @file +# Set this folder on the path for all linux builds +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "global-nix", + "flags": ["set_path"] +} diff --git a/BaseTools/BinWrappers/WindowsLike/win_build_tools_path_env.yaml b/BaseTools/BinWrappers/WindowsLike/win_build_tools_path_env.yaml new file mode 100644 index 00000000000..83f5856e75c --- /dev/null +++ b/BaseTools/BinWrappers/WindowsLike/win_build_tools_path_env.yaml @@ -0,0 +1,10 @@ +## @file +# Add this folder to the path on Windows +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "global-win", + "flags": ["set_path"] +} diff --git a/BaseTools/Conf/build_rule.template b/BaseTools/Conf/build_rule.template index 3a58ac8015e..51748bc0655 100755 --- a/BaseTools/Conf/build_rule.template +++ b/BaseTools/Conf/build_rule.template @@ -81,6 +81,8 @@ # will be generated only when this macro is used in command line. # This is intended to get over the long command line limitation. # ) +# $(DEPS_FLAGS) This is a tool flag to have c compiler generate dependent header file list for a source file. +# To enable incremental build, this flag must apply to $(CC), $(VFRPP), $(PP), $(ASLCC) and $(ASLPP). # # $(CP) copy command # $(MV) move command @@ -123,14 +125,14 @@ $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj - "$(CC)" /Fo${dst} $(CC_FLAGS) $(INC) ${src} + "$(CC)" /Fo${dst} $(DEPS_FLAGS) $(CC_FLAGS) $(INC) ${src} # For RVCTCYGWIN CC_FLAGS must be first to work around pathing issues - "$(CC)" $(CC_FLAGS) -c -o ${dst} $(INC) ${src} + "$(CC)" $(DEPS_FLAGS) $(CC_FLAGS) -c -o ${dst} $(INC) ${src} - "$(CC)" $(CC_FLAGS) -o ${dst} $(INC) ${src} + "$(CC)" $(DEPS_FLAGS) $(CC_FLAGS) -o ${dst} $(INC) ${src} [C-Code-File.BASE.AARCH64,C-Code-File.SEC.AARCH64,C-Code-File.PEI_CORE.AARCH64,C-Code-File.PEIM.AARCH64,C-Code-File.BASE.ARM,C-Code-File.SEC.ARM,C-Code-File.PEI_CORE.ARM,C-Code-File.PEIM.ARM] @@ -167,15 +169,17 @@ $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --source-code --convert-hex --trim-long -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i - "$(ASM)" /Fo${dst} $(ASM_FLAGS) /I${s_path} $(INC) ${d_path}(+)${s_base}.iii + Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --source-code --convert-hex --trim-long -o ${d_path}(+)${s_base}.iiii ${d_path}(+)${s_base}.ii + "$(ASM)" /Fo${dst} $(ASM_FLAGS) /I${s_path} $(INC) ${d_path}(+)${s_base}.iiii - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --trim-long --source-code -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i + Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --trim-long --source-code -o ${d_path}(+)${s_base}.iiii ${d_path}(+)${s_base}.ii # For RVCTCYGWIN ASM_FLAGS must be first to work around pathing issues - "$(ASM)" $(ASM_FLAGS) -o ${dst} $(INC) ${d_path}(+)${s_base}.iii + "$(ASM)" $(ASM_FLAGS) -o ${dst} $(INC) ${d_path}(+)${s_base}.iiii [Assembly-Code-File.COMMON.ARM,Assembly-Code-File.COMMON.AARCH64] # Remove --convert-hex for ARM as it breaks MSFT assemblers @@ -192,20 +196,23 @@ $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --source-code --convert-hex --trim-long -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i - "$(ASM)" /Fo${dst} $(ASM_FLAGS) /I${s_path} $(INC) ${d_path}(+)${s_base}.iii + Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --source-code --convert-hex --trim-long -o ${d_path}(+)${s_base}.iiii ${d_path}(+)${s_base}.ii + "$(ASM)" /Fo${dst} $(ASM_FLAGS) /I${s_path} $(INC) ${d_path}(+)${s_base}.iiii - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --source-code --trim-long -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i - "$(ASM)" /Fo${dst} $(ASM_FLAGS) /I${s_path} $(INC) ${d_path}(+)${s_base}.iii + Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --source-code --trim-long -o ${d_path}(+)${s_base}.iiii ${d_path}(+)${s_base}.ii + "$(ASM)" /Fo${dst} $(ASM_FLAGS) /I${s_path} $(INC) ${d_path}(+)${s_base}.iiii - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --trim-long --source-code -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i + Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --trim-long --source-code -o ${d_path}(+)${s_base}.iiii ${d_path}(+)${s_base}.ii # For RVCTCYGWIN ASM_FLAGS must be first to work around pathing issues - "$(ASM)" $(ASM_FLAGS) -o ${dst} $(INC) ${d_path}(+)${s_base}.iii + "$(ASM)" $(ASM_FLAGS) -o ${dst} $(INC) ${d_path}(+)${s_base}.iiii [Nasm-Assembly-Code-File.COMMON.COMMON] @@ -218,8 +225,9 @@ $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --trim-long --source-code -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i + Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --trim-long --source-code -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.ii "$(NASM)" -I${s_path}(+) $(NASM_INC) $(NASM_FLAGS) -o $dst ${d_path}(+)${s_base}.iii [Device-Tree-Source-File] @@ -249,7 +257,7 @@ $(DEBUG_DIR)(+)${s_dir}(+)${s_base}.c - "$(VFRPP)" $(VFRPP_FLAGS) $(INC) ${src} > $(OUTPUT_DIR)(+)${s_base}.i + "$(VFRPP)" $(DEPS_FLAGS) $(VFRPP_FLAGS) $(INC) ${src} > $(OUTPUT_DIR)(+)${s_base}.i "$(VFR)" $(VFR_FLAGS) --string-db $(OUTPUT_DIR)(+)$(MODULE_NAME)StrDefs.hpk --output-directory ${d_path} $(OUTPUT_DIR)(+)${s_base}.i [Object-File] @@ -260,7 +268,7 @@ $(OUTPUT_DIR)(+)$(MODULE_NAME).lib - + "$(SLINK)" $(SLINK_FLAGS) /OUT:${dst} @$(OBJECT_FILES_LIST) @@ -291,7 +299,7 @@ "$(DLINK)" /OUT:${dst} $(DLINK_FLAGS) $(DLINK2_FLAGS) $(DLINK_SPATH) @$(STATIC_LIBRARY_FILES_LIST) "$(DLINK)" /OUT:${dst} $(DLINK_FLAGS) $(DLINK_SPATH) @$(STATIC_LIBRARY_FILES_LIST) - + "$(DLINK)" /OUT:${dst} $(DLINK_FLAGS) $(DLINK_SPATH) @$(STATIC_LIBRARY_FILES_LIST) $(DLINK2_FLAGS) @@ -334,7 +342,7 @@ $(DEBUG_DIR)(+)$(MODULE_NAME) - + "$(DLINK)" $(DLINK_FLAGS) $(DLINK_SPATH) @$(STATIC_LIBRARY_FILES_LIST) @@ -358,7 +366,7 @@ $(OUTPUT_DIR)(+)$(MODULE_NAME).efi - + "$(GENFW)" -e $(MODULE_TYPE) -o ${dst} ${src} $(GENFW_FLAGS) $(CP) ${dst} $(DEBUG_DIR) $(CP) ${dst} $(BIN_DIR)(+)$(MODULE_NAME_GUID).efi @@ -400,7 +408,7 @@ $(MAKE_FILE) - "$(PP)" $(APP_FLAGS) $(INC) ${src} > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i + "$(PP)" $(DEPS_FLAGS) $(APP_FLAGS) $(INC) ${src} > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i Trim --source-code -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i GenDepex -t $(MODULE_TYPE) -o ${dst} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii @@ -415,14 +423,14 @@ $(MAKE_FILE) - Trim --asl-file -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i -i $(INC_LIST) ${src} - "$(ASLPP)" $(ASLPP_FLAGS) $(INC) /I${s_path} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii + Trim --asl-file --asl-deps -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(ASLPP)" $(DEPS_FLAGS) $(ASLPP_FLAGS) $(INC) /I${s_path} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii Trim --source-code -l -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii "$(ASL)" $(ASL_FLAGS) $(ASL_OUTFLAGS)${dst} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii - Trim --asl-file -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i -i $(INC_LIST) ${src} - "$(ASLPP)" $(ASLPP_FLAGS) $(INC) -I${s_path} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii + Trim --asl-file --asl-deps -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(ASLPP)" $(DEPS_FLAGS) $(ASLPP_FLAGS) $(INC) -I${s_path} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii Trim --source-code -l -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii "$(ASL)" $(ASL_FLAGS) $(ASL_OUTFLAGS)${dst} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii @@ -437,12 +445,12 @@ $(MAKE_FILE) - "$(ASLCC)" /Fo$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASLCC_FLAGS) $(INC) ${src} + "$(ASLCC)" $(DEPS_FLAGS) /Fo$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src} "$(ASLDLINK)" /OUT:$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj "$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS) - "$(ASLCC)" -c -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) $(INC) ${src} + "$(ASLCC)" $(DEPS_FLAGS) -c -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src} "$(ASLDLINK)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj "$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS) @@ -457,22 +465,22 @@ $(MAKE_FILE) - "$(ASLCC)" /Fo$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASLCC_FLAGS) $(INC) ${src} + "$(ASLCC)" $(DEPS_FLAGS) /Fo$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src} "$(ASLDLINK)" /OUT:$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj "$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS) - "$(ASLCC)" -c -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) $(INC) ${src} + "$(ASLCC)" $(DEPS_FLAGS) -c -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src} "$(ASLDLINK)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) "$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS) - - "$(ASLCC)" -c -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) $(INC) ${src} + + "$(ASLCC)" $(DEPS_FLAGS) -c -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src} "$(ASLDLINK)" /OUT:$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj "$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS) - "$(ASLCC)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASLCC_FLAGS) $(INC) ${src} + "$(ASLCC)" $(DEPS_FLAGS) -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src} "$(ASLDLINK)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj "$(MTOC)" -subsystem $(MODULE_TYPE) $(MTOC_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.pecoff "$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.pecoff $(GENFW_FLAGS) @@ -489,21 +497,24 @@ $(OUTPUT_DIR)(+)${s_base}.com - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --source-code --convert-hex --trim-long -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i + Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --source-code --convert-hex --trim-long -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.ii cd $(OUTPUT_DIR)(+)${s_dir} "$(ASM16)" /nologo /c /omf $(INC) /Fo$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj ${d_path}(+)${s_base}.iii "$(ASMLINK)" $(ASMLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj,${dst},,,, - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --source-code -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i + Trim --asm-file -o {d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --source-code -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.ii "$(ASM)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASM_FLAGS) $(INC) ${d_path}(+)${s_base}.iii "$(DLINK)" -o ${dst} $(DLINK_FLAGS) --start-group $(DLINK_SPATH) $(LIBS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj --end-group - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --source-code -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i + Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --source-code -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.ii "$(ASM)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASM_FLAGS) $(INC) ${d_path}(+)${s_base}.iii "$(SLINK)" $(SLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.slib $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj otool -t $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.slib | hex2bin.py ${dst} @@ -520,9 +531,10 @@ $(OUTPUT_DIR)(+)${s_base}.bin - "$(PP)" $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.i - Trim --source-code --convert-hex -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.i - "$(NASM)" -I${s_path}(+) -l ${d_path}(+)${s_base}.lst $(NASMB_FLAGS) -o $dst ${d_path}(+)${s_base}.iii + Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src} + "$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii + Trim --source-code --convert-hex -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.ii + "$(NASM)" -I${s_path}(+) -l ${d_path}(+)${s_base}.lst $(NASMB_FLAGS) $(NASM_INC) -o $dst ${d_path}(+)${s_base}.iii # copy the output file with .com postfix that be same to the output file of .asm16 $(CP) ${dst} $(OUTPUT_DIR)(+)${s_base}.com @@ -623,20 +635,20 @@ $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.hpk - "$(VFRPP)" $(VFRPP_FLAGS) $(INC) ${src} > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i + "$(VFRPP)" $(DEPS_FLAGS) $(VFRPP_FLAGS) $(INC) ${src} > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i "$(VFR)" $(VFR_FLAGS) --create-ifr-package --string-db $(OUTPUT_DIR)(+)$(MODULE_NAME)StrDefs.hpk --output-directory $(OUTPUT_DIR)(+)${s_dir} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i [Hii-Binary-Package.UEFI_HII] *.hpk - + $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.lib $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc - + "$(GENFW)" -o $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc -g $(MODULE_GUID) --hiipackage $(HII_BINARY_PACKAGES) $(GENFW_FLAGS) "$(RC)" /Fo${dst} $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template index dce6c5875a2..feee2bbf161 100755 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template @@ -4,9 +4,18 @@ # Portions copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
# Copyright (c) 2015, Hewlett-Packard Development Company, L.P.
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+# Copyright (c) Microsoft Corporation # # SPDX-License-Identifier: BSD-2-Clause-Patent # +# +# Increase this version tag any time you want user to get warning about updating this +# file in the Conf dir. By default it does not do update existing conf dirs. +# +# 2.00 - Initial version with changes for CI +# - Change RC path to use plugin +# +#!VERSION=2.00 IDENTIFIER = Default TOOL_CHAIN_CONF @@ -71,6 +80,11 @@ DEFINE VS2019_BIN_X64 = DEF(VS2019_BIN)\HostDEF(VS_HOST)\x64 DEFINE VS2019_BIN_ARM = DEF(VS2019_BIN)\HostDEF(VS_HOST)\arm DEFINE VS2019_BIN_AARCH64 = DEF(VS2019_BIN)\HostDEF(VS_HOST)\arm64 +# +# Resource compiler +# +DEFINE RC_PATH = ENV(WINSDK_PATH_FOR_RC_EXE)\rc.exe + DEFINE WINSDK_BIN = ENV(WINSDK_PREFIX) DEFINE WINSDKx86_BIN = ENV(WINSDKx86_PREFIX) @@ -133,6 +147,9 @@ DEFINE DEFAULT_WIN_ASL_BIN = DEF(WIN_IASL_BIN) DEFINE DEFAULT_WIN_ASL_FLAGS = DEF(IASL_FLAGS) DEFINE DEFAULT_WIN_ASL_OUTFLAGS = DEF(IASL_OUTFLAGS) +# MSFT Build Flag for included header file list generation +DEFINE MSFT_DEPS_FLAGS = /showIncludes + DEFINE MSFT_ASLPP_FLAGS = /nologo /E /C /FIAutoGen.h DEFINE MSFT_ASLCC_FLAGS = /nologo /c /FIAutoGen.h /TC /Dmain=ReferenceAcpiTable DEFINE MSFT_ASLDLINK_FLAGS = /NODEFAULTLIB /ENTRY:ReferenceAcpiTable /SUBSYSTEM:CONSOLE @@ -268,7 +285,7 @@ DEFINE DTC_BIN = ENV(DTC_PREFIX)dtc # Required to build platforms or ACPI tables: # Intel(r) ACPI Compiler from # https://acpica.org/downloads -# CLANG9 -Linux, Windows, Mac- Requires: +# CLANGPDB -Linux, Windows, Mac- Requires: # Clang 9 or above from http://releases.llvm.org/ # Optional: # Required to compile nasm source: @@ -320,12 +337,16 @@ DEFINE DTC_BIN = ENV(DTC_PREFIX)dtc # Required to build platforms or ACPI tables: # Microsoft ASL ACPI Compiler (asl.exe) v4.0.0 from # http://download.microsoft.com/download/2/c/1/2c16c7e0-96c1-40f5-81fc-3e4bf7b65496/microsoft_asl_compiler-v4-0-0.msi +# Notes: Since this tool chain is obsolete, it doesn't enable the compiler option for included header file list generation, +# and lose the incremental build capability. # RVCTLINUX -unix- Requires: # ARM C/C++ Compiler, 5.00 # Optional: # Required to build platforms or ACPI tables: # Intel(r) ACPI Compiler from # https://acpica.org/downloads +# Notes: Since this tool chain is obsolete, it doesn't enable the compiler option for included header file list generation, +# and lose the incremental build capability. # * Commented out - All versions of VS2005 use the same standard install directory # #################################################################################### @@ -401,7 +422,7 @@ DEFINE DTC_BIN = ENV(DTC_PREFIX)dtc *_VS2008_*_APP_FLAGS = /nologo /E /TC *_VS2008_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2008_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h - +*_VS2008_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2008_*_ASM16_PATH = DEF(VS2008_BIN)\ml.exe ################## @@ -464,9 +485,9 @@ NOOPT_VS2008_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2008_X64_ASLPP_PATH = DEF(VS2008_BINX64)\cl.exe *_VS2008_X64_ASLDLINK_PATH = DEF(VS2008_BINX64)\link.exe - DEBUG_VS2008_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /MP -RELEASE_VS2008_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2008_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2008_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 +RELEASE_VS2008_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2008_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2008_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2008_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -517,7 +538,7 @@ NOOPT_VS2008_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2008x86_*_APP_FLAGS = /nologo /E /TC *_VS2008x86_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2008x86_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h - +*_VS2008x86_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2008x86_*_ASM16_PATH = DEF(VS2008x86_BIN)\ml.exe ################## @@ -548,9 +569,9 @@ NOOPT_VS2008_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2008x86_IA32_ASM_PATH = DEF(VS2008x86_BIN)\ml.exe *_VS2008x86_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2008x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /MP -RELEASE_VS2008x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2008x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2008x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 +RELEASE_VS2008x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2008x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2008x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2008x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -580,10 +601,9 @@ NOOPT_VS2008x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2008x86_X64_DLINK_PATH = DEF(VS2008x86_BINX64)\link.exe *_VS2008x86_X64_ASLDLINK_PATH = DEF(VS2008x86_BINX64)\link.exe - DEBUG_VS2008x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /MP -RELEASE_VS2008x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2008x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP - + DEBUG_VS2008x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 +RELEASE_VS2008x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2008x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2008x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2008x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd NOOPT_VS2008x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi @@ -636,7 +656,7 @@ NOOPT_VS2008x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2010_*_APP_FLAGS = /nologo /E /TC *_VS2010_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2010_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h - +*_VS2010_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2010_*_ASM16_PATH = DEF(VS2010_BIN)\ml.exe ################## @@ -667,9 +687,9 @@ NOOPT_VS2008x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2010_IA32_ASLDLINK_PATH = DEF(VS2010_BIN)\link.exe *_VS2010_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2010_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /MP -RELEASE_VS2010_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2010_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm /Od /MP + DEBUG_VS2010_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 +RELEASE_VS2010_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2010_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Zi /Gm /Od DEBUG_VS2010_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2010_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -699,9 +719,9 @@ NOOPT_VS2010_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2010_X64_ASLPP_PATH = DEF(VS2010_BINX64)\cl.exe *_VS2010_X64_ASLDLINK_PATH = DEF(VS2010_BINX64)\link.exe - DEBUG_VS2010_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /MP -RELEASE_VS2010_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2010_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2010_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 +RELEASE_VS2010_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2010_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2010_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2010_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -752,7 +772,7 @@ NOOPT_VS2010_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2010x86_*_APP_FLAGS = /nologo /E /TC *_VS2010x86_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2010x86_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h - +*_VS2010x86_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2010x86_*_ASM16_PATH = DEF(VS2010x86_BIN)\ml.exe ################## @@ -783,9 +803,9 @@ NOOPT_VS2010_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2010x86_IA32_ASM_PATH = DEF(VS2010x86_BIN)\ml.exe *_VS2010x86_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2010x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /MP -RELEASE_VS2010x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2010x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2010x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 +RELEASE_VS2010x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2010x86_IA32_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2010x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2010x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -815,9 +835,9 @@ NOOPT_VS2010x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2010x86_X64_DLINK_PATH = DEF(VS2010x86_BINX64)\link.exe *_VS2010x86_X64_ASLDLINK_PATH = DEF(VS2010x86_BINX64)\link.exe - DEBUG_VS2010x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /MP -RELEASE_VS2010x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2010x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2010x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 +RELEASE_VS2010x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2010x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2010x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2010x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -870,7 +890,7 @@ NOOPT_VS2010x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2012_*_APP_FLAGS = /nologo /E /TC *_VS2012_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2012_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h - +*_VS2012_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2012_*_ASM16_PATH = DEF(VS2012_BIN)\ml.exe ################## @@ -901,9 +921,9 @@ NOOPT_VS2010x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2012_IA32_ASLDLINK_PATH = DEF(VS2012_BIN)\link.exe *_VS2012_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2012_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /MP -RELEASE_VS2012_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2012_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2012_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 +RELEASE_VS2012_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2012_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2012_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2012_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -933,9 +953,9 @@ NOOPT_VS2012_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2012_X64_ASLPP_PATH = DEF(VS2012_BINX64)\cl.exe *_VS2012_X64_ASLDLINK_PATH = DEF(VS2012_BINX64)\link.exe - DEBUG_VS2012_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /MP -RELEASE_VS2012_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2012_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2012_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 +RELEASE_VS2012_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2012_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2012_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2012_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -986,7 +1006,7 @@ NOOPT_VS2012_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2012x86_*_APP_FLAGS = /nologo /E /TC *_VS2012x86_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2012x86_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h - +*_VS2012x86_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2012x86_*_ASM16_PATH = DEF(VS2012x86_BIN)\ml.exe ################## @@ -1017,9 +1037,9 @@ NOOPT_VS2012_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2012x86_IA32_ASM_PATH = DEF(VS2012x86_BIN)\ml.exe *_VS2012x86_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2012x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /MP -RELEASE_VS2012x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2012x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2012x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 +RELEASE_VS2012x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2012x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2012x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2012x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -1049,9 +1069,9 @@ NOOPT_VS2012x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2012x86_X64_DLINK_PATH = DEF(VS2012x86_BINX64)\link.exe *_VS2012x86_X64_ASLDLINK_PATH = DEF(VS2012x86_BINX64)\link.exe - DEBUG_VS2012x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /MP -RELEASE_VS2012x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /MP -NOOPT_VS2012x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2012x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 +RELEASE_VS2012x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF +NOOPT_VS2012x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2012x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2012x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -1104,7 +1124,7 @@ NOOPT_VS2012x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2013_*_APP_FLAGS = /nologo /E /TC *_VS2013_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2013_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h - +*_VS2013_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2013_*_ASM16_PATH = DEF(VS2013_BIN)\ml.exe ################## @@ -1135,9 +1155,9 @@ NOOPT_VS2012x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2013_IA32_ASLDLINK_PATH = DEF(VS2013_BIN)\link.exe *_VS2013_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2013_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw /MP -RELEASE_VS2013_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2013_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2013_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw +RELEASE_VS2013_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2013_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2013_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2013_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -1167,9 +1187,9 @@ NOOPT_VS2013_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2013_X64_ASLPP_PATH = DEF(VS2013_BINX64)\cl.exe *_VS2013_X64_ASLDLINK_PATH = DEF(VS2013_BINX64)\link.exe - DEBUG_VS2013_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw /MP -RELEASE_VS2013_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2013_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2013_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw +RELEASE_VS2013_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2013_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2013_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2013_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -1220,7 +1240,7 @@ NOOPT_VS2013_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2013x86_*_APP_FLAGS = /nologo /E /TC *_VS2013x86_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2013x86_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h - +*_VS2013x86_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2013x86_*_ASM16_PATH = DEF(VS2013x86_BIN)\ml.exe ################## @@ -1251,9 +1271,9 @@ NOOPT_VS2013_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2013x86_IA32_ASM_PATH = DEF(VS2013x86_BIN)\ml.exe *_VS2013x86_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2013x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw /MP -RELEASE_VS2013x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2013x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2013x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw +RELEASE_VS2013x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2013x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2013x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2013x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -1283,9 +1303,9 @@ NOOPT_VS2013x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2013x86_X64_DLINK_PATH = DEF(VS2013x86_BINX64)\link.exe *_VS2013x86_X64_ASLDLINK_PATH = DEF(VS2013x86_BINX64)\link.exe - DEBUG_VS2013x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw /MP -RELEASE_VS2013x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2013x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2013x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw +RELEASE_VS2013x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2013x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2013x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2013x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -1339,7 +1359,7 @@ NOOPT_VS2013x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2015_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2015_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h *_VS2015_*_DLINK2_FLAGS = - +*_VS2015_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2015_*_ASM16_PATH = DEF(VS2015_BIN)\ml.exe ################## @@ -1370,9 +1390,9 @@ NOOPT_VS2013x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2015_IA32_ASLDLINK_PATH = DEF(VS2015_BIN)\link.exe *_VS2015_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2015_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw /MP -RELEASE_VS2015_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2015_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2015_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw +RELEASE_VS2015_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2015_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2015_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2015_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -1402,9 +1422,9 @@ NOOPT_VS2015_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2015_X64_ASLPP_PATH = DEF(VS2015_BINX64)\cl.exe *_VS2015_X64_ASLDLINK_PATH = DEF(VS2015_BINX64)\link.exe - DEBUG_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw /MP -RELEASE_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw +RELEASE_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2015_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2015_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -1456,7 +1476,7 @@ NOOPT_VS2015_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2015x86_*_PP_FLAGS = /nologo /E /TC /FIAutoGen.h *_VS2015x86_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h *_VS2015x86_*_DLINK2_FLAGS = - +*_VS2015x86_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) *_VS2015x86_*_ASM16_PATH = DEF(VS2015x86_BIN)\ml.exe ################## @@ -1487,9 +1507,9 @@ NOOPT_VS2015_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT *_VS2015x86_IA32_ASM_PATH = DEF(VS2015x86_BIN)\ml.exe *_VS2015x86_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2015x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw /MP -RELEASE_VS2015x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2015x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2015x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw +RELEASE_VS2015x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2015x86_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2015x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2015x86_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -1519,9 +1539,9 @@ NOOPT_VS2015x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2015x86_X64_DLINK_PATH = DEF(VS2015x86_BINX64)\link.exe *_VS2015x86_X64_ASLDLINK_PATH = DEF(VS2015x86_BINX64)\link.exe - DEBUG_VS2015x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw /MP -RELEASE_VS2015x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2015x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2015x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw +RELEASE_VS2015x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2015x86_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2015x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2015x86_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -1566,7 +1586,7 @@ NOOPT_VS2015x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2017_*_MAKE_PATH = DEF(VS2017_BIN_HOST)\nmake.exe *_VS2017_*_MAKE_FLAG = /nologo -*_VS2017_*_RC_PATH = DEF(WINSDK10_BIN)\rc.exe +*_VS2017_*_RC_PATH = DEF(RC_PATH) *_VS2017_*_MAKE_FLAGS = /nologo *_VS2017_*_SLINK_FLAGS = /NOLOGO /LTCG @@ -1575,7 +1595,7 @@ NOOPT_VS2015x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2017_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h *_VS2017_*_DLINK2_FLAGS = /WHOLEARCHIVE *_VS2017_*_ASM16_PATH = DEF(VS2017_BIN_IA32)\ml.exe - +*_VS2017_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) ################## # ASL definitions ################## @@ -1601,9 +1621,9 @@ NOOPT_VS2015x86_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2017_IA32_ASM_PATH = DEF(VS2017_BIN_IA32)\ml.exe *_VS2017_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2017_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw /MP -RELEASE_VS2017_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2017_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2017_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw +RELEASE_VS2017_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2017_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2017_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2017_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -1631,9 +1651,9 @@ NOOPT_VS2017_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /O *_VS2017_X64_DLINK_PATH = DEF(VS2017_BIN_X64)\link.exe *_VS2017_X64_ASLDLINK_PATH = DEF(VS2017_BIN_X64)\link.exe - DEBUG_VS2017_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw /MP -RELEASE_VS2017_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2017_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2017_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw +RELEASE_VS2017_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2017_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2017_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2017_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -1729,7 +1749,7 @@ NOOPT_VS2017_AARCH64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2019_*_MAKE_PATH = DEF(VS2019_BIN_HOST)\nmake.exe *_VS2019_*_MAKE_FLAG = /nologo -*_VS2019_*_RC_PATH = DEF(WINSDK10_BIN)\rc.exe +*_VS2019_*_RC_PATH = DEF(RC_PATH) *_VS2019_*_MAKE_FLAGS = /nologo *_VS2019_*_SLINK_FLAGS = /NOLOGO /LTCG @@ -1738,7 +1758,7 @@ NOOPT_VS2017_AARCH64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2019_*_VFRPP_FLAGS = /nologo /E /TC /DVFRCOMPILE /FI$(MODULE_NAME)StrDefs.h *_VS2019_*_DLINK2_FLAGS = /WHOLEARCHIVE *_VS2019_*_ASM16_PATH = DEF(VS2019_BIN_IA32)\ml.exe - +*_VS2019_*_DEPS_FLAGS = DEF(MSFT_DEPS_FLAGS) ################## # ASL definitions ################## @@ -1764,9 +1784,9 @@ NOOPT_VS2017_AARCH64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF *_VS2019_IA32_ASM_PATH = DEF(VS2019_BIN_IA32)\ml.exe *_VS2019_IA32_MAKE_FLAGS = /nologo - DEBUG_VS2019_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw /MP -RELEASE_VS2019_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2019_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od /MP + DEBUG_VS2019_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Gw +RELEASE_VS2019_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2 /GL /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2019_IA32_CC_FLAGS = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D UNICODE /FIAutoGen.h /EHs-c- /GR- /GF /Gy /Z7 /Od DEBUG_VS2019_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd /Zi RELEASE_VS2019_IA32_ASM_FLAGS = /nologo /c /WX /W3 /Cx /coff /Zd @@ -1794,9 +1814,9 @@ NOOPT_VS2019_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /O *_VS2019_X64_DLINK_PATH = DEF(VS2019_BIN_X64)\link.exe *_VS2019_X64_ASLDLINK_PATH = DEF(VS2019_BIN_X64)\link.exe - DEBUG_VS2019_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw /MP -RELEASE_VS2019_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw /MP -NOOPT_VS2019_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od /MP + DEBUG_VS2019_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw +RELEASE_VS2019_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw +NOOPT_VS2019_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Od DEBUG_VS2019_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd /Zi RELEASE_VS2019_X64_ASM_FLAGS = /nologo /c /WX /W3 /Cx /Zd @@ -1927,6 +1947,9 @@ DEFINE GCC_X64_RC_FLAGS = -I binary -O elf64-x86-64 -B i386 DEFINE GCC_ARM_RC_FLAGS = -I binary -O elf32-littlearm -B arm --rename-section .data=.hii DEFINE GCC_AARCH64_RC_FLAGS = -I binary -O elf64-littleaarch64 -B aarch64 --rename-section .data=.hii +# GCC Build Flag for included header file list generation +DEFINE GCC_DEPS_FLAGS = -MMD -MF $@.deps + DEFINE GCC48_ALL_CC_FLAGS = -g -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -include AutoGen.h -fno-common -DSTRING_ARRAY_NAME=$(BASE_NAME)Strings DEFINE GCC48_IA32_X64_DLINK_COMMON = -nostdlib -Wl,-n,-q,--gc-sections -z common-page-size=0x20 DEFINE GCC48_IA32_CC_FLAGS = DEF(GCC48_ALL_CC_FLAGS) -m32 -march=i586 -malign-double -fno-stack-protector -D EFI32 -fno-asynchronous-unwind-tables -Wno-address @@ -2016,6 +2039,7 @@ DEFINE GCC5_ASLCC_FLAGS = DEF(GCC49_ASLCC_FLAGS) -fno-lto *_GCC48_*_APP_FLAGS = *_GCC48_*_ASL_FLAGS = DEF(IASL_FLAGS) *_GCC48_*_ASL_OUTFLAGS = DEF(IASL_OUTFLAGS) +*_GCC48_*_DEPS_FLAGS = DEF(GCC_DEPS_FLAGS) ################## # GCC48 IA32 definitions @@ -2155,6 +2179,7 @@ RELEASE_GCC48_AARCH64_CC_FLAGS = DEF(GCC48_AARCH64_CC_FLAGS) -Wno-unused-but-s *_GCC49_*_APP_FLAGS = *_GCC49_*_ASL_FLAGS = DEF(IASL_FLAGS) *_GCC49_*_ASL_OUTFLAGS = DEF(IASL_OUTFLAGS) +*_GCC49_*_DEPS_FLAGS = DEF(GCC_DEPS_FLAGS) ################## # GCC49 IA32 definitions @@ -2301,6 +2326,7 @@ RELEASE_GCC49_AARCH64_DLINK_XIPFLAGS = -z common-page-size=0x20 *_GCC5_*_APP_FLAGS = *_GCC5_*_ASL_FLAGS = DEF(IASL_FLAGS) *_GCC5_*_ASL_OUTFLAGS = DEF(IASL_OUTFLAGS) +*_GCC5_*_DEPS_FLAGS = DEF(GCC_DEPS_FLAGS) ################## # GCC5 IA32 definitions @@ -2466,6 +2492,7 @@ RELEASE_GCC5_AARCH64_DLINK_XIPFLAGS = -z common-page-size=0x20 *_CLANG35_*_ASLPP_PATH = ENV(CLANG35_BIN)clang *_CLANG35_*_DLINK_PATH = ENV(CLANG35_BIN)clang *_CLANG35_*_ASLDLINK_PATH = ENV(CLANG35_BIN)clang +*_CLANG35_*_DEPS_FLAGS = DEF(GCC_DEPS_FLAGS) DEFINE CLANG35_ARM_TARGET = -target arm-linux-gnueabi DEFINE CLANG35_AARCH64_TARGET = -target aarch64-linux-gnu @@ -2533,7 +2560,7 @@ RELEASE_CLANG35_AARCH64_CC_FLAGS = DEF(CLANG35_AARCH64_CC_FLAGS) $(ARCHCC_FLAGS) *_CLANG38_*_APP_FLAGS = *_CLANG38_*_ASL_FLAGS = DEF(IASL_FLAGS) *_CLANG38_*_ASL_OUTFLAGS = DEF(IASL_OUTFLAGS) - +*_CLANG38_*_DEPS_FLAGS = DEF(GCC_DEPS_FLAGS) DEFINE CLANG38_IA32_PREFIX = ENV(CLANG38_BIN) DEFINE CLANG38_X64_PREFIX = ENV(CLANG38_BIN) @@ -2709,97 +2736,98 @@ RELEASE_CLANG38_AARCH64_DLINK_FLAGS = DEF(CLANG38_AARCH64_DLINK_FLAGS) -flto -Wl #################################################################################### # -# CLANG9 - This configuration is used to compile under Windows/Linux/Mac to produce +# CLANGPDB - This configuration is used to compile under Windows/Linux/Mac to produce # PE/COFF binaries using LLVM/Clang/LLD with Link Time Optimization enabled # #################################################################################### -*_CLANG9_*_*_FAMILY = GCC -*_CLANG9_*_*_BUILDRULEFAMILY = CLANGPE -*_CLANG9_*_MAKE_PATH = ENV(CLANG_HOST_BIN)make -*_CLANG9_*_*_DLL = ENV(CLANG9_DLL) -*_CLANG9_*_ASL_PATH = DEF(UNIX_IASL_BIN) +*_CLANGPDB_*_*_FAMILY = GCC +*_CLANGPDB_*_*_BUILDRULEFAMILY = CLANGPDB +*_CLANGPDB_*_MAKE_PATH = ENV(CLANG_HOST_BIN)make +*_CLANGPDB_*_*_DLL = ENV(CLANGPDB_DLL) +*_CLANGPDB_*_ASL_PATH = DEF(UNIX_IASL_BIN) -*_CLANG9_*_APP_FLAGS = -*_CLANG9_*_ASL_FLAGS = DEF(DEFAULT_WIN_ASL_FLAGS) -*_CLANG9_*_ASL_OUTFLAGS = DEF(DEFAULT_WIN_ASL_OUTFLAGS) -*_CLANG9_*_ASLDLINK_FLAGS = DEF(MSFT_ASLDLINK_FLAGS) +*_CLANGPDB_*_APP_FLAGS = +*_CLANGPDB_*_ASL_FLAGS = DEF(DEFAULT_WIN_ASL_FLAGS) +*_CLANGPDB_*_ASL_OUTFLAGS = DEF(DEFAULT_WIN_ASL_OUTFLAGS) +*_CLANGPDB_*_ASLDLINK_FLAGS = DEF(MSFT_ASLDLINK_FLAGS) +*_CLANGPDB_*_DEPS_FLAGS = DEF(GCC_DEPS_FLAGS) -DEFINE CLANG9_IA32_PREFIX = ENV(CLANG9_BIN) -DEFINE CLANG9_X64_PREFIX = ENV(CLANG9_BIN) +DEFINE CLANGPDB_IA32_PREFIX = ENV(CLANG_BIN) +DEFINE CLANGPDB_X64_PREFIX = ENV(CLANG_BIN) -DEFINE CLANG9_IA32_TARGET = -target i686-unknown-windows -DEFINE CLANG9_X64_TARGET = -target x86_64-unknown-windows +DEFINE CLANGPDB_IA32_TARGET = -target i686-unknown-windows +DEFINE CLANGPDB_X64_TARGET = -target x86_64-unknown-windows -DEFINE CLANG9_WARNING_OVERRIDES = -Wno-parentheses-equality -Wno-tautological-compare -Wno-tautological-constant-out-of-range-compare -Wno-empty-body -Wno-unused-const-variable -Wno-varargs -Wno-unknown-warning-option -Wno-microsoft-enum-forward-reference -DEFINE CLANG9_ALL_CC_FLAGS = DEF(GCC48_ALL_CC_FLAGS) DEF(CLANG9_WARNING_OVERRIDES) -fno-stack-protector -mms-bitfields -Wno-address -Wno-shift-negative-value -Wno-unknown-pragmas -Wno-incompatible-library-redeclaration -fno-asynchronous-unwind-tables -mno-implicit-float -ftrap-function=undefined_behavior_has_been_optimized_away_by_clang -funsigned-char -fno-ms-extensions -Wno-null-dereference -fms-compatibility -mno-stack-arg-probe +DEFINE CLANGPDB_WARNING_OVERRIDES = -Wno-parentheses-equality -Wno-tautological-compare -Wno-tautological-constant-out-of-range-compare -Wno-empty-body -Wno-unused-const-variable -Wno-varargs -Wno-unknown-warning-option -Wno-microsoft-enum-forward-reference +DEFINE CLANGPDB_ALL_CC_FLAGS = DEF(GCC48_ALL_CC_FLAGS) DEF(CLANGPDB_WARNING_OVERRIDES) -fno-stack-protector -mms-bitfields -Wno-address -Wno-shift-negative-value -Wno-unknown-pragmas -Wno-incompatible-library-redeclaration -fno-asynchronous-unwind-tables -mno-implicit-float -ftrap-function=undefined_behavior_has_been_optimized_away_by_clang -funsigned-char -fno-ms-extensions -Wno-null-dereference -fms-compatibility -mno-stack-arg-probe ########################### -# CLANG9 IA32 definitions +# CLANGPDB IA32 definitions ########################### -*_CLANG9_IA32_CC_PATH = DEF(CLANG9_IA32_PREFIX)clang -*_CLANG9_IA32_SLINK_PATH = DEF(CLANG9_IA32_PREFIX)llvm-lib -*_CLANG9_IA32_DLINK_PATH = DEF(CLANG9_IA32_PREFIX)lld-link -*_CLANG9_IA32_ASLDLINK_PATH = DEF(CLANG9_IA32_PREFIX)lld-link -*_CLANG9_IA32_ASM_PATH = DEF(CLANG9_IA32_PREFIX)clang -*_CLANG9_IA32_PP_PATH = DEF(CLANG9_IA32_PREFIX)clang -*_CLANG9_IA32_VFRPP_PATH = DEF(CLANG9_IA32_PREFIX)clang -*_CLANG9_IA32_ASLCC_PATH = DEF(CLANG9_IA32_PREFIX)clang -*_CLANG9_IA32_ASLPP_PATH = DEF(CLANG9_IA32_PREFIX)clang -*_CLANG9_IA32_RC_PATH = DEF(CLANG9_IA32_PREFIX)llvm-rc - -*_CLANG9_IA32_ASLCC_FLAGS = DEF(GCC_ASLCC_FLAGS) -m32 -fno-lto DEF(CLANG9_IA32_TARGET) -*_CLANG9_IA32_ASM_FLAGS = DEF(GCC_ASM_FLAGS) -m32 -march=i386 DEF(CLANG9_IA32_TARGET) -*_CLANG9_IA32_OBJCOPY_FLAGS = -*_CLANG9_IA32_NASM_FLAGS = -f win32 -*_CLANG9_IA32_PP_FLAGS = DEF(GCC_PP_FLAGS) DEF(CLANG9_IA32_TARGET) -*_CLANG9_IA32_ASLPP_FLAGS = DEF(GCC_ASLPP_FLAGS) DEF(CLANG9_IA32_TARGET) -*_CLANG9_IA32_VFRPP_FLAGS = DEF(GCC_VFRPP_FLAGS) DEF(CLANG9_IA32_TARGET) - -DEBUG_CLANG9_IA32_CC_FLAGS = DEF(CLANG9_ALL_CC_FLAGS) -m32 -Oz -flto -march=i586 DEF(CLANG9_IA32_TARGET) -gcodeview -DEBUG_CLANG9_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /lldmap -DEBUG_CLANG9_IA32_DLINK2_FLAGS = - -RELEASE_CLANG9_IA32_CC_FLAGS = DEF(CLANG9_ALL_CC_FLAGS) -m32 -Oz -flto -march=i586 DEF(CLANG9_IA32_TARGET) -RELEASE_CLANG9_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /MERGE:.rdata=.data /lldmap -RELEASE_CLANG9_IA32_DLINK2_FLAGS = - -NOOPT_CLANG9_IA32_CC_FLAGS = DEF(CLANG9_ALL_CC_FLAGS) -m32 -O0 -march=i586 DEF(CLANG9_IA32_TARGET) -gcodeview -NOOPT_CLANG9_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /lldmap -NOOPT_CLANG9_IA32_DLINK2_FLAGS = +*_CLANGPDB_IA32_CC_PATH = DEF(CLANGPDB_IA32_PREFIX)clang +*_CLANGPDB_IA32_SLINK_PATH = DEF(CLANGPDB_IA32_PREFIX)llvm-lib +*_CLANGPDB_IA32_DLINK_PATH = DEF(CLANGPDB_IA32_PREFIX)lld-link +*_CLANGPDB_IA32_ASLDLINK_PATH = DEF(CLANGPDB_IA32_PREFIX)lld-link +*_CLANGPDB_IA32_ASM_PATH = DEF(CLANGPDB_IA32_PREFIX)clang +*_CLANGPDB_IA32_PP_PATH = DEF(CLANGPDB_IA32_PREFIX)clang +*_CLANGPDB_IA32_VFRPP_PATH = DEF(CLANGPDB_IA32_PREFIX)clang +*_CLANGPDB_IA32_ASLCC_PATH = DEF(CLANGPDB_IA32_PREFIX)clang +*_CLANGPDB_IA32_ASLPP_PATH = DEF(CLANGPDB_IA32_PREFIX)clang +*_CLANGPDB_IA32_RC_PATH = DEF(CLANGPDB_IA32_PREFIX)llvm-rc + +*_CLANGPDB_IA32_ASLCC_FLAGS = DEF(GCC_ASLCC_FLAGS) -m32 -fno-lto DEF(CLANGPDB_IA32_TARGET) +*_CLANGPDB_IA32_ASM_FLAGS = DEF(GCC_ASM_FLAGS) -m32 -march=i386 DEF(CLANGPDB_IA32_TARGET) +*_CLANGPDB_IA32_OBJCOPY_FLAGS = +*_CLANGPDB_IA32_NASM_FLAGS = -f win32 +*_CLANGPDB_IA32_PP_FLAGS = DEF(GCC_PP_FLAGS) DEF(CLANGPDB_IA32_TARGET) +*_CLANGPDB_IA32_ASLPP_FLAGS = DEF(GCC_ASLPP_FLAGS) DEF(CLANGPDB_IA32_TARGET) +*_CLANGPDB_IA32_VFRPP_FLAGS = DEF(GCC_VFRPP_FLAGS) DEF(CLANGPDB_IA32_TARGET) + +DEBUG_CLANGPDB_IA32_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m32 -Oz -flto -march=i586 DEF(CLANGPDB_IA32_TARGET) -gcodeview +DEBUG_CLANGPDB_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /lldmap +DEBUG_CLANGPDB_IA32_DLINK2_FLAGS = + +RELEASE_CLANGPDB_IA32_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m32 -Oz -flto -march=i586 DEF(CLANGPDB_IA32_TARGET) +RELEASE_CLANGPDB_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /MERGE:.rdata=.data /lldmap +RELEASE_CLANGPDB_IA32_DLINK2_FLAGS = + +NOOPT_CLANGPDB_IA32_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m32 -O0 -march=i586 DEF(CLANGPDB_IA32_TARGET) -gcodeview +NOOPT_CLANGPDB_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /lldmap +NOOPT_CLANGPDB_IA32_DLINK2_FLAGS = ########################## # CLANGWIN X64 definitions ########################## -*_CLANG9_X64_CC_PATH = DEF(CLANG9_X64_PREFIX)clang -*_CLANG9_X64_SLINK_PATH = DEF(CLANG9_X64_PREFIX)llvm-lib -*_CLANG9_X64_DLINK_PATH = DEF(CLANG9_X64_PREFIX)lld-link -*_CLANG9_X64_ASLDLINK_PATH = DEF(CLANG9_X64_PREFIX)lld-link -*_CLANG9_X64_ASM_PATH = DEF(CLANG9_X64_PREFIX)clang -*_CLANG9_X64_PP_PATH = DEF(CLANG9_X64_PREFIX)clang -*_CLANG9_X64_VFRPP_PATH = DEF(CLANG9_X64_PREFIX)clang -*_CLANG9_X64_ASLCC_PATH = DEF(CLANG9_X64_PREFIX)clang -*_CLANG9_X64_ASLPP_PATH = DEF(CLANG9_X64_PREFIX)clang -*_CLANG9_X64_RC_PATH = DEF(CLANG9_IA32_PREFIX)llvm-rc +*_CLANGPDB_X64_CC_PATH = DEF(CLANGPDB_X64_PREFIX)clang +*_CLANGPDB_X64_SLINK_PATH = DEF(CLANGPDB_X64_PREFIX)llvm-lib +*_CLANGPDB_X64_DLINK_PATH = DEF(CLANGPDB_X64_PREFIX)lld-link +*_CLANGPDB_X64_ASLDLINK_PATH = DEF(CLANGPDB_X64_PREFIX)lld-link +*_CLANGPDB_X64_ASM_PATH = DEF(CLANGPDB_X64_PREFIX)clang +*_CLANGPDB_X64_PP_PATH = DEF(CLANGPDB_X64_PREFIX)clang +*_CLANGPDB_X64_VFRPP_PATH = DEF(CLANGPDB_X64_PREFIX)clang +*_CLANGPDB_X64_ASLCC_PATH = DEF(CLANGPDB_X64_PREFIX)clang +*_CLANGPDB_X64_ASLPP_PATH = DEF(CLANGPDB_X64_PREFIX)clang +*_CLANGPDB_X64_RC_PATH = DEF(CLANGPDB_IA32_PREFIX)llvm-rc -*_CLANG9_X64_ASLCC_FLAGS = DEF(GCC_ASLCC_FLAGS) -m64 -fno-lto DEF(CLANG9_X64_TARGET) -*_CLANG9_X64_ASM_FLAGS = DEF(GCC_ASM_FLAGS) -m64 DEF(CLANG9_X64_TARGET) -*_CLANG9_X64_OBJCOPY_FLAGS = -*_CLANG9_X64_NASM_FLAGS = -f win64 -*_CLANG9_X64_PP_FLAGS = DEF(GCC_PP_FLAGS) DEF(CLANG9_X64_TARGET) -*_CLANG9_X64_ASLPP_FLAGS = DEF(GCC_ASLPP_FLAGS) DEF(CLANG9_X64_TARGET) -*_CLANG9_X64_VFRPP_FLAGS = DEF(GCC_VFRPP_FLAGS) DEF(CLANG9_X64_TARGET) +*_CLANGPDB_X64_ASLCC_FLAGS = DEF(GCC_ASLCC_FLAGS) -m64 -fno-lto DEF(CLANGPDB_X64_TARGET) +*_CLANGPDB_X64_ASM_FLAGS = DEF(GCC_ASM_FLAGS) -m64 DEF(CLANGPDB_X64_TARGET) +*_CLANGPDB_X64_OBJCOPY_FLAGS = +*_CLANGPDB_X64_NASM_FLAGS = -f win64 +*_CLANGPDB_X64_PP_FLAGS = DEF(GCC_PP_FLAGS) DEF(CLANGPDB_X64_TARGET) +*_CLANGPDB_X64_ASLPP_FLAGS = DEF(GCC_ASLPP_FLAGS) DEF(CLANGPDB_X64_TARGET) +*_CLANGPDB_X64_VFRPP_FLAGS = DEF(GCC_VFRPP_FLAGS) DEF(CLANGPDB_X64_TARGET) -DEBUG_CLANG9_X64_CC_FLAGS = DEF(CLANG9_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -Oz -flto DEF(CLANG9_X64_TARGET) -gcodeview -DEBUG_CLANG9_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /lldmap -DEBUG_CLANG9_X64_DLINK2_FLAGS = +DEBUG_CLANGPDB_X64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -Oz -flto DEF(CLANGPDB_X64_TARGET) -gcodeview +DEBUG_CLANGPDB_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /lldmap +DEBUG_CLANGPDB_X64_DLINK2_FLAGS = -RELEASE_CLANG9_X64_CC_FLAGS = DEF(CLANG9_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -Oz -flto DEF(CLANG9_X64_TARGET) -RELEASE_CLANG9_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /MERGE:.rdata=.data /lldmap -RELEASE_CLANG9_X64_DLINK2_FLAGS = +RELEASE_CLANGPDB_X64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -Oz -flto DEF(CLANGPDB_X64_TARGET) +RELEASE_CLANGPDB_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /MERGE:.rdata=.data /lldmap +RELEASE_CLANGPDB_X64_DLINK2_FLAGS = -NOOPT_CLANG9_X64_CC_FLAGS = DEF(CLANG9_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -O0 DEF(CLANG9_X64_TARGET) -gcodeview -NOOPT_CLANG9_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /lldmap -NOOPT_CLANG9_X64_DLINK2_FLAGS = +NOOPT_CLANGPDB_X64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -O0 DEF(CLANGPDB_X64_TARGET) -gcodeview +NOOPT_CLANGPDB_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:32 /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /lldmap +NOOPT_CLANGPDB_X64_DLINK2_FLAGS = # @@ -2826,6 +2854,7 @@ NOOPT_CLANG9_X64_DLINK2_FLAGS = *_XCODE5_*_ASLDLINK_PATH = ld *_XCODE5_*_DSYMUTIL_PATH = /usr/bin/dsymutil *_XCODE5_*_MTOC_PATH = /usr/local/bin/mtoc +*_XCODE5_*_DEPS_FLAGS = DEF(GCC_DEPS_FLAGS) ################## # ASL definitions diff --git a/BaseTools/Edk2ToolsBuild.py b/BaseTools/Edk2ToolsBuild.py new file mode 100644 index 00000000000..057d2e9e063 --- /dev/null +++ b/BaseTools/Edk2ToolsBuild.py @@ -0,0 +1,163 @@ +# @file Edk2ToolsBuild.py +# Invocable class that builds the basetool c files. +# +# Supports VS2017, VS2019, and GCC5 +## +# Copyright (c) Microsoft Corporation +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import os +import sys +import logging +import argparse +from edk2toolext import edk2_logging +from edk2toolext.environment import self_describing_environment +from edk2toolext.base_abstract_invocable import BaseAbstractInvocable +from edk2toollib.utility_functions import RunCmd +from edk2toollib.windows.locate_tools import QueryVcVariables + + +class Edk2ToolsBuild(BaseAbstractInvocable): + + def ParseCommandLineOptions(self): + ''' parse arguments ''' + ParserObj = argparse.ArgumentParser() + ParserObj.add_argument("-t", "--tool_chain_tag", dest="tct", default="VS2017", + help="Set the toolchain used to compile the build tools") + args = ParserObj.parse_args() + self.tool_chain_tag = args.tct + + def GetWorkspaceRoot(self): + ''' Return the workspace root for initializing the SDE ''' + + # this is the bastools dir...not the traditional EDK2 workspace root + return os.path.dirname(os.path.abspath(__file__)) + + def GetActiveScopes(self): + ''' return tuple containing scopes that should be active for this process ''' + + # for now don't use scopes + return ('global',) + + def GetLoggingLevel(self, loggerType): + ''' Get the logging level for a given type (return Logging.Level) + base == lowest logging level supported + con == Screen logging + txt == plain text file logging + md == markdown file logging + ''' + if(loggerType == "con"): + return logging.ERROR + else: + return logging.DEBUG + + def GetLoggingFolderRelativeToRoot(self): + ''' Return a path to folder for log files ''' + return "BaseToolsBuild" + + def GetVerifyCheckRequired(self): + ''' Will call self_describing_environment.VerifyEnvironment if this returns True ''' + return True + + def GetLoggingFileName(self, loggerType): + ''' Get the logging file name for the type. + Return None if the logger shouldn't be created + + base == lowest logging level supported + con == Screen logging + txt == plain text file logging + md == markdown file logging + ''' + return "BASETOOLS_BUILD" + + def WritePathEnvFile(self, OutputDir): + ''' Write a PyTool path env file for future PyTool based edk2 builds''' + content = '''## +# Set shell variable EDK_TOOLS_BIN to this folder +# +# Autogenerated by Edk2ToolsBuild.py +# +# Copyright (c), Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "id": "You-Built-BaseTools", + "scope": "edk2-build", + "flags": ["set_shell_var", "set_path"], + "var_name": "EDK_TOOLS_BIN" +} +''' + with open(os.path.join(OutputDir, "basetoolsbin_path_env.yaml"), "w") as f: + f.write(content) + + def Go(self): + logging.info("Running Python version: " + str(sys.version_info)) + + (build_env, shell_env) = self_describing_environment.BootstrapEnvironment( + self.GetWorkspaceRoot(), self.GetActiveScopes()) + + # # Bind our current execution environment into the shell vars. + ph = os.path.dirname(sys.executable) + if " " in ph: + ph = '"' + ph + '"' + shell_env.set_shell_var("PYTHON_HOME", ph) + # PYTHON_COMMAND is required to be set for using edk2 python builds. + pc = sys.executable + if " " in pc: + pc = '"' + pc + '"' + shell_env.set_shell_var("PYTHON_COMMAND", pc) + + if self.tool_chain_tag.lower().startswith("vs"): + + # # Update environment with required VC vars. + interesting_keys = ["ExtensionSdkDir", "INCLUDE", "LIB"] + interesting_keys.extend( + ["LIBPATH", "Path", "UniversalCRTSdkDir", "UCRTVersion", "WindowsLibPath", "WindowsSdkBinPath"]) + interesting_keys.extend( + ["WindowsSdkDir", "WindowsSdkVerBinPath", "WindowsSDKVersion", "VCToolsInstallDir"]) + vc_vars = QueryVcVariables( + interesting_keys, 'x86', vs_version=self.tool_chain_tag.lower()) + for key in vc_vars.keys(): + logging.debug(f"Var - {key} = {vc_vars[key]}") + if key.lower() == 'path': + shell_env.insert_path(vc_vars[key]) + else: + shell_env.set_shell_var(key, vc_vars[key]) + + self.OutputDir = os.path.join( + shell_env.get_shell_var("EDK_TOOLS_PATH"), "Bin", "Win32") + + # compiled tools need to be added to path because antlr is referenced + shell_env.insert_path(self.OutputDir) + + # Actually build the tools. + ret = RunCmd('nmake.exe', None, + workingdir=shell_env.get_shell_var("EDK_TOOLS_PATH")) + if ret != 0: + raise Exception("Failed to build.") + + self.WritePathEnvFile(self.OutputDir) + return ret + + elif self.tool_chain_tag.lower().startswith("gcc"): + ret = RunCmd("make", "-C .", workingdir=shell_env.get_shell_var("EDK_TOOLS_PATH")) + if ret != 0: + raise Exception("Failed to build.") + + self.OutputDir = os.path.join( + shell_env.get_shell_var("EDK_TOOLS_PATH"), "Source", "C", "bin") + + self.WritePathEnvFile(self.OutputDir) + return ret + + logging.critical("Tool Chain not supported") + return -1 + + +def main(): + Edk2ToolsBuild().Invoke() + + +if __name__ == "__main__": + main() diff --git a/BaseTools/Plugin/BuildToolsReport/BuildToolsReportGenerator.py b/BaseTools/Plugin/BuildToolsReport/BuildToolsReportGenerator.py new file mode 100644 index 00000000000..9f86b1c3588 --- /dev/null +++ b/BaseTools/Plugin/BuildToolsReport/BuildToolsReportGenerator.py @@ -0,0 +1,69 @@ +## +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import os +import logging +import json + +try: + from edk2toolext.environment.plugintypes.uefi_build_plugin import IUefiBuildPlugin + + class BuildToolsReportGenerator(IUefiBuildPlugin): + def do_report(self, thebuilder): + try: + from edk2toolext.environment import version_aggregator + except ImportError: + logging.critical("Loading BuildToolsReportGenerator failed, please update your Edk2-PyTool-Extensions") + return 0 + + OutputReport = os.path.join(thebuilder.env.GetValue("BUILD_OUTPUT_BASE"), "BUILD_TOOLS_REPORT") + OutputReport = os.path.normpath(OutputReport) + if not os.path.isdir(os.path.dirname(OutputReport)): + os.makedirs(os.path.dirname(OutputReport)) + + Report = BuildToolsReport() + Report.MakeReport(version_aggregator.GetVersionAggregator().GetAggregatedVersionInformation(), OutputReport=OutputReport) + + def do_pre_build(self, thebuilder): + self.do_report(thebuilder) + return 0 + + def do_post_build(self, thebuilder): + self.do_report(thebuilder) + return 0 + +except ImportError: + pass + + +class BuildToolsReport(object): + MY_FOLDER = os.path.dirname(os.path.realpath(__file__)) + VERSION = "1.00" + + def __init__(self): + pass + + def MakeReport(self, BuildTools, OutputReport="BuildToolsReport"): + logging.info("Writing BuildToolsReports to {0}".format(OutputReport)) + versions_list = [] + for key, value in BuildTools.items(): + versions_list.append(value) + versions_list = sorted(versions_list, key=lambda k: k['type']) + json_dict = {"modules": versions_list, + "PluginVersion": BuildToolsReport.VERSION} + + htmlfile = open(OutputReport + ".html", "w") + jsonfile = open(OutputReport + ".json", "w") + template = open(os.path.join(BuildToolsReport.MY_FOLDER, "BuildToolsReport_Template.html"), "r") + + for line in template.readlines(): + if "%TO_BE_FILLED_IN_BY_PYTHON_SCRIPT%" in line: + line = line.replace("%TO_BE_FILLED_IN_BY_PYTHON_SCRIPT%", json.dumps(json_dict)) + htmlfile.write(line) + + jsonfile.write(json.dumps(versions_list, indent=4)) + + jsonfile.close() + template.close() + htmlfile.close() diff --git a/BaseTools/Plugin/BuildToolsReport/BuildToolsReportGenerator_plug_in.yaml b/BaseTools/Plugin/BuildToolsReport/BuildToolsReportGenerator_plug_in.yaml new file mode 100644 index 00000000000..89335357297 --- /dev/null +++ b/BaseTools/Plugin/BuildToolsReport/BuildToolsReportGenerator_plug_in.yaml @@ -0,0 +1,12 @@ +## @file +# Build Plugin used to output html report of all versions collected +# during the build +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "global", + "name": "Build Tools Report Generator", + "module": "BuildToolsReportGenerator" +} diff --git a/BaseTools/Plugin/BuildToolsReport/BuildToolsReport_Template.html b/BaseTools/Plugin/BuildToolsReport/BuildToolsReport_Template.html new file mode 100644 index 00000000000..8273fdee499 --- /dev/null +++ b/BaseTools/Plugin/BuildToolsReport/BuildToolsReport_Template.html @@ -0,0 +1,126 @@ + + + + + + Build Tools Report + + + + + + +
+

Build Tools Report

+ +
+
+ + + + + + + + + +
KeyValueType
+
+
+
+
+

+

+ Build Tools Report Template Version: 1.00
+ Build Tools Report Plugin Version:
+

+

License

+
+
+

+ Copyright (c) Microsoft Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +

+
+
+
+

External Licenses

+
+
+
+
+
+ + + + + + + + + + + + diff --git a/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py new file mode 100644 index 00000000000..a4f89818394 --- /dev/null +++ b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py @@ -0,0 +1,115 @@ +# @file HostBasedUnitTestRunner.py +# Plugin to located any host-based unit tests in the output directory and execute them. +## +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +import os +import logging +import glob +import xml.etree.ElementTree +from edk2toolext.environment.plugintypes.uefi_build_plugin import IUefiBuildPlugin +from edk2toolext import edk2_logging +import edk2toollib.windows.locate_tools as locate_tools +from edk2toolext.environment import shell_environment +from edk2toollib.utility_functions import RunCmd + + +class HostBasedUnitTestRunner(IUefiBuildPlugin): + + def do_pre_build(self, thebuilder): + ''' + Works with the compiler (either the HostBasedCompilerPlugin or an other Builder) to set + up the environment that will be needed to build host-based unit tests. + + EXPECTS: + - Build Var 'CI_BUILD_TYPE' - If not set to 'host_unit_test', will not do anything. + + UPDATES: + - Shell Var (Several) - Updates the shell with all vars listed in interesting_keys. + - Shell Path - Updated from QueryVcVariables() + - Shell Var 'CMOCKA_MESSAGE_OUTPUT' + ''' + ci_type = thebuilder.env.GetValue('CI_BUILD_TYPE') + if ci_type != 'host_unit_test': + return 0 + + shell_env = shell_environment.GetEnvironment() + # Use the tools lib to determine the correct values for the vars that interest us. + interesting_keys = ["ExtensionSdkDir", "INCLUDE", "LIB", "LIBPATH", "UniversalCRTSdkDir", + "UCRTVersion", "WindowsLibPath", "WindowsSdkBinPath", "WindowsSdkDir", "WindowsSdkVerBinPath", + "WindowsSDKVersion", "VCToolsInstallDir"] + vs_vars = locate_tools.QueryVcVariables(interesting_keys, "amd64") + for (k, v) in vs_vars.items(): + if k.upper() == "PATH": + shell_env.append_path(v) + else: + shell_env.set_shell_var(k, v) + + # Set up the reporting type for Cmocka. + shell_env.set_shell_var('CMOCKA_MESSAGE_OUTPUT', 'xml') + return 0 + + def do_post_build(self, thebuilder): + ''' + After a build, will automatically locate and run all host-based unit tests. Logs any + failures with Warning severity and will return a count of the failures as the return code. + + EXPECTS: + - Build Var 'CI_BUILD_TYPE' - If not set to 'host_unit_test', will not do anything. + + UPDATES: + - Shell Var 'CMOCKA_XML_FILE' + ''' + ci_type = thebuilder.env.GetValue('CI_BUILD_TYPE') + if ci_type != 'host_unit_test': + return 0 + + shell_env = shell_environment.GetEnvironment() + logging.log(edk2_logging.get_section_level(), + "Run Host based Unit Tests") + path = thebuilder.env.GetValue("BUILD_OUTPUT_BASE") + + failure_count = 0 + + for arch in thebuilder.env.GetValue("TARGET_ARCH").split(): + logging.log(edk2_logging.get_subsection_level(), + "Testing for architecture: " + arch) + cp = os.path.join(path, arch) + + # If any old results XML files exist, clean them up. + for old_result in glob.iglob(os.path.join(cp, "*.result.xml")): + os.remove(old_result) + + # Determine whether any tests exist. + testList = glob.glob(os.path.join(cp, "*Test*.exe")) + for test in testList: + # Configure output name. + shell_env.set_shell_var( + 'CMOCKA_XML_FILE', test + ".%g." + arch + ".result.xml") + + # Run the test. + ret = RunCmd('"' + test + '"', "", workingdir=cp) + if(ret != 0): + logging.error("UnitTest Execution Error: " + + os.path.basename(test)) + else: + logging.info("UnitTest Completed: " + + os.path.basename(test)) + file_match_pattern = test + ".*." + arch + ".result.xml" + xml_results_list = glob.glob(file_match_pattern) + for xml_result_file in xml_results_list: + root = xml.etree.ElementTree.parse( + xml_result_file).getroot() + for suite in root: + for case in suite: + for result in case: + if result.tag == 'failure': + logging.warning( + "%s Test Failed" % os.path.basename(test)) + logging.warning( + " %s - %s" % (case.attrib['name'], result.text)) + failure_count += 1 + + return failure_count diff --git a/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner_plug_in.yaml b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner_plug_in.yaml new file mode 100644 index 00000000000..c25fa4746c4 --- /dev/null +++ b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner_plug_in.yaml @@ -0,0 +1,12 @@ +## +# IUefiBuildPlugin used to run any unittests that +# were built on this build. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "host-test-win", + "name": "Windows Host-Based Unit Test Runner", + "module": "HostBasedUnitTestRunner" +} diff --git a/BaseTools/Plugin/LinuxGcc5ToolChain/LinuxGcc5ToolChain.py b/BaseTools/Plugin/LinuxGcc5ToolChain/LinuxGcc5ToolChain.py new file mode 100644 index 00000000000..c31641e9314 --- /dev/null +++ b/BaseTools/Plugin/LinuxGcc5ToolChain/LinuxGcc5ToolChain.py @@ -0,0 +1,85 @@ +# @file LinuxGcc5ToolChain.py +# Plugin to configures paths for GCC5 ARM/AARCH64 Toolchain +## +# This plugin works in conjuncture with the tools_def +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import os +import logging +from edk2toolext.environment.plugintypes.uefi_build_plugin import IUefiBuildPlugin +from edk2toolext.environment import shell_environment + + +class LinuxGcc5ToolChain(IUefiBuildPlugin): + + def do_post_build(self, thebuilder): + return 0 + + def do_pre_build(self, thebuilder): + self.Logger = logging.getLogger("LinuxGcc5ToolChain") + + # + # GCC5 - The ARM and AARCH64 compilers need their paths set if available + if thebuilder.env.GetValue("TOOL_CHAIN_TAG") == "GCC5": + + # Start with AARACH64 compiler + ret = self._check_aarch64() + if ret != 0: + self.Logger.critical("Failed in check aarch64") + return ret + + # Check arm compiler + ret = self._check_arm() + if ret != 0: + self.Logger.critical("Failed in check arm") + return ret + + return 0 + + def _check_arm(self): + # check to see if full path already configured + if shell_environment.GetEnvironment().get_shell_var("GCC5_ARM_PREFIX") is not None: + self.Logger.info("GCC5_ARM_PREFIX is already set.") + + else: + # now check for install dir. If set then set the Prefix + install_path = shell_environment.GetEnvironment().get_shell_var("GCC5_ARM_INSTALL") + if install_path is None: + return 0 + + # make GCC5_ARM_PREFIX to align with tools_def.txt + prefix = os.path.join(install_path, "bin", "arm-linux-gnueabihf-") + shell_environment.GetEnvironment().set_shell_var("GCC5_ARM_PREFIX", prefix) + + # now confirm it exists + if not os.path.exists(shell_environment.GetEnvironment().get_shell_var("GCC5_ARM_PREFIX") + "gcc"): + self.Logger.error("Path for GCC5_ARM_PREFIX toolchain is invalid") + return -2 + + return 0 + + def _check_aarch64(self): + # check to see if full path already configured + if shell_environment.GetEnvironment().get_shell_var("GCC5_AARCH64_PREFIX") is not None: + self.Logger.info("GCC5_AARCH64_PREFIX is already set.") + + else: + # now check for install dir. If set then set the Prefix + install_path = shell_environment.GetEnvironment( + ).get_shell_var("GCC5_AARCH64_INSTALL") + if install_path is None: + return 0 + + # make GCC5_AARCH64_PREFIX to align with tools_def.txt + prefix = os.path.join(install_path, "bin", "aarch64-linux-gnu-") + shell_environment.GetEnvironment().set_shell_var("GCC5_AARCH64_PREFIX", prefix) + + # now confirm it exists + if not os.path.exists(shell_environment.GetEnvironment().get_shell_var("GCC5_AARCH64_PREFIX") + "gcc"): + self.Logger.error( + "Path for GCC5_AARCH64_PREFIX toolchain is invalid") + return -2 + + return 0 diff --git a/BaseTools/Plugin/LinuxGcc5ToolChain/LinuxGcc5ToolChain_plug_in.yaml b/BaseTools/Plugin/LinuxGcc5ToolChain/LinuxGcc5ToolChain_plug_in.yaml new file mode 100644 index 00000000000..39c378a926a --- /dev/null +++ b/BaseTools/Plugin/LinuxGcc5ToolChain/LinuxGcc5ToolChain_plug_in.yaml @@ -0,0 +1,12 @@ +## @file +# Build Plugin used to set the path +# for the GCC5 ARM/AARCH64 downloaded compilers +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "global-nix", + "name": "Linux GCC5 Tool Chain Support", + "module": "LinuxGcc5ToolChain" +} diff --git a/BaseTools/Plugin/WindowsResourceCompiler/WinRcPath.py b/BaseTools/Plugin/WindowsResourceCompiler/WinRcPath.py new file mode 100644 index 00000000000..ec2f2d1298f --- /dev/null +++ b/BaseTools/Plugin/WindowsResourceCompiler/WinRcPath.py @@ -0,0 +1,29 @@ +## @file WinRcPath.py +# Plugin to find Windows SDK Resource Compiler rc.exe +## +# This plugin works in conjuncture with the tools_def to support rc.exe +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import os +from edk2toolext.environment.plugintypes.uefi_build_plugin import IUefiBuildPlugin +import edk2toollib.windows.locate_tools as locate_tools +from edk2toolext.environment import shell_environment +from edk2toolext.environment import version_aggregator + +class WinRcPath(IUefiBuildPlugin): + + def do_post_build(self, thebuilder): + return 0 + + def do_pre_build(self, thebuilder): + #get the locate tools module + path = locate_tools.FindToolInWinSdk("rc.exe") + if path is None: + thebuilder.logging.warning("Failed to find rc.exe") + else: + p = os.path.abspath(os.path.dirname(path)) + shell_environment.GetEnvironment().set_shell_var("WINSDK_PATH_FOR_RC_EXE", p) + version_aggregator.GetVersionAggregator().ReportVersion("WINSDK_PATH_FOR_RC_EXE", p, version_aggregator.VersionTypes.INFO) + return 0 diff --git a/BaseTools/Plugin/WindowsResourceCompiler/WinRcPath_plug_in.yaml b/BaseTools/Plugin/WindowsResourceCompiler/WinRcPath_plug_in.yaml new file mode 100644 index 00000000000..3aec35d863a --- /dev/null +++ b/BaseTools/Plugin/WindowsResourceCompiler/WinRcPath_plug_in.yaml @@ -0,0 +1,13 @@ +## @file +# Build Plugin used to set the path to rc.exe on windows. +# The plugin is able to use python to locate the tool as to avoid +# hard-coding the path +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "global-win", + "name": "Windows RC Path Support", + "module": "WinRcPath" +} diff --git a/BaseTools/Plugin/WindowsVsToolChain/WindowsVsToolChain.py b/BaseTools/Plugin/WindowsVsToolChain/WindowsVsToolChain.py new file mode 100644 index 00000000000..a8202e5992a --- /dev/null +++ b/BaseTools/Plugin/WindowsVsToolChain/WindowsVsToolChain.py @@ -0,0 +1,126 @@ +## @file WindowsVsToolChain.py +# Plugin to configures paths for the VS2017 and VS2019 tool chain +## +# This plugin works in conjuncture with the tools_def +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import os +import logging +from edk2toolext.environment.plugintypes.uefi_build_plugin import IUefiBuildPlugin +import edk2toollib.windows.locate_tools as locate_tools +from edk2toollib.windows.locate_tools import FindWithVsWhere +from edk2toolext.environment import shell_environment +from edk2toolext.environment import version_aggregator + +class WindowsVsToolChain(IUefiBuildPlugin): + + def do_post_build(self, thebuilder): + return 0 + + def do_pre_build(self, thebuilder): + self.Logger = logging.getLogger("WindowsVsToolChain") + +# + # VS2017 - Follow VS2017 where there is potential for many versions of the tools. + # If a specific version is required then the user must set both env variables: + ## VS150INSTALLPATH: base install path on system to VC install dir. Here you will find the VC folder, etc + ## VS150TOOLVER: version number for the VC compiler tools + ## VS2017_PREFIX: path to MSVC compiler folder with trailing slash (can be used instead of two vars above) + if thebuilder.env.GetValue("TOOL_CHAIN_TAG") == "VS2017": + + # check to see if full path already configured + if shell_environment.GetEnvironment().get_shell_var("VS2017_PREFIX") != None: + self.Logger.info("VS2017_PREFIX is already set.") + + else: + install_path = self._get_vs_install_path("VS2017".lower(), "VS150INSTALLPATH") + vc_ver = self._get_vc_version(install_path, "VS150TOOLVER") + + if install_path is None or vc_ver is None: + self.Logger.error("Failed to configure environment for VS2017") + return -1 + + version_aggregator.GetVersionAggregator().ReportVersion( + "Visual Studio Install Path", install_path, version_aggregator.VersionTypes.INFO) + version_aggregator.GetVersionAggregator().ReportVersion( + "VC Version", vc_ver, version_aggregator.VersionTypes.TOOL) + + #make VS2017_PREFIX to align with tools_def.txt + prefix = os.path.join(install_path, "VC", "Tools", "MSVC", vc_ver) + prefix = prefix + os.path.sep + shell_environment.GetEnvironment().set_shell_var("VS2017_PREFIX", prefix) + + # now confirm it exists + if not os.path.exists(shell_environment.GetEnvironment().get_shell_var("VS2017_PREFIX")): + self.Logger.error("Path for VS2017 toolchain is invalid") + return -2 + + # + # VS2019 - Follow VS2019 where there is potential for many versions of the tools. + # If a specific version is required then the user must set both env variables: + ## VS160INSTALLPATH: base install path on system to VC install dir. Here you will find the VC folder, etc + ## VS160TOOLVER: version number for the VC compiler tools + ## VS2019_PREFIX: path to MSVC compiler folder with trailing slash (can be used instead of two vars above) + elif thebuilder.env.GetValue("TOOL_CHAIN_TAG") == "VS2019": + + # check to see if full path already configured + if shell_environment.GetEnvironment().get_shell_var("VS2019_PREFIX") != None: + self.Logger.info("VS2019_PREFIX is already set.") + + else: + install_path = self._get_vs_install_path("VS2019".lower(), "VS160INSTALLPATH") + vc_ver = self._get_vc_version(install_path, "VS160TOOLVER") + + if install_path is None or vc_ver is None: + self.Logger.error("Failed to configure environment for VS2019") + return -1 + + version_aggregator.GetVersionAggregator().ReportVersion( + "Visual Studio Install Path", install_path, version_aggregator.VersionTypes.INFO) + version_aggregator.GetVersionAggregator().ReportVersion( + "VC Version", vc_ver, version_aggregator.VersionTypes.TOOL) + + #make VS2019_PREFIX to align with tools_def.txt + prefix = os.path.join(install_path, "VC", "Tools", "MSVC", vc_ver) + prefix = prefix + os.path.sep + shell_environment.GetEnvironment().set_shell_var("VS2019_PREFIX", prefix) + + # now confirm it exists + if not os.path.exists(shell_environment.GetEnvironment().get_shell_var("VS2019_PREFIX")): + self.Logger.error("Path for VS2019 toolchain is invalid") + return -2 + + return 0 + + def _get_vs_install_path(self, vs_version, varname): + # check if already specified + path = shell_environment.GetEnvironment().get_shell_var(varname) + if(path is None): + # Not specified...find latest + (rc, path) = FindWithVsWhere(vs_version=vs_version) + if rc == 0 and path is not None and os.path.exists(path): + self.Logger.debug("Found VS instance for %s", vs_version) + else: + self.Logger.error("Failed to find VS instance with VsWhere (%d)" % rc) + return path + + def _get_vc_version(self, path, varname): + # check if already specified + vc_ver = shell_environment.GetEnvironment().get_shell_var(varname) + if (path is None): + self.Logger.critical("Failed to find Visual Studio tools. Might need to check for VS install") + return vc_ver + if(vc_ver is None): + # Not specified...find latest + p2 = os.path.join(path, "VC", "Tools", "MSVC") + if not os.path.isdir(p2): + self.Logger.critical( + "Failed to find VC tools. Might need to check for VS install") + return vc_ver + vc_ver = os.listdir(p2)[-1].strip() # get last in list + self.Logger.debug("Found VC Tool version is %s" % vc_ver) + return vc_ver + + diff --git a/BaseTools/Plugin/WindowsVsToolChain/WindowsVsToolChain_plug_in.yaml b/BaseTools/Plugin/WindowsVsToolChain/WindowsVsToolChain_plug_in.yaml new file mode 100644 index 00000000000..72b5c4a0926 --- /dev/null +++ b/BaseTools/Plugin/WindowsVsToolChain/WindowsVsToolChain_plug_in.yaml @@ -0,0 +1,11 @@ +## @file +# Build Plugin used to set the path to the visual studio tools chain +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "global-win", + "name": "Windows Visual Studio Tool Chain Support", + "module": "WindowsVsToolChain" +} diff --git a/BaseTools/Scripts/PatchCheck.py b/BaseTools/Scripts/PatchCheck.py index 2a4e6f603e7..173d4517e0a 100755 --- a/BaseTools/Scripts/PatchCheck.py +++ b/BaseTools/Scripts/PatchCheck.py @@ -1,7 +1,8 @@ ## @file # Check a patch for various format issues # -# Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
+# Copyright (C) 2020, Red Hat, Inc.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -22,6 +23,62 @@ class Verbose: SILENT, ONELINE, NORMAL = range(3) level = NORMAL +class EmailAddressCheck: + """Checks an email address.""" + + def __init__(self, email, description): + self.ok = True + + if email is None: + self.error('Email address is missing!') + return + if description is None: + self.error('Email description is missing!') + return + + self.description = "'" + description + "'" + self.check_email_address(email) + + def error(self, *err): + if self.ok and Verbose.level > Verbose.ONELINE: + print('The ' + self.description + ' email address is not valid:') + self.ok = False + if Verbose.level < Verbose.NORMAL: + return + count = 0 + for line in err: + prefix = (' *', ' ')[count > 0] + print(prefix, line) + count += 1 + + email_re1 = re.compile(r'(?:\s*)(.*?)(\s*)<(.+)>\s*$', + re.MULTILINE|re.IGNORECASE) + + def check_email_address(self, email): + email = email.strip() + mo = self.email_re1.match(email) + if mo is None: + self.error("Email format is invalid: " + email.strip()) + return + + name = mo.group(1).strip() + if name == '': + self.error("Name is not provided with email address: " + + email) + else: + quoted = len(name) > 2 and name[0] == '"' and name[-1] == '"' + if name.find(',') >= 0 and not quoted: + self.error('Add quotes (") around name with a comma: ' + + name) + + if mo.group(2) == '': + self.error("There should be a space between the name and " + + "email address: " + email) + + if mo.group(3).find(' ') >= 0: + self.error("The email address cannot contain a space: " + + mo.group(3)) + class CommitMessageCheck: """Checks the contents of a git commit message.""" @@ -35,6 +92,8 @@ def __init__(self, subject, message): self.subject = subject self.msg = message + print (subject) + self.check_contributed_under() self.check_signed_off_by() self.check_misc_signatures() @@ -121,38 +180,10 @@ def find_signatures(self, sig): if s[2] != ' ': self.error("There should be a space after '" + sig + ":'") - self.check_email_address(s[3]) + EmailAddressCheck(s[3], sig) return sigs - email_re1 = re.compile(r'(?:\s*)(.*?)(\s*)<(.+)>\s*$', - re.MULTILINE|re.IGNORECASE) - - def check_email_address(self, email): - email = email.strip() - mo = self.email_re1.match(email) - if mo is None: - self.error("Email format is invalid: " + email.strip()) - return - - name = mo.group(1).strip() - if name == '': - self.error("Name is not provided with email address: " + - email) - else: - quoted = len(name) > 2 and name[0] == '"' and name[-1] == '"' - if name.find(',') >= 0 and not quoted: - self.error('Add quotes (") around name with a comma: ' + - name) - - if mo.group(2) == '': - self.error("There should be a space between the name and " + - "email address: " + email) - - if mo.group(3).find(' ') >= 0: - self.error("The email address cannot contain a space: " + - mo.group(3)) - def check_signed_off_by(self): sob='Signed-off-by' if self.msg.find(sob) < 0: @@ -179,6 +210,8 @@ def check_misc_signatures(self): for sig in self.sig_types: self.find_signatures(sig) + cve_re = re.compile('CVE-[0-9]{4}-[0-9]{5}[^0-9]') + def check_overall_format(self): lines = self.msg.splitlines() @@ -196,9 +229,26 @@ def check_overall_format(self): self.error('Empty commit message!') return - if count >= 1 and len(lines[0]) >= 72: - self.error('First line of commit message (subject line) ' + - 'is too long.') + if count >= 1 and re.search(self.cve_re, lines[0]): + # + # If CVE-xxxx-xxxxx is present in subject line, then limit length of + # subject line to 92 characters + # + if len(lines[0].rstrip()) >= 93: + self.error( + 'First line of commit message (subject line) is too long (%d >= 93).' % + (len(lines[0].rstrip())) + ) + else: + # + # If CVE-xxxx-xxxxx is not present in subject line, then limit + # length of subject line to 75 characters + # + if len(lines[0].rstrip()) >= 76: + self.error( + 'First line of commit message (subject line) is too long (%d >= 76).' % + (len(lines[0].rstrip())) + ) if count >= 1 and len(lines[0].strip()) == 0: self.error('First line of commit message (subject line) ' + @@ -212,7 +262,14 @@ def check_overall_format(self): if (len(lines[i]) >= 76 and len(lines[i].split()) > 1 and not lines[i].startswith('git-svn-id:')): - self.error('Line %d of commit message is too long.' % (i + 1)) + # + # Print a warning if body line is longer than 75 characters + # + print( + 'WARNING - Line %d of commit message is too long (%d >= 76).' % + (i + 1, len(lines[i])) + ) + print(lines[i]) last_sig_line = None for i in range(count - 1, 0, -1): @@ -422,6 +479,9 @@ def __init__(self, name, patch): self.patch = patch self.find_patch_pieces() + email_check = EmailAddressCheck(self.author_email, 'Author') + email_ok = email_check.ok + msg_check = CommitMessageCheck(self.commit_subject, self.commit_msg) msg_ok = msg_check.ok @@ -430,7 +490,7 @@ def __init__(self, name, patch): diff_check = GitDiffCheck(self.diff) diff_ok = diff_check.ok - self.ok = msg_ok and diff_ok + self.ok = email_ok and msg_ok and diff_ok if Verbose.level == Verbose.ONELINE: if self.ok: @@ -503,11 +563,30 @@ def find_patch_pieces(self): else: self.stat = mo.group('stat') self.commit_msg = mo.group('commit_message') + # + # Parse subject line from email header. The subject line may be + # composed of multiple parts with different encodings. Decode and + # combine all the parts to produce a single string with the contents of + # the decoded subject line. + # + parts = email.header.decode_header(pmail.get('subject')) + subject = '' + for (part, encoding) in parts: + if encoding: + part = part.decode(encoding) + else: + try: + part = part.decode() + except: + pass + subject = subject + part - self.commit_subject = pmail['subject'].replace('\r\n', '') + self.commit_subject = subject.replace('\r\n', '') self.commit_subject = self.commit_subject.replace('\n', '') self.commit_subject = self.subject_prefix_re.sub('', self.commit_subject, 1) + self.author_email = pmail['from'] + class CheckGitCommits: """Reads patches from git based on the specified git revision range. @@ -527,6 +606,8 @@ def __init__(self, rev_spec, max_count): else: blank_line = True print('Checking git commit:', commit) + email = self.read_committer_email_address_from_git(commit) + self.ok &= EmailAddressCheck(email, 'Committer').ok patch = self.read_patch_from_git(commit) self.ok &= CheckOnePatch(commit, patch).ok if not commits: @@ -545,6 +626,10 @@ def read_patch_from_git(self, commit): # Run git to get the commit patch return self.run_git('show', '--pretty=email', '--no-textconv', commit) + def read_committer_email_address_from_git(self, commit): + # Run git to get the committer email + return self.run_git('show', '--pretty=%cn <%ce>', '--no-patch', commit) + def run_git(self, *args): cmd = [ 'git' ] cmd += args diff --git a/BaseTools/Scripts/SetupGit.py b/BaseTools/Scripts/SetupGit.py index 3d39d3b35fd..514f1c4d42d 100644 --- a/BaseTools/Scripts/SetupGit.py +++ b/BaseTools/Scripts/SetupGit.py @@ -2,6 +2,7 @@ # Set up the git configuration for contributing to TianoCore projects # # Copyright (c) 2019, Linaro Ltd. All rights reserved.
+# Copyright (c) 2019, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -53,29 +54,30 @@ # Set of options to be set identically for all repositories OPTIONS = [ - {'section': 'am', 'option': 'keepcr', 'value': True}, - {'section': 'am', 'option': 'signoff', 'value': True}, - {'section': 'cherry-pick', 'option': 'signoff', 'value': True}, - {'section': 'color', 'option': 'diff', 'value': True}, - {'section': 'color', 'option': 'grep', 'value': 'auto'}, - {'section': 'commit', 'option': 'signoff', 'value': True}, - {'section': 'core', 'option': 'abbrev', 'value': 12}, + {'section': 'am', 'option': 'keepcr', 'value': True}, + {'section': 'am', 'option': 'signoff', 'value': True}, + {'section': 'cherry-pick', 'option': 'signoff', 'value': True}, + {'section': 'color', 'option': 'diff', 'value': True}, + {'section': 'color', 'option': 'grep', 'value': 'auto'}, + {'section': 'commit', 'option': 'signoff', 'value': True}, + {'section': 'core', 'option': 'abbrev', 'value': 12}, {'section': 'core', 'option': 'attributesFile', 'value': os.path.join(CONFDIR, 'gitattributes').replace('\\', '/')}, - {'section': 'core', 'option': 'whitespace', 'value': 'cr-at-eol'}, - {'section': 'diff', 'option': 'algorithm', 'value': 'patience'}, + {'section': 'core', 'option': 'whitespace', 'value': 'cr-at-eol'}, + {'section': 'diff', 'option': 'algorithm', 'value': 'patience'}, {'section': 'diff', 'option': 'orderFile', 'value': os.path.join(CONFDIR, 'diff.order').replace('\\', '/')}, - {'section': 'diff', 'option': 'renames', 'value': 'copies'}, - {'section': 'diff', 'option': 'statGraphWidth', 'value': '20'}, - {'section': 'diff "ini"', 'option': 'xfuncname', + {'section': 'diff', 'option': 'renames', 'value': 'copies'}, + {'section': 'diff', 'option': 'statGraphWidth', 'value': '20'}, + {'section': 'diff "ini"', 'option': 'xfuncname', 'value': '^\\\\[[A-Za-z0-9_., ]+]'}, - {'section': 'format', 'option': 'coverLetter', 'value': True}, - {'section': 'format', 'option': 'numbered', 'value': True}, - {'section': 'format', 'option': 'signoff', 'value': False}, - {'section': 'notes', 'option': 'rewriteRef', 'value': 'refs/notes/commits'}, - {'section': 'sendemail', 'option': 'chainreplyto', 'value': False}, - {'section': 'sendemail', 'option': 'thread', 'value': True}, + {'section': 'format', 'option': 'coverLetter', 'value': True}, + {'section': 'format', 'option': 'numbered', 'value': True}, + {'section': 'format', 'option': 'signoff', 'value': False}, + {'section': 'notes', 'option': 'rewriteRef', 'value': 'refs/notes/commits'}, + {'section': 'sendemail', 'option': 'chainreplyto', 'value': False}, + {'section': 'sendemail', 'option': 'thread', 'value': True}, + {'section': 'sendemail', 'option': 'transferEncoding', 'value': '8bit'}, ] diff --git a/BaseTools/Source/C/GenFv/GenFvInternalLib.c b/BaseTools/Source/C/GenFv/GenFvInternalLib.c index 908740de505..daebfe894c7 100644 --- a/BaseTools/Source/C/GenFv/GenFvInternalLib.c +++ b/BaseTools/Source/C/GenFv/GenFvInternalLib.c @@ -791,6 +791,7 @@ Routine Description: FILE *PeMapFile; CHAR8 Line [MAX_LINE_LEN]; CHAR8 KeyWord [MAX_LINE_LEN]; + CHAR8 KeyWord2 [MAX_LINE_LEN]; CHAR8 FunctionName [MAX_LINE_LEN]; EFI_PHYSICAL_ADDRESS FunctionAddress; UINT32 FunctionType; @@ -805,6 +806,7 @@ Routine Description: UINT32 TextVirtualAddress; UINT32 DataVirtualAddress; EFI_PHYSICAL_ADDRESS LinkTimeBaseAddress; + BOOLEAN IsUseClang; // // Init local variable @@ -932,6 +934,7 @@ Routine Description: // Output Functions information into Fv Map file // LinkTimeBaseAddress = 0; + IsUseClang = FALSE; while (fgets (Line, MAX_LINE_LEN, PeMapFile) != NULL) { // // Skip blank line @@ -946,6 +949,12 @@ Routine Description: if (FunctionType == 0) { sscanf (Line, "%s", KeyWord); if (stricmp (KeyWord, "Address") == 0) { + sscanf (Line, "%s %s", KeyWord, KeyWord2); + if (stricmp (KeyWord2, "Size") == 0) { + IsUseClang = TRUE; + FunctionType = 1; + continue; + } // // function list // @@ -967,11 +976,20 @@ Routine Description: // Printf Function Information // if (FunctionType == 1) { - sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName); - FunctionAddress = (UINT64) TempLongAddress; - if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) { - fprintf (FvMapFile, " 0x%010llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress)); - fprintf (FvMapFile, "%s\n", FunctionName); + if (IsUseClang) { + sscanf (Line, "%llx %s %s %s", &TempLongAddress, KeyWord, KeyWord2, FunctionTypeName); + FunctionAddress = (UINT64) TempLongAddress; + if (FunctionTypeName [0] == '_' ) { + fprintf (FvMapFile, " 0x%010llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress)); + fprintf (FvMapFile, "%s\n", FunctionTypeName); + } + } else { + sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName); + FunctionAddress = (UINT64) TempLongAddress; + if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) { + fprintf (FvMapFile, " 0x%010llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress)); + fprintf (FvMapFile, "%s\n", FunctionName); + } } } else if (FunctionType == 2) { sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName); diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c index d574300ac4f..d623dce1f9d 100644 --- a/BaseTools/Source/C/GenFw/Elf64Convert.c +++ b/BaseTools/Source/C/GenFw/Elf64Convert.c @@ -1044,6 +1044,19 @@ WriteSections64 ( /* fall through */ case R_AARCH64_ADR_PREL_PG_HI21: + // + // In order to handle Cortex-A53 erratum #843419, the LD linker may + // convert ADRP instructions into ADR instructions, but without + // updating the static relocation type, and so we may end up here + // while the instruction in question is actually ADR. So let's + // just disregard it: the section offset check we apply below to + // ADR instructions will trigger for its R_AARCH64_xxx_ABS_LO12_NC + // companion instruction as well, so it is safe to omit it here. + // + if ((*(UINT32 *)Targ & BIT31) == 0) { + break; + } + // // AArch64 PG_H21 relocations are typically paired with ABS_LO12 // relocations, where a PC-relative reference with +/- 4 GB range is diff --git a/BaseTools/Source/C/Makefiles/NmakeSubdirs.py b/BaseTools/Source/C/Makefiles/NmakeSubdirs.py index 356f5aca638..9b699ea086e 100644 --- a/BaseTools/Source/C/Makefiles/NmakeSubdirs.py +++ b/BaseTools/Source/C/Makefiles/NmakeSubdirs.py @@ -38,7 +38,7 @@ def RunCommand(WorkDir=None, *Args, **kwargs): stdout, stderr = p.communicate() message = "" if stdout is not None: - message = stdout.decode(encoding='utf-8', errors='ignore') #for compatibility in python 2 and 3 + message = stdout.decode(errors='ignore') #for compatibility in python 2 and 3 if p.returncode != 0: raise RuntimeError("Error while execute command \'{0}\' in direcotry {1}\n{2}".format(" ".join(Args), WorkDir, message)) diff --git a/BaseTools/Source/Python/AutoGen/AutoGenWorker.py b/BaseTools/Source/Python/AutoGen/AutoGenWorker.py index 94ea61a4870..40b448f5b2d 100755 --- a/BaseTools/Source/Python/AutoGen/AutoGenWorker.py +++ b/BaseTools/Source/Python/AutoGen/AutoGenWorker.py @@ -128,12 +128,27 @@ def clearQueue(self): clearQ(taskq) clearQ(self.feedback_q) clearQ(logq) + # Copy the cache queue itmes to parent thread before clear + cacheq = self.autogen_workers[0].cache_q + try: + cache_num = 0 + while True: + item = cacheq.get() + if item == "CacheDone": + cache_num += 1 + else: + GlobalData.gModuleAllCacheStatus.add(item) + if cache_num == len(self.autogen_workers): + break + except: + print ("cache_q error") + def TerminateWorkers(self): self.error_event.set() def kill(self): self.feedback_q.put(None) class AutoGenWorkerInProcess(mp.Process): - def __init__(self,module_queue,data_pipe_file_path,feedback_q,file_lock,cache_lock,share_data,log_q,error_event): + def __init__(self,module_queue,data_pipe_file_path,feedback_q,file_lock,cache_q,log_q,error_event): mp.Process.__init__(self) self.module_queue = module_queue self.data_pipe_file_path =data_pipe_file_path @@ -141,8 +156,7 @@ def __init__(self,module_queue,data_pipe_file_path,feedback_q,file_lock,cache_lo self.feedback_q = feedback_q self.PlatformMetaFileSet = {} self.file_lock = file_lock - self.cache_lock = cache_lock - self.share_data = share_data + self.cache_q = cache_q self.log_q = log_q self.error_event = error_event def GetPlatformMetaFile(self,filepath,root): @@ -184,12 +198,19 @@ def run(self): GlobalData.gDisableIncludePathCheck = False GlobalData.gFdfParser = self.data_pipe.Get("FdfParser") GlobalData.gDatabasePath = self.data_pipe.Get("DatabasePath") + + GlobalData.gUseHashCache = self.data_pipe.Get("UseHashCache") GlobalData.gBinCacheSource = self.data_pipe.Get("BinCacheSource") GlobalData.gBinCacheDest = self.data_pipe.Get("BinCacheDest") - GlobalData.gCacheIR = self.share_data + GlobalData.gPlatformHashFile = self.data_pipe.Get("PlatformHashFile") + GlobalData.gModulePreMakeCacheStatus = dict() + GlobalData.gModuleMakeCacheStatus = dict() + GlobalData.gHashChainStatus = dict() + GlobalData.gCMakeHashFile = dict() + GlobalData.gModuleHashFile = dict() + GlobalData.gFileHashDict = dict() GlobalData.gEnableGenfdsMultiThread = self.data_pipe.Get("EnableGenfdsMultiThread") GlobalData.file_lock = self.file_lock - GlobalData.cache_lock = self.cache_lock CommandTarget = self.data_pipe.Get("CommandTarget") pcd_from_build_option = [] for pcd_tuple in self.data_pipe.Get("BuildOptPcd"): @@ -205,10 +226,6 @@ def run(self): GlobalData.FfsCmd = FfsCmd PlatformMetaFile = self.GetPlatformMetaFile(self.data_pipe.Get("P_Info").get("ActivePlatform"), self.data_pipe.Get("P_Info").get("WorkspaceDir")) - libConstPcd = self.data_pipe.Get("LibConstPcd") - Refes = self.data_pipe.Get("REFS") - GlobalData.libConstPcd = libConstPcd - GlobalData.Refes = Refes while True: if self.module_queue.empty(): break @@ -230,27 +247,41 @@ def run(self): toolchain = self.data_pipe.Get("P_Info").get("ToolChain") Ma = ModuleAutoGen(self.Wa,module_metafile,target,toolchain,arch,PlatformMetaFile,self.data_pipe) Ma.IsLibrary = IsLib - if IsLib: - if (Ma.MetaFile.File,Ma.MetaFile.Root,Ma.Arch,Ma.MetaFile.Path) in libConstPcd: - Ma.ConstPcd = libConstPcd[(Ma.MetaFile.File,Ma.MetaFile.Root,Ma.Arch,Ma.MetaFile.Path)] - if (Ma.MetaFile.File,Ma.MetaFile.Root,Ma.Arch,Ma.MetaFile.Path) in Refes: - Ma.ReferenceModules = Refes[(Ma.MetaFile.File,Ma.MetaFile.Root,Ma.Arch,Ma.MetaFile.Path)] - if GlobalData.gBinCacheSource and CommandTarget in [None, "", "all"]: - Ma.GenModuleFilesHash(GlobalData.gCacheIR) - Ma.GenPreMakefileHash(GlobalData.gCacheIR) - if Ma.CanSkipbyPreMakefileCache(GlobalData.gCacheIR): + # SourceFileList calling sequence impact the makefile string sequence. + # Create cached SourceFileList here to unify its calling sequence for both + # CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile. + RetVal = Ma.SourceFileList + if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and CommandTarget in [None, "", "all"]: + try: + CacheResult = Ma.CanSkipbyPreMakeCache() + except: + CacheResult = False + traceback.print_exc(file=sys.stdout) + self.feedback_q.put(taskname) + + if CacheResult: + self.cache_q.put((Ma.MetaFile.Path, Ma.Arch, "PreMakeCache", True)) continue + else: + self.cache_q.put((Ma.MetaFile.Path, Ma.Arch, "PreMakeCache", False)) Ma.CreateCodeFile(False) Ma.CreateMakeFile(False,GenFfsList=FfsCmd.get((Ma.MetaFile.Path, Ma.Arch),[])) if GlobalData.gBinCacheSource and CommandTarget in [None, "", "all"]: - Ma.GenMakeHeaderFilesHash(GlobalData.gCacheIR) - Ma.GenMakeHash(GlobalData.gCacheIR) - if Ma.CanSkipbyMakeCache(GlobalData.gCacheIR): + try: + CacheResult = Ma.CanSkipbyMakeCache() + except: + CacheResult = False + traceback.print_exc(file=sys.stdout) + self.feedback_q.put(taskname) + + if CacheResult: + self.cache_q.put((Ma.MetaFile.Path, Ma.Arch, "MakeCache", True)) continue else: - Ma.PrintFirstMakeCacheMissFile(GlobalData.gCacheIR) + self.cache_q.put((Ma.MetaFile.Path, Ma.Arch, "MakeCache", False)) + except Empty: pass except: @@ -258,6 +289,8 @@ def run(self): self.feedback_q.put(taskname) finally: self.feedback_q.put("Done") + self.cache_q.put("CacheDone") + def printStatus(self): print("Processs ID: %d Run %d modules in AutoGen " % (os.getpid(),len(AutoGen.Cache()))) print("Processs ID: %d Run %d modules in AutoGenInfo " % (os.getpid(),len(AutoGenInfo.GetCache()))) diff --git a/BaseTools/Source/Python/AutoGen/BuildEngine.py b/BaseTools/Source/Python/AutoGen/BuildEngine.py index 069a3a1c9db..d602414ca41 100644 --- a/BaseTools/Source/Python/AutoGen/BuildEngine.py +++ b/BaseTools/Source/Python/AutoGen/BuildEngine.py @@ -20,7 +20,7 @@ from Common.Misc import tdict, PathClass from Common.StringUtils import NormPath from Common.DataType import * -from Common.TargetTxtClassObject import TargetTxt +from Common.TargetTxtClassObject import TargetTxtDict gDefaultBuildRuleFile = 'build_rule.txt' AutoGenReqBuildRuleVerNum = '0.1' @@ -588,24 +588,42 @@ def __getitem__(self, Key): _UnknownSection : SkipSection, } -def GetBuildRule(): - BuildRuleFile = None - if TAB_TAT_DEFINES_BUILD_RULE_CONF in TargetTxt.TargetTxtDictionary: - BuildRuleFile = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF] - if not BuildRuleFile: - BuildRuleFile = gDefaultBuildRuleFile - RetVal = BuildRule(BuildRuleFile) - if RetVal._FileVersion == "": - RetVal._FileVersion = AutoGenReqBuildRuleVerNum - else: - if RetVal._FileVersion < AutoGenReqBuildRuleVerNum : - # If Build Rule's version is less than the version number required by the tools, halting the build. - EdkLogger.error("build", AUTOGEN_ERROR, - ExtraData="The version number [%s] of build_rule.txt is less than the version number required by the AutoGen.(the minimum required version number is [%s])"\ - % (RetVal._FileVersion, AutoGenReqBuildRuleVerNum)) - return RetVal - -BuildRuleObj = GetBuildRule() +class ToolBuildRule(): + + def __new__(cls, *args, **kw): + if not hasattr(cls, '_instance'): + orig = super(ToolBuildRule, cls) + cls._instance = orig.__new__(cls, *args, **kw) + return cls._instance + + def __init__(self): + if not hasattr(self, 'ToolBuildRule'): + self._ToolBuildRule = None + + @property + def ToolBuildRule(self): + if not self._ToolBuildRule: + self._GetBuildRule() + return self._ToolBuildRule + + def _GetBuildRule(self): + BuildRuleFile = None + TargetObj = TargetTxtDict() + TargetTxt = TargetObj.Target + if TAB_TAT_DEFINES_BUILD_RULE_CONF in TargetTxt.TargetTxtDictionary: + BuildRuleFile = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF] + if not BuildRuleFile: + BuildRuleFile = gDefaultBuildRuleFile + RetVal = BuildRule(BuildRuleFile) + if RetVal._FileVersion == "": + RetVal._FileVersion = AutoGenReqBuildRuleVerNum + else: + if RetVal._FileVersion < AutoGenReqBuildRuleVerNum : + # If Build Rule's version is less than the version number required by the tools, halting the build. + EdkLogger.error("build", AUTOGEN_ERROR, + ExtraData="The version number [%s] of build_rule.txt is less than the version number required by the AutoGen.(the minimum required version number is [%s])"\ + % (RetVal._FileVersion, AutoGenReqBuildRuleVerNum)) + self._ToolBuildRule = RetVal # This acts like the main() function for the script, unless it is 'import'ed into another # script. diff --git a/BaseTools/Source/Python/AutoGen/CacheIR.py b/BaseTools/Source/Python/AutoGen/CacheIR.py deleted file mode 100755 index 715be5273c1..00000000000 --- a/BaseTools/Source/Python/AutoGen/CacheIR.py +++ /dev/null @@ -1,29 +0,0 @@ -## @file -# Build cache intermediate result and state -# -# Copyright (c) 2019, Intel Corporation. All rights reserved.
-# SPDX-License-Identifier: BSD-2-Clause-Patent -# - -class ModuleBuildCacheIR(): - def __init__(self, Path, Arch): - self.ModulePath = Path - self.ModuleArch = Arch - self.ModuleFilesHashDigest = None - self.ModuleFilesHashHexDigest = None - self.ModuleFilesChain = [] - self.PreMakefileHashHexDigest = None - self.CreateCodeFileDone = False - self.CreateMakeFileDone = False - self.MakefilePath = None - self.AutoGenFileList = None - self.DependencyHeaderFileSet = None - self.MakeHeaderFilesHashChain = None - self.MakeHeaderFilesHashDigest = None - self.MakeHeaderFilesHashChain = [] - self.MakeHashDigest = None - self.MakeHashHexDigest = None - self.MakeHashChain = [] - self.CacheCrash = False - self.PreMakeCacheHit = False - self.MakeCacheHit = False diff --git a/BaseTools/Source/Python/AutoGen/DataPipe.py b/BaseTools/Source/Python/AutoGen/DataPipe.py index 078bafecb45..50403fbfb56 100755 --- a/BaseTools/Source/Python/AutoGen/DataPipe.py +++ b/BaseTools/Source/Python/AutoGen/DataPipe.py @@ -159,6 +159,8 @@ def FillData(self,PlatformInfo): self.DataContainer = {"LogLevel": EdkLogger.GetLevel()} + self.DataContainer = {"UseHashCache":GlobalData.gUseHashCache} + self.DataContainer = {"BinCacheSource":GlobalData.gBinCacheSource} self.DataContainer = {"BinCacheDest":GlobalData.gBinCacheDest} diff --git a/BaseTools/Source/Python/AutoGen/GenMake.py b/BaseTools/Source/Python/AutoGen/GenMake.py index 59a01a7f243..fe94f9a4c23 100755 --- a/BaseTools/Source/Python/AutoGen/GenMake.py +++ b/BaseTools/Source/Python/AutoGen/GenMake.py @@ -185,6 +185,12 @@ def Generate(self, FileType=gMakeType): self._FileType = FileType FileContent = self._TEMPLATE_.Replace(self._TemplateDict) FileName = self._FILE_NAME_[FileType] + if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "deps.txt")): + with open(os.path.join(self._AutoGenObject.MakeFileDir, "deps.txt"),"w+") as fd: + fd.write("") + if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "dependency")): + with open(os.path.join(self._AutoGenObject.MakeFileDir, "dependency"),"w+") as fd: + fd.write("") return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False) ## Return a list of directory creation command string @@ -304,9 +310,6 @@ class ModuleMakefile(BuildFile): ${BEGIN}${file_macro} ${END} -COMMON_DEPS = ${BEGIN}${common_dependency_file} \\ - ${END} - # # Overridable Target Macro Definitions # @@ -382,6 +385,8 @@ class ModuleMakefile(BuildFile): \t@"$(MAKE)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds \t@cd $(MODULE_BUILD_DIR) +${INCLUDETAG} + # # Individual Object Build Targets # @@ -515,9 +520,6 @@ def _TemplateDict(self): # Remove duplicated include path, if any if Attr == "FLAGS": Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList) - if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Tool == 'CC' and '/GM' in Value: - Value = Value.replace(' /MP', '') - MyAgo.BuildOption[Tool][Attr] = Value if Tool == "OPTROM" and PCI_COMPRESS_Flag: ValueList = Value.split() if ValueList: @@ -540,7 +542,7 @@ def _TemplateDict(self): UnexpandMacro = [] NewStr = [] for Str in StrList: - if '$' in Str: + if '$' in Str or '-MMD' in Str or '-MF' in Str: UnexpandMacro.append(Str) else: NewStr.append(Str) @@ -590,10 +592,9 @@ def _TemplateDict(self): ) FileMacroList.append(FileMacro) # Add support when compiling .nasm source files - for File in self.FileCache.keys(): - if not str(File).endswith('.nasm'): - continue - IncludePathList = [] + IncludePathList = [] + asmsource = [item for item in MyAgo.SourceFileList if item.File.upper().endswith((".NASM",".ASM",".NASMB","S"))] + if asmsource: for P in MyAgo.IncludePathList: IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros) if IncludePath.endswith(os.sep): @@ -606,7 +607,6 @@ def _TemplateDict(self): IncludePath = os.path.join(IncludePath, '') IncludePathList.append(IncludePath) FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name": "NASM_INC", "source_file": IncludePathList})) - break # Generate macros used to represent files containing list of input files for ListFileMacro in self.ListFileMacros: @@ -696,6 +696,7 @@ def _TemplateDict(self): "file_macro" : FileMacroList, "file_build_target" : self.BuildTargetList, "backward_compatible_target": BcTargetList, + "INCLUDETAG" : self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$(MODULE_BUILD_DIR)","dependency") } return MakefileTemplateDict @@ -903,16 +904,10 @@ def ProcessBuildTargetList(self): if Item in SourceFileList: SourceFileList.remove(Item) - FileDependencyDict = self.GetFileDependency( - SourceFileList, - ForceIncludedFile, - self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList - ) - + FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList} - if FileDependencyDict: - for Dependency in FileDependencyDict.values(): - self.DependencyHeaderFileSet.update(set(Dependency)) + for Dependency in FileDependencyDict.values(): + self.DependencyHeaderFileSet.update(set(Dependency)) # Get a set of unique package includes from MetaFile parentMetaFileIncludes = set() @@ -972,42 +967,16 @@ def ProcessBuildTargetList(self): ExtraData = "Local Header: " + aFile + " not found in " + self._AutoGenObject.MetaFile.Path ) - DepSet = None for File,Dependency in FileDependencyDict.items(): if not Dependency: - FileDependencyDict[File] = ['$(FORCE_REBUILD)'] continue self._AutoGenObject.AutoGenDepSet |= set(Dependency) - # skip non-C files - if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c": - continue - elif DepSet is None: - DepSet = set(Dependency) - else: - DepSet &= set(Dependency) - # in case nothing in SourceFileList - if DepSet is None: - DepSet = set() - # - # Extract common files list in the dependency files - # - for File in DepSet: - self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros)) - CmdSumDict = {} CmdTargetDict = {} CmdCppDict = {} DependencyDict = FileDependencyDict.copy() - for File in FileDependencyDict: - # skip non-C files - if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c": - continue - NewDepSet = set(FileDependencyDict[File]) - NewDepSet -= DepSet - FileDependencyDict[File] = ["$(COMMON_DEPS)"] + list(NewDepSet) - DependencyDict[File] = list(NewDepSet) # Convert target description object to target string in makefile if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets: @@ -1080,17 +1049,13 @@ def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, Depend else: CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path] if CppPath.Path in DependencyDict: - if '$(FORCE_REBUILD)' in DependencyDict[CppPath.Path]: - if '$(FORCE_REBUILD)' not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]): - CmdCppDict[item.Target.SubDir].append('$(FORCE_REBUILD)') - else: - for Temp in DependencyDict[CppPath.Path]: - try: - Path = self.PlaceMacro(Temp.Path, self.Macros) - except: - continue - if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]): - CmdCppDict[item.Target.SubDir].append(Path) + for Temp in DependencyDict[CppPath.Path]: + try: + Path = self.PlaceMacro(Temp.Path, self.Macros) + except: + continue + if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]): + CmdCppDict[item.Target.SubDir].append(Path) if T.Commands: CommandList = T.Commands[:] for Item in CommandList[:]: @@ -1109,7 +1074,7 @@ def ParserCCodeFile(self, T, Type, CmdSumDict, CmdTargetDict, CmdCppDict, Depend CommandList.pop(Index) if SingleCommandList[-1].endswith("%s%s.c" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])): Cpplist = CmdCppDict[T.Target.SubDir] - Cpplist.insert(0, '$(OBJLIST_%d): $(COMMON_DEPS)' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir)) + Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir)) T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign]) else: T.Commands.pop(Index) diff --git a/BaseTools/Source/Python/AutoGen/IncludesAutoGen.py b/BaseTools/Source/Python/AutoGen/IncludesAutoGen.py new file mode 100644 index 00000000000..bb6e883d84c --- /dev/null +++ b/BaseTools/Source/Python/AutoGen/IncludesAutoGen.py @@ -0,0 +1,284 @@ +## @file +# Build cache intermediate result and state +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +from Common.caching import cached_property +import Common.EdkLogger as EdkLogger +import Common.LongFilePathOs as os +from Common.BuildToolError import * +from Common.Misc import SaveFileOnChange, PathClass +from Common.Misc import TemplateString +import sys +gIsFileMap = {} +if sys.platform == "win32": + _INCLUDE_DEPS_TEMPLATE = TemplateString(''' +${BEGIN} +!IF EXIST(${deps_file}) +!INCLUDE ${deps_file} +!ENDIF +${END} + ''') +else: + _INCLUDE_DEPS_TEMPLATE = TemplateString(''' +${BEGIN} +-include ${deps_file} +${END} + ''') + +DEP_FILE_TAIL = "# Updated \n" + +class IncludesAutoGen(): + """ This class is to manage the dependent files witch are used in Makefile to support incremental build. + 1. C files: + 1. MSVS. + cl.exe has a build option /showIncludes to display include files on stdout. Build tool captures + that messages and generate dependency files, .deps files. + 2. CLANG and GCC + -MMD -MF build option are used to generate dependency files by compiler. Build tool updates the + .deps files. + 2. ASL files: + 1. Trim find out all the included files with asl specific include format and generate .trim.deps file. + 2. ASL PP use c preprocessor to find out all included files with #include format and generate a .deps file + 3. build tool updates the .deps file + 3. ASM files (.asm, .s or .nasm): + 1. Trim find out all the included files with asl specific include format and generate .trim.deps file. + 2. ASM PP use c preprocessor to find out all included files with #include format and generate a deps file + 3. build tool updates the .deps file + """ + def __init__(self, makefile_folder, ModuleAuto): + self.d_folder = makefile_folder + self.makefile_folder = makefile_folder + self.module_autogen = ModuleAuto + self.ToolChainFamily = ModuleAuto.ToolChainFamily + self.workspace = ModuleAuto.WorkspaceDir + + def CreateModuleDeps(self): + SaveFileOnChange(os.path.join(self.makefile_folder,"deps.txt"),"\n".join(self.DepsCollection),False) + + def CreateDepsInclude(self): + deps_file = {'deps_file':self.deps_files} + try: + deps_include_str = _INCLUDE_DEPS_TEMPLATE.Replace(deps_file) + except Exception as e: + print(e) + SaveFileOnChange(os.path.join(self.makefile_folder,"dependency"),deps_include_str,False) + + @cached_property + def deps_files(self): + """ Get all .deps file under module build folder. """ + deps_files = [] + for root, _, files in os.walk(self.d_folder, topdown=False): + for name in files: + if not name.endswith(".deps"): + continue + abspath = os.path.join(root, name) + deps_files.append(abspath) + return deps_files + + @cached_property + def DepsCollection(self): + """ Collect all the dependency files list from all .deps files under a module's build folder """ + includes = set() + targetname = [item[0].Name for item in self.TargetFileList.values()] + for abspath in self.deps_files: + try: + with open(abspath,"r") as fd: + lines = fd.readlines() + + firstlineitems = lines[0].split(": ") + dependency_file = firstlineitems[1].strip(" \\\n") + dependency_file = dependency_file.strip('''"''') + if dependency_file: + if os.path.normpath(dependency_file +".deps") == abspath: + continue + filename = os.path.basename(dependency_file).strip() + if filename not in self.SourceFileList and filename not in targetname: + includes.add(dependency_file.strip()) + + for item in lines[1:]: + if item == DEP_FILE_TAIL: + continue + dependency_file = item.strip(" \\\n") + dependency_file = dependency_file.strip('''"''') + if os.path.normpath(dependency_file +".deps") == abspath: + continue + filename = os.path.basename(dependency_file).strip() + if filename in self.SourceFileList: + continue + if filename in targetname: + continue + includes.add(dependency_file.strip()) + except Exception as e: + EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False) + continue + rt = sorted(list(set([item.strip(' " \\\n') for item in includes]))) + return rt + + @cached_property + def SourceFileList(self): + """ Get a map of module's source files name to module's source files path """ + source = {os.path.basename(item.File):item.Path for item in self.module_autogen.SourceFileList} + middle_file = {} + for afile in source: + if afile.upper().endswith(".VFR"): + middle_file.update({afile.split(".")[0]+".c":os.path.join(self.module_autogen.DebugDir,afile.split(".")[0]+".c")}) + if afile.upper().endswith((".S","ASM")): + middle_file.update({afile.split(".")[0]+".i":os.path.join(self.module_autogen.OutputDir,afile.split(".")[0]+".i")}) + if afile.upper().endswith(".ASL"): + middle_file.update({afile.split(".")[0]+".i":os.path.join(self.module_autogen.OutputDir,afile.split(".")[0]+".i")}) + source.update({"AutoGen.c":os.path.join(self.module_autogen.OutputDir,"AutoGen.c")}) + source.update(middle_file) + return source + + @cached_property + def HasNamesakeSourceFile(self): + source_base_name = set([os.path.basename(item.File) for item in self.module_autogen.SourceFileList]) + rt = len(source_base_name) != len(self.module_autogen.SourceFileList) + return rt + @cached_property + def CcPPCommandPathSet(self): + rt = set() + rt.add(self.module_autogen.BuildOption.get('CC',{}).get('PATH')) + rt.add(self.module_autogen.BuildOption.get('ASLCC',{}).get('PATH')) + rt.add(self.module_autogen.BuildOption.get('ASLPP',{}).get('PATH')) + rt.add(self.module_autogen.BuildOption.get('VFRPP',{}).get('PATH')) + rt.add(self.module_autogen.BuildOption.get('PP',{}).get('PATH')) + rt.add(self.module_autogen.BuildOption.get('APP',{}).get('PATH')) + rt.discard(None) + return rt + @cached_property + def TargetFileList(self): + """ Get a map of module's target name to a tuple of module's targets path and whose input file path """ + targets = {} + targets["AutoGen.obj"] = (PathClass(os.path.join(self.module_autogen.OutputDir,"AutoGen.obj")),PathClass(os.path.join(self.module_autogen.DebugDir,"AutoGen.c"))) + for item in self.module_autogen.Targets.values(): + for block in item: + targets[block.Target.Path] = (block.Target,block.Inputs[0]) + return targets + + def GetRealTarget(self,source_file_abs): + """ Get the final target file based on source file abspath """ + source_target_map = {item[1].Path:item[0].Path for item in self.TargetFileList.values()} + source_name_map = {item[1].File:item[0].Path for item in self.TargetFileList.values()} + target_abs = source_target_map.get(source_file_abs) + if target_abs is None: + if source_file_abs.strip().endswith(".i"): + sourcefilename = os.path.basename(source_file_abs.strip()) + for sourcefile in source_name_map: + if sourcefilename.split(".")[0] == sourcefile.split(".")[0]: + target_abs = source_name_map[sourcefile] + break + else: + target_abs = source_file_abs + else: + target_abs = source_file_abs + return target_abs + + def CreateDepsFileForMsvc(self, DepList): + """ Generate dependency files, .deps file from /showIncludes output message """ + if not DepList: + return + ModuleDepDict = {} + current_source = "" + SourceFileAbsPathMap = self.SourceFileList + for line in DepList: + line = line.strip() + if self.HasNamesakeSourceFile: + for cc_cmd in self.CcPPCommandPathSet: + if cc_cmd in line: + if '''"'''+cc_cmd+'''"''' in line: + cc_options = line[len(cc_cmd)+2:].split() + else: + cc_options = line[len(cc_cmd):].split() + SourceFileAbsPathMap = {os.path.basename(item):item for item in cc_options if not item.startswith("/") and os.path.exists(item)} + if line in SourceFileAbsPathMap: + current_source = line + if current_source not in ModuleDepDict: + ModuleDepDict[SourceFileAbsPathMap[current_source]] = [] + elif "Note: including file:" == line.lstrip()[:21]: + if not current_source: + EdkLogger.error("build",BUILD_ERROR, "Parse /showIncludes output failed. line: %s. \n" % line, RaiseError=False) + else: + ModuleDepDict[SourceFileAbsPathMap[current_source]].append(line.lstrip()[22:].strip()) + + for source_abs in ModuleDepDict: + if ModuleDepDict[source_abs]: + target_abs = self.GetRealTarget(source_abs) + dep_file_name = os.path.basename(source_abs) + ".deps" + SaveFileOnChange(os.path.join(os.path.dirname(target_abs),dep_file_name)," \\\n".join([target_abs+":"] + ['''"''' + item +'''"''' for item in ModuleDepDict[source_abs]]),False) + + def UpdateDepsFileforNonMsvc(self): + """ Update .deps files. + 1. Update target path to absolute path. + 2. Update middle target to final target. + """ + + for abspath in self.deps_files: + if abspath.endswith(".trim.deps"): + continue + try: + newcontent = [] + with open(abspath,"r") as fd: + lines = fd.readlines() + if lines[-1] == DEP_FILE_TAIL: + continue + firstlineitems = lines[0].strip().split(" ") + + if len(firstlineitems) > 2: + sourceitem = firstlineitems[1] + else: + sourceitem = lines[1].strip().split(" ")[0] + + source_abs = self.SourceFileList.get(sourceitem,sourceitem) + firstlineitems[0] = self.GetRealTarget(source_abs) + p_target = firstlineitems + if not p_target[0].strip().endswith(":"): + p_target[0] += ": " + + if len(p_target) == 2: + p_target[0] += lines[1] + newcontent.append(p_target[0]) + newcontent.extend(lines[2:]) + else: + line1 = " ".join(p_target).strip() + line1 += "\n" + newcontent.append(line1) + newcontent.extend(lines[1:]) + + newcontent.append("\n") + newcontent.append(DEP_FILE_TAIL) + with open(abspath,"w") as fw: + fw.write("".join(newcontent)) + except Exception as e: + EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False) + continue + + def UpdateDepsFileforTrim(self): + """ Update .deps file which generated by trim. """ + + for abspath in self.deps_files: + if not abspath.endswith(".trim.deps"): + continue + try: + newcontent = [] + with open(abspath,"r") as fd: + lines = fd.readlines() + if lines[-1] == DEP_FILE_TAIL: + continue + + source_abs = lines[0].strip().split(" ")[0] + targetitem = self.GetRealTarget(source_abs.strip(" :")) + + targetitem += ": " + targetitem += lines[1] + newcontent.append(targetitem) + newcontent.extend(lines[2:]) + newcontent.append("\n") + newcontent.append(DEP_FILE_TAIL) + with open(abspath,"w") as fw: + fw.write("".join(newcontent)) + except Exception as e: + EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False) + continue diff --git a/BaseTools/Source/Python/AutoGen/ModuleAutoGen.py b/BaseTools/Source/Python/AutoGen/ModuleAutoGen.py index f0812b6887b..aad591de65f 100755 --- a/BaseTools/Source/Python/AutoGen/ModuleAutoGen.py +++ b/BaseTools/Source/Python/AutoGen/ModuleAutoGen.py @@ -6,7 +6,7 @@ # from __future__ import absolute_import from AutoGen.AutoGen import AutoGen -from Common.LongFilePathSupport import CopyLongFilePath +from Common.LongFilePathSupport import LongFilePath, CopyLongFilePath from Common.BuildToolError import * from Common.DataType import * from Common.Misc import * @@ -26,7 +26,6 @@ from .GenPcdDb import CreatePcdDatabaseCode from Common.caching import cached_class_function from AutoGen.ModuleAutoGenHelper import PlatformInfo,WorkSpaceInfo -from AutoGen.CacheIR import ModuleBuildCacheIR import json import tempfile @@ -271,7 +270,7 @@ def __init_platform_info__(self): # @cached_class_function def __hash__(self): - return hash((self.MetaFile, self.Arch)) + return hash((self.MetaFile, self.Arch, self.ToolChain,self.BuildTarget)) def __repr__(self): return "%s [%s]" % (self.MetaFile, self.Arch) @@ -462,14 +461,31 @@ def MakeFileDir(self): def BuildCommand(self): return self.PlatformInfo.BuildCommand - ## Get object list of all packages the module and its dependent libraries belong to + ## Get Module package and Platform package + # + # @retval list The list of package object + # + @cached_property + def PackageList(self): + PkagList = [] + if self.Module.Packages: + PkagList.extend(self.Module.Packages) + Platform = self.BuildDatabase[self.PlatformInfo.MetaFile, self.Arch, self.BuildTarget, self.ToolChain] + for Package in Platform.Packages: + if Package in PkagList: + continue + PkagList.append(Package) + return PkagList + + ## Get object list of all packages the module and its dependent libraries belong to and the Platform depends on # # @retval list The list of package object # @cached_property def DerivedPackageList(self): PackageList = [] - for M in [self.Module] + self.DependentLibraryList: + PackageList.extend(self.PackageList) + for M in self.DependentLibraryList: for Package in M.Packages: if Package in PackageList: continue @@ -938,13 +954,13 @@ def FileTypes(self): self.Targets return self._FileTypes - ## Get the list of package object the module depends on + ## Get the list of package object the module depends on and the Platform depends on # # @retval list The package object list # @cached_property def DependentPackageList(self): - return self.Module.Packages + return self.PackageList ## Return the list of auto-generated code file # @@ -1101,7 +1117,7 @@ def IncludePathList(self): RetVal.append(self.MetaFile.Dir) RetVal.append(self.DebugDir) - for Package in self.Module.Packages: + for Package in self.PackageList: PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir) if PackageDir not in RetVal: RetVal.append(PackageDir) @@ -1112,8 +1128,31 @@ def IncludePathList(self): for Inc in IncludesList: if Inc not in RetVal: RetVal.append(str(Inc)) + RetVal.extend(self.IncPathFromBuildOptions) return RetVal + @cached_property + def IncPathFromBuildOptions(self): + IncPathList = [] + for tool in self.BuildOption: + if 'FLAGS' in self.BuildOption[tool]: + flags = self.BuildOption[tool]['FLAGS'] + whitespace = False + for flag in flags.split(" "): + flag = flag.strip() + if flag.startswith(("/I","-I")): + if len(flag)>2: + if os.path.exists(flag[2:]): + IncPathList.append(flag[2:]) + else: + whitespace = True + continue + if whitespace and flag: + if os.path.exists(flag): + IncPathList.append(flag) + whitespace = False + return IncPathList + @cached_property def IncludePathLength(self): return sum(len(inc)+1 for inc in self.IncludePathList) @@ -1125,7 +1164,7 @@ def IncludePathLength(self): @cached_property def PackageIncludePathList(self): IncludesList = [] - for Package in self.Module.Packages: + for Package in self.PackageList: PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir) IncludesList = Package.Includes if Package._PrivateIncludes: @@ -1268,28 +1307,16 @@ def _GenOffsetBin(self): def OutputFile(self): retVal = set() - OutputDir = self.OutputDir.replace('\\', '/').strip('/') - DebugDir = self.DebugDir.replace('\\', '/').strip('/') - for Item in self.CodaTargetList: - File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/') - NewFile = path.join(self.OutputDir, File) - retVal.add(NewFile) - - Bin = self._GenOffsetBin() - if Bin: - NewFile = path.join(self.OutputDir, Bin) - retVal.add(NewFile) - - for Root, Dirs, Files in os.walk(self.OutputDir): + for Root, Dirs, Files in os.walk(self.BuildDir): for File in Files: # lib file is already added through above CodaTargetList, skip it here - if not (File.lower().endswith('.obj') or File.lower().endswith('.lib')): - NewFile = path.join(self.OutputDir, File) + if not (File.lower().endswith('.obj') or File.lower().endswith('.debug')): + NewFile = path.join(Root, File) retVal.add(NewFile) for Root, Dirs, Files in os.walk(self.FfsOutputDir): for File in Files: - NewFile = path.join(self.FfsOutputDir, File) + NewFile = path.join(Root, File) retVal.add(NewFile) return retVal @@ -1622,9 +1649,12 @@ def CreateAsBuiltInf(self): self.IsAsBuiltInfCreated = True - def CacheCopyFile(self, OriginDir, CopyDir, File): - sub_dir = os.path.relpath(File, CopyDir) - destination_file = os.path.join(OriginDir, sub_dir) + def CacheCopyFile(self, DestDir, SourceDir, File): + if os.path.isdir(File): + return + + sub_dir = os.path.relpath(File, SourceDir) + destination_file = os.path.join(DestDir, sub_dir) destination_dir = os.path.dirname(destination_file) CreateDirectory(destination_dir) try: @@ -1634,105 +1664,73 @@ def CacheCopyFile(self, OriginDir, CopyDir, File): return def CopyModuleToCache(self): - self.GenPreMakefileHash(GlobalData.gCacheIR) - if not (self.MetaFile.Path, self.Arch) in GlobalData.gCacheIR or \ - not GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest: - EdkLogger.quiet("[cache warning]: Cannot generate PreMakefileHash for module: %s[%s]" % (self.MetaFile.Path, self.Arch)) - return False + # Find the MakeHashStr and PreMakeHashStr from latest MakeHashFileList + # and PreMakeHashFileList files + MakeHashStr = None + PreMakeHashStr = None + MakeTimeStamp = 0 + PreMakeTimeStamp = 0 + Files = [f for f in os.listdir(LongFilePath(self.BuildDir)) if path.isfile(LongFilePath(path.join(self.BuildDir, f)))] + for File in Files: + if ".MakeHashFileList." in File: + #find lastest file through time stamp + FileTimeStamp = os.stat(LongFilePath(path.join(self.BuildDir, File)))[8] + if FileTimeStamp > MakeTimeStamp: + MakeTimeStamp = FileTimeStamp + MakeHashStr = File.split('.')[-1] + if len(MakeHashStr) != 32: + EdkLogger.quiet("[cache error]: wrong MakeHashFileList file:%s" % (File)) + if ".PreMakeHashFileList." in File: + FileTimeStamp = os.stat(LongFilePath(path.join(self.BuildDir, File)))[8] + if FileTimeStamp > PreMakeTimeStamp: + PreMakeTimeStamp = FileTimeStamp + PreMakeHashStr = File.split('.')[-1] + if len(PreMakeHashStr) != 32: + EdkLogger.quiet("[cache error]: wrong PreMakeHashFileList file:%s" % (File)) - self.GenMakeHash(GlobalData.gCacheIR) - if not (self.MetaFile.Path, self.Arch) in GlobalData.gCacheIR or \ - not GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].MakeHashChain or \ - not GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest: - EdkLogger.quiet("[cache warning]: Cannot generate MakeHashChain for module: %s[%s]" % (self.MetaFile.Path, self.Arch)) - return False + if not MakeHashStr: + EdkLogger.quiet("[cache error]: No MakeHashFileList file for module:%s[%s]" % (self.MetaFile.Path, self.Arch)) + return + if not PreMakeHashStr: + EdkLogger.quiet("[cache error]: No PreMakeHashFileList file for module:%s[%s]" % (self.MetaFile.Path, self.Arch)) + return - MakeHashStr = str(GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest) - FileDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName, MakeHashStr) - FfsDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name, MakeHashStr) + # Create Cache destination dirs + FileDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName) + FfsDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name) + CacheFileDir = path.join(FileDir, MakeHashStr) + CacheFfsDir = path.join(FfsDir, MakeHashStr) + CreateDirectory (CacheFileDir) + CreateDirectory (CacheFfsDir) - CreateDirectory (FileDir) - self.SaveHashChainFileToCache(GlobalData.gCacheIR) - ModuleFile = path.join(self.OutputDir, self.Name + '.inf') - if os.path.exists(ModuleFile): - CopyFileOnChange(ModuleFile, FileDir) + # Create ModuleHashPair file to support multiple version cache together + ModuleHashPair = path.join(FileDir, self.Name + ".ModuleHashPair") + ModuleHashPairList = [] # tuple list: [tuple(PreMakefileHash, MakeHash)] + if os.path.exists(ModuleHashPair): + with open(ModuleHashPair, 'r') as f: + ModuleHashPairList = json.load(f) + if not (PreMakeHashStr, MakeHashStr) in set(map(tuple, ModuleHashPairList)): + ModuleHashPairList.insert(0, (PreMakeHashStr, MakeHashStr)) + with open(ModuleHashPair, 'w') as f: + json.dump(ModuleHashPairList, f, indent=2) + + # Copy files to Cache destination dirs if not self.OutputFile: Ma = self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain] self.OutputFile = Ma.Binaries for File in self.OutputFile: - if os.path.exists(File): - if File.startswith(os.path.abspath(self.FfsOutputDir)+os.sep): - self.CacheCopyFile(FfsDir, self.FfsOutputDir, File) + if File.startswith(os.path.abspath(self.FfsOutputDir)+os.sep): + self.CacheCopyFile(CacheFfsDir, self.FfsOutputDir, File) + else: + if self.Name + ".autogen.hash." in File or \ + self.Name + ".autogen.hashchain." in File or \ + self.Name + ".hash." in File or \ + self.Name + ".hashchain." in File or \ + self.Name + ".PreMakeHashFileList." in File or \ + self.Name + ".MakeHashFileList." in File: + self.CacheCopyFile(FileDir, self.BuildDir, File) else: - self.CacheCopyFile(FileDir, self.OutputDir, File) - - def SaveHashChainFileToCache(self, gDict): - if not GlobalData.gBinCacheDest: - return False - - self.GenPreMakefileHash(gDict) - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest: - EdkLogger.quiet("[cache warning]: Cannot generate PreMakefileHash for module: %s[%s]" % (self.MetaFile.Path, self.Arch)) - return False - - self.GenMakeHash(gDict) - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain or \ - not gDict[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest: - EdkLogger.quiet("[cache warning]: Cannot generate MakeHashChain for module: %s[%s]" % (self.MetaFile.Path, self.Arch)) - return False - - # save the hash chain list as cache file - MakeHashStr = str(GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest) - CacheDestDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName) - CacheHashDestDir = path.join(CacheDestDir, MakeHashStr) - ModuleHashPair = path.join(CacheDestDir, self.Name + ".ModuleHashPair") - MakeHashChain = path.join(CacheHashDestDir, self.Name + ".MakeHashChain") - ModuleFilesChain = path.join(CacheHashDestDir, self.Name + ".ModuleFilesChain") - - # save the HashChainDict as json file - CreateDirectory (CacheDestDir) - CreateDirectory (CacheHashDestDir) - try: - ModuleHashPairList = [] # tuple list: [tuple(PreMakefileHash, MakeHash)] - if os.path.exists(ModuleHashPair): - with open(ModuleHashPair, 'r') as f: - ModuleHashPairList = json.load(f) - PreMakeHash = gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest - MakeHash = gDict[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest - ModuleHashPairList.append((PreMakeHash, MakeHash)) - ModuleHashPairList = list(set(map(tuple, ModuleHashPairList))) - with open(ModuleHashPair, 'w') as f: - json.dump(ModuleHashPairList, f, indent=2) - except: - EdkLogger.quiet("[cache warning]: fail to save ModuleHashPair file in cache: %s" % ModuleHashPair) - return False - - try: - with open(MakeHashChain, 'w') as f: - json.dump(gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain, f, indent=2) - except: - EdkLogger.quiet("[cache warning]: fail to save MakeHashChain file in cache: %s" % MakeHashChain) - return False - - try: - with open(ModuleFilesChain, 'w') as f: - json.dump(gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesChain, f, indent=2) - except: - EdkLogger.quiet("[cache warning]: fail to save ModuleFilesChain file in cache: %s" % ModuleFilesChain) - return False - - # save the autogenfile and makefile for debug usage - CacheDebugDir = path.join(CacheHashDestDir, "CacheDebug") - CreateDirectory (CacheDebugDir) - CopyFileOnChange(gDict[(self.MetaFile.Path, self.Arch)].MakefilePath, CacheDebugDir) - if gDict[(self.MetaFile.Path, self.Arch)].AutoGenFileList: - for File in gDict[(self.MetaFile.Path, self.Arch)].AutoGenFileList: - CopyFileOnChange(str(File), CacheDebugDir) - - return True - + self.CacheCopyFile(CacheFileDir, self.BuildDir, File) ## Create makefile for the module and its dependent libraries # # @param CreateLibraryMakeFile Flag indicating if or not the makefiles of @@ -1740,10 +1738,6 @@ def SaveHashChainFileToCache(self, gDict): # @cached_class_function def CreateMakeFile(self, CreateLibraryMakeFile=True, GenFfsList = []): - gDict = GlobalData.gCacheIR - if (self.MetaFile.Path, self.Arch) in gDict and \ - gDict[(self.MetaFile.Path, self.Arch)].CreateMakeFileDone: - return # nest this function inside it's only caller. def CreateTimeStamp(): @@ -1793,20 +1787,8 @@ def CreateTimeStamp(): MakefileType = Makefile._FileType MakefileName = Makefile._FILE_NAME_[MakefileType] MakefilePath = os.path.join(self.MakeFileDir, MakefileName) - - MewIR = ModuleBuildCacheIR(self.MetaFile.Path, self.Arch) - MewIR.MakefilePath = MakefilePath - MewIR.DependencyHeaderFileSet = Makefile.DependencyHeaderFileSet - MewIR.CreateMakeFileDone = True - with GlobalData.cache_lock: - try: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.MakefilePath = MakefilePath - IR.DependencyHeaderFileSet = Makefile.DependencyHeaderFileSet - IR.CreateMakeFileDone = True - gDict[(self.MetaFile.Path, self.Arch)] = IR - except: - gDict[(self.MetaFile.Path, self.Arch)] = MewIR + FilePath = path.join(self.BuildDir, self.Name + ".makefile") + SaveFileOnChange(FilePath, MakefilePath, False) def CopyBinaryFiles(self): for File in self.Module.Binaries: @@ -1819,10 +1801,6 @@ def CopyBinaryFiles(self): # dependent libraries will be created # def CreateCodeFile(self, CreateLibraryCodeFile=True): - gDict = GlobalData.gCacheIR - if (self.MetaFile.Path, self.Arch) in gDict and \ - gDict[(self.MetaFile.Path, self.Arch)].CreateCodeFileDone: - return if self.IsCodeFileCreated: return @@ -1881,15 +1859,6 @@ def CreateCodeFile(self, CreateLibraryCodeFile=True): (" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.Name, self.Arch)) self.IsCodeFileCreated = True - MewIR = ModuleBuildCacheIR(self.MetaFile.Path, self.Arch) - MewIR.CreateCodeFileDone = True - with GlobalData.cache_lock: - try: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.CreateCodeFileDone = True - gDict[(self.MetaFile.Path, self.Arch)] = IR - except: - gDict[(self.MetaFile.Path, self.Arch)] = MewIR return AutoGenList @@ -1914,618 +1883,539 @@ def LibraryAutoGenList(self): self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE) return RetVal - def GenModuleHash(self): - # Initialize a dictionary for each arch type - if self.Arch not in GlobalData.gModuleHash: - GlobalData.gModuleHash[self.Arch] = {} + def GenCMakeHash(self): + # GenCMakeHash can only be called in --binary-destination + # Never called in multiprocessing and always directly save result in main process, + # so no need remote dict to share the gCMakeHashFile result with main process - # Early exit if module or library has been hashed and is in memory - if self.Name in GlobalData.gModuleHash[self.Arch]: - return GlobalData.gModuleHash[self.Arch][self.Name].encode('utf-8') + DependencyFileSet = set() + # Add AutoGen files + if self.AutoGenFileList: + for File in set(self.AutoGenFileList): + DependencyFileSet.add(File) + # Add Makefile + abspath = path.join(self.BuildDir, self.Name + ".makefile") + try: + with open(LongFilePath(abspath),"r") as fd: + lines = fd.readlines() + except Exception as e: + EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False) + if lines: + DependencyFileSet.update(lines) + + # Caculate all above dependency files hash # Initialze hash object + FileList = [] m = hashlib.md5() - - # Add Platform level hash - m.update(GlobalData.gPlatformHash.encode('utf-8')) - - # Add Package level hash - if self.DependentPackageList: - for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName): - if Pkg.PackageName in GlobalData.gPackageHash: - m.update(GlobalData.gPackageHash[Pkg.PackageName].encode('utf-8')) - - # Add Library hash - if self.LibraryAutoGenList: - for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name): - if Lib.Name not in GlobalData.gModuleHash[self.Arch]: - Lib.GenModuleHash() - m.update(GlobalData.gModuleHash[self.Arch][Lib.Name].encode('utf-8')) - - # Add Module self - with open(str(self.MetaFile), 'rb') as f: - Content = f.read() - m.update(Content) - - # Add Module's source files - if self.SourceFileList: - for File in sorted(self.SourceFileList, key=lambda x: str(x)): - f = open(str(File), 'rb') + for File in sorted(DependencyFileSet, key=lambda x: str(x)): + if not path.exists(LongFilePath(str(File))): + EdkLogger.quiet("[cache warning]: header file %s is missing for module: %s[%s]" % (File, self.MetaFile.Path, self.Arch)) + continue + with open(LongFilePath(str(File)), 'rb') as f: Content = f.read() - f.close() - m.update(Content) - - GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest() - - return GlobalData.gModuleHash[self.Arch][self.Name].encode('utf-8') + m.update(Content) + FileList.append((str(File), hashlib.md5(Content).hexdigest())) - def GenModuleFilesHash(self, gDict): - # Early exit if module or library has been hashed and is in memory - if (self.MetaFile.Path, self.Arch) in gDict: - if gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesChain: - return gDict[(self.MetaFile.Path, self.Arch)] + HashChainFile = path.join(self.BuildDir, self.Name + ".autogen.hashchain." + m.hexdigest()) + GlobalData.gCMakeHashFile[(self.MetaFile.Path, self.Arch)] = HashChainFile + try: + with open(LongFilePath(HashChainFile), 'w') as f: + json.dump(FileList, f, indent=2) + except: + EdkLogger.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile) + return False - # skip if the module cache already crashed - if (self.MetaFile.Path, self.Arch) in gDict and \ - gDict[(self.MetaFile.Path, self.Arch)].CacheCrash: - return + def GenModuleHash(self): + # GenModuleHash only called after autogen phase + # Never called in multiprocessing and always directly save result in main process, + # so no need remote dict to share the gModuleHashFile result with main process + # + # GenPreMakefileHashList consume no dict. + # GenPreMakefileHashList produce local gModuleHashFile dict. DependencyFileSet = set() # Add Module Meta file - DependencyFileSet.add(self.MetaFile) + DependencyFileSet.add(self.MetaFile.Path) # Add Module's source files if self.SourceFileList: for File in set(self.SourceFileList): - DependencyFileSet.add(File) + DependencyFileSet.add(File.Path) # Add modules's include header files - # Search dependency file list for each source file - SourceFileList = [] - OutPutFileList = [] - for Target in self.IntroTargetList: - SourceFileList.extend(Target.Inputs) - OutPutFileList.extend(Target.Outputs) - if OutPutFileList: - for Item in OutPutFileList: - if Item in SourceFileList: - SourceFileList.remove(Item) - SearchList = [] - for file_path in self.IncludePathList + self.BuildOptionIncPathList: - # skip the folders in platform BuildDir which are not been generated yet - if file_path.startswith(os.path.abspath(self.PlatformInfo.BuildDir)+os.sep): - continue - SearchList.append(file_path) - FileDependencyDict = {} - ForceIncludedFile = [] - for F in SourceFileList: - # skip the files which are not been generated yet, because - # the SourceFileList usually contains intermediate build files, e.g. AutoGen.c - if not os.path.exists(F.Path): - continue - FileDependencyDict[F] = GenMake.GetDependencyList(self, self.FileDependCache, F, ForceIncludedFile, SearchList) + # Directly use the deps.txt file in the module BuildDir + abspath = path.join(self.BuildDir, "deps.txt") + rt = None + try: + with open(LongFilePath(abspath),"r") as fd: + lines = fd.readlines() + if lines: + rt = set([item.lstrip().strip("\n") for item in lines if item.strip("\n").endswith(".h")]) + except Exception as e: + EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False) + + if rt: + DependencyFileSet.update(rt) - if FileDependencyDict: - for Dependency in FileDependencyDict.values(): - DependencyFileSet.update(set(Dependency)) # Caculate all above dependency files hash # Initialze hash object FileList = [] m = hashlib.md5() + BuildDirStr = path.abspath(self.BuildDir).lower() for File in sorted(DependencyFileSet, key=lambda x: str(x)): - if not os.path.exists(str(File)): + # Skip the AutoGen files in BuildDir which already been + # included in .autogen.hash. file + if BuildDirStr in path.abspath(File).lower(): + continue + if not path.exists(LongFilePath(File)): EdkLogger.quiet("[cache warning]: header file %s is missing for module: %s[%s]" % (File, self.MetaFile.Path, self.Arch)) continue - with open(str(File), 'rb') as f: + with open(LongFilePath(File), 'rb') as f: Content = f.read() m.update(Content) - FileList.append((str(File), hashlib.md5(Content).hexdigest())) - - - MewIR = ModuleBuildCacheIR(self.MetaFile.Path, self.Arch) - MewIR.ModuleFilesHashDigest = m.digest() - MewIR.ModuleFilesHashHexDigest = m.hexdigest() - MewIR.ModuleFilesChain = FileList - with GlobalData.cache_lock: - try: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.ModuleFilesHashDigest = m.digest() - IR.ModuleFilesHashHexDigest = m.hexdigest() - IR.ModuleFilesChain = FileList - gDict[(self.MetaFile.Path, self.Arch)] = IR - except: - gDict[(self.MetaFile.Path, self.Arch)] = MewIR + FileList.append((File, hashlib.md5(Content).hexdigest())) - return gDict[(self.MetaFile.Path, self.Arch)] - - def GenPreMakefileHash(self, gDict): - # Early exit if module or library has been hashed and is in memory - if (self.MetaFile.Path, self.Arch) in gDict and \ - gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest: - return gDict[(self.MetaFile.Path, self.Arch)] + HashChainFile = path.join(self.BuildDir, self.Name + ".hashchain." + m.hexdigest()) + GlobalData.gModuleHashFile[(self.MetaFile.Path, self.Arch)] = HashChainFile + try: + with open(LongFilePath(HashChainFile), 'w') as f: + json.dump(FileList, f, indent=2) + except: + EdkLogger.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile) + return False - # skip if the module cache already crashed - if (self.MetaFile.Path, self.Arch) in gDict and \ - gDict[(self.MetaFile.Path, self.Arch)].CacheCrash: - return + def GenPreMakefileHashList(self): + # GenPreMakefileHashList consume below dicts: + # gPlatformHashFile + # gPackageHashFile + # gModuleHashFile + # GenPreMakefileHashList produce no dict. + # gModuleHashFile items might be produced in multiprocessing, so + # need check gModuleHashFile remote dict # skip binary module if self.IsBinaryModule: return - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest: - self.GenModuleFilesHash(gDict) - - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest: - EdkLogger.quiet("[cache warning]: Cannot generate ModuleFilesHashDigest for module %s[%s]" %(self.MetaFile.Path, self.Arch)) - return - - # Initialze hash object + FileList = [] m = hashlib.md5() - # Add Platform level hash - if ('PlatformHash') in gDict: - m.update(gDict[('PlatformHash')].encode('utf-8')) + HashFile = GlobalData.gPlatformHashFile + if path.exists(LongFilePath(HashFile)): + FileList.append(HashFile) + m.update(HashFile.encode('utf-8')) else: - EdkLogger.quiet("[cache warning]: PlatformHash is missing") + EdkLogger.quiet("[cache warning]: No Platform HashFile: %s" % HashFile) # Add Package level hash if self.DependentPackageList: for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName): - if (Pkg.PackageName, 'PackageHash') in gDict: - m.update(gDict[(Pkg.PackageName, 'PackageHash')].encode('utf-8')) + if not (Pkg.PackageName, Pkg.Arch) in GlobalData.gPackageHashFile: + EdkLogger.quiet("[cache warning]:No Package %s for module %s[%s]" % (Pkg.PackageName, self.MetaFile.Path, self.Arch)) + continue + HashFile = GlobalData.gPackageHashFile[(Pkg.PackageName, Pkg.Arch)] + if path.exists(LongFilePath(HashFile)): + FileList.append(HashFile) + m.update(HashFile.encode('utf-8')) else: - EdkLogger.quiet("[cache warning]: %s PackageHash needed by %s[%s] is missing" %(Pkg.PackageName, self.MetaFile.Name, self.Arch)) - - # Add Library hash - if self.LibraryAutoGenList: - for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name): - if not (Lib.MetaFile.Path, Lib.Arch) in gDict or \ - not gDict[(Lib.MetaFile.Path, Lib.Arch)].ModuleFilesHashDigest: - Lib.GenPreMakefileHash(gDict) - m.update(gDict[(Lib.MetaFile.Path, Lib.Arch)].ModuleFilesHashDigest) + EdkLogger.quiet("[cache warning]:No Package HashFile: %s" % HashFile) # Add Module self - m.update(gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest) - - with GlobalData.cache_lock: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.PreMakefileHashHexDigest = m.hexdigest() - gDict[(self.MetaFile.Path, self.Arch)] = IR - - return gDict[(self.MetaFile.Path, self.Arch)] - - def GenMakeHeaderFilesHash(self, gDict): - # Early exit if module or library has been hashed and is in memory - if (self.MetaFile.Path, self.Arch) in gDict and \ - gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashDigest: - return gDict[(self.MetaFile.Path, self.Arch)] - - # skip if the module cache already crashed - if (self.MetaFile.Path, self.Arch) in gDict and \ - gDict[(self.MetaFile.Path, self.Arch)].CacheCrash: - return - - # skip binary module - if self.IsBinaryModule: - return - - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].CreateCodeFileDone: - if self.IsLibrary: - if (self.MetaFile.File,self.MetaFile.Root,self.Arch,self.MetaFile.Path) in GlobalData.libConstPcd: - self.ConstPcd = GlobalData.libConstPcd[(self.MetaFile.File,self.MetaFile.Root,self.Arch,self.MetaFile.Path)] - if (self.MetaFile.File,self.MetaFile.Root,self.Arch,self.MetaFile.Path) in GlobalData.Refes: - self.ReferenceModules = GlobalData.Refes[(self.MetaFile.File,self.MetaFile.Root,self.Arch,self.MetaFile.Path)] - self.CreateCodeFile() - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].CreateMakeFileDone: - self.CreateMakeFile(GenFfsList=GlobalData.FfsCmd.get((self.MetaFile.Path, self.Arch),[])) - - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].CreateCodeFileDone or \ - not gDict[(self.MetaFile.Path, self.Arch)].CreateMakeFileDone: - EdkLogger.quiet("[cache warning]: Cannot create CodeFile or Makefile for module %s[%s]" %(self.MetaFile.Path, self.Arch)) - return - - DependencyFileSet = set() - # Add Makefile - if gDict[(self.MetaFile.Path, self.Arch)].MakefilePath: - DependencyFileSet.add(gDict[(self.MetaFile.Path, self.Arch)].MakefilePath) + # GenPreMakefileHashList needed in both --binary-destination + # and --hash. And --hash might save ModuleHashFile in remote dict + # during multiprocessing. + if (self.MetaFile.Path, self.Arch) in GlobalData.gModuleHashFile: + HashFile = GlobalData.gModuleHashFile[(self.MetaFile.Path, self.Arch)] else: - EdkLogger.quiet("[cache warning]: makefile is missing for module %s[%s]" %(self.MetaFile.Path, self.Arch)) - - # Add header files - if gDict[(self.MetaFile.Path, self.Arch)].DependencyHeaderFileSet: - for File in gDict[(self.MetaFile.Path, self.Arch)].DependencyHeaderFileSet: - DependencyFileSet.add(File) + EdkLogger.quiet("[cache error]:No ModuleHashFile for module: %s[%s]" % (self.MetaFile.Path, self.Arch)) + if path.exists(LongFilePath(HashFile)): + FileList.append(HashFile) + m.update(HashFile.encode('utf-8')) else: - EdkLogger.quiet("[cache warning]: No dependency header found for module %s[%s]" %(self.MetaFile.Path, self.Arch)) + EdkLogger.quiet("[cache warning]:No Module HashFile: %s" % HashFile) - # Add AutoGen files - if self.AutoGenFileList: - for File in set(self.AutoGenFileList): - DependencyFileSet.add(File) - - # Caculate all above dependency files hash - # Initialze hash object - FileList = [] - m = hashlib.md5() - for File in sorted(DependencyFileSet, key=lambda x: str(x)): - if not os.path.exists(str(File)): - EdkLogger.quiet("[cache warning]: header file: %s doesn't exist for module: %s[%s]" % (File, self.MetaFile.Path, self.Arch)) - continue - f = open(str(File), 'rb') - Content = f.read() - f.close() - m.update(Content) - FileList.append((str(File), hashlib.md5(Content).hexdigest())) - - with GlobalData.cache_lock: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.AutoGenFileList = self.AutoGenFileList.keys() - IR.MakeHeaderFilesHashChain = FileList - IR.MakeHeaderFilesHashDigest = m.digest() - gDict[(self.MetaFile.Path, self.Arch)] = IR + # Add Library hash + if self.LibraryAutoGenList: + for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.MetaFile.Path): - return gDict[(self.MetaFile.Path, self.Arch)] + if (Lib.MetaFile.Path, Lib.Arch) in GlobalData.gModuleHashFile: + HashFile = GlobalData.gModuleHashFile[(Lib.MetaFile.Path, Lib.Arch)] + else: + EdkLogger.quiet("[cache error]:No ModuleHashFile for lib: %s[%s]" % (Lib.MetaFile.Path, Lib.Arch)) + if path.exists(LongFilePath(HashFile)): + FileList.append(HashFile) + m.update(HashFile.encode('utf-8')) + else: + EdkLogger.quiet("[cache warning]:No Lib HashFile: %s" % HashFile) - def GenMakeHash(self, gDict): - # Early exit if module or library has been hashed and is in memory - if (self.MetaFile.Path, self.Arch) in gDict and \ - gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain: - return gDict[(self.MetaFile.Path, self.Arch)] + # Save PreMakeHashFileList + FilePath = path.join(self.BuildDir, self.Name + ".PreMakeHashFileList." + m.hexdigest()) + try: + with open(LongFilePath(FilePath), 'w') as f: + json.dump(FileList, f, indent=0) + except: + EdkLogger.quiet("[cache warning]: fail to save PreMake HashFileList: %s" % FilePath) - # skip if the module cache already crashed - if (self.MetaFile.Path, self.Arch) in gDict and \ - gDict[(self.MetaFile.Path, self.Arch)].CacheCrash: - return + def GenMakefileHashList(self): + # GenMakefileHashList only need in --binary-destination which will + # everything in local dict. So don't need check remote dict. # skip binary module if self.IsBinaryModule: return - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest: - self.GenModuleFilesHash(gDict) - if not gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashDigest: - self.GenMakeHeaderFilesHash(gDict) - - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest or \ - not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesChain or \ - not gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashDigest or \ - not gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashChain: - EdkLogger.quiet("[cache warning]: Cannot generate ModuleFilesHash or MakeHeaderFilesHash for module %s[%s]" %(self.MetaFile.Path, self.Arch)) - return - - # Initialze hash object + FileList = [] m = hashlib.md5() - MakeHashChain = [] + # Add AutoGen hash + HashFile = GlobalData.gCMakeHashFile[(self.MetaFile.Path, self.Arch)] + if path.exists(LongFilePath(HashFile)): + FileList.append(HashFile) + m.update(HashFile.encode('utf-8')) + else: + EdkLogger.quiet("[cache warning]:No AutoGen HashFile: %s" % HashFile) - # Add hash of makefile and dependency header files - m.update(gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashDigest) - New = list(set(gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashChain) - set(MakeHashChain)) - New.sort(key=lambda x: str(x)) - MakeHashChain += New + # Add Module self + if (self.MetaFile.Path, self.Arch) in GlobalData.gModuleHashFile: + HashFile = GlobalData.gModuleHashFile[(self.MetaFile.Path, self.Arch)] + else: + EdkLogger.quiet("[cache error]:No ModuleHashFile for module: %s[%s]" % (self.MetaFile.Path, self.Arch)) + if path.exists(LongFilePath(HashFile)): + FileList.append(HashFile) + m.update(HashFile.encode('utf-8')) + else: + EdkLogger.quiet("[cache warning]:No Module HashFile: %s" % HashFile) # Add Library hash if self.LibraryAutoGenList: - for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name): - if not (Lib.MetaFile.Path, Lib.Arch) in gDict or \ - not gDict[(Lib.MetaFile.Path, Lib.Arch)].MakeHashChain: - Lib.GenMakeHash(gDict) - if not gDict[(Lib.MetaFile.Path, Lib.Arch)].MakeHashDigest: - print("Cannot generate MakeHash for lib module:", Lib.MetaFile.Path, Lib.Arch) - continue - m.update(gDict[(Lib.MetaFile.Path, Lib.Arch)].MakeHashDigest) - New = list(set(gDict[(Lib.MetaFile.Path, Lib.Arch)].MakeHashChain) - set(MakeHashChain)) - New.sort(key=lambda x: str(x)) - MakeHashChain += New + for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.MetaFile.Path): + if (Lib.MetaFile.Path, Lib.Arch) in GlobalData.gModuleHashFile: + HashFile = GlobalData.gModuleHashFile[(Lib.MetaFile.Path, Lib.Arch)] + else: + EdkLogger.quiet("[cache error]:No ModuleHashFile for lib: %s[%s]" % (Lib.MetaFile.Path, Lib.Arch)) + if path.exists(LongFilePath(HashFile)): + FileList.append(HashFile) + m.update(HashFile.encode('utf-8')) + else: + EdkLogger.quiet("[cache warning]:No Lib HashFile: %s" % HashFile) - # Add Module self - m.update(gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest) - New = list(set(gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesChain) - set(MakeHashChain)) - New.sort(key=lambda x: str(x)) - MakeHashChain += New + # Save MakeHashFileList + FilePath = path.join(self.BuildDir, self.Name + ".MakeHashFileList." + m.hexdigest()) + try: + with open(LongFilePath(FilePath), 'w') as f: + json.dump(FileList, f, indent=0) + except: + EdkLogger.quiet("[cache warning]: fail to save Make HashFileList: %s" % FilePath) + + def CheckHashChainFile(self, HashChainFile): + # Assume the HashChainFile basename format is the 'x.hashchain.16BytesHexStr' + # The x is module name and the 16BytesHexStr is md5 hexdigest of + # all hashchain files content + HashStr = HashChainFile.split('.')[-1] + if len(HashStr) != 32: + EdkLogger.quiet("[cache error]: wrong format HashChainFile:%s" % (File)) + return False - with GlobalData.cache_lock: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.MakeHashDigest = m.digest() - IR.MakeHashHexDigest = m.hexdigest() - IR.MakeHashChain = MakeHashChain - gDict[(self.MetaFile.Path, self.Arch)] = IR + try: + with open(LongFilePath(HashChainFile), 'r') as f: + HashChainList = json.load(f) + except: + EdkLogger.quiet("[cache error]: fail to load HashChainFile: %s" % HashChainFile) + return False - return gDict[(self.MetaFile.Path, self.Arch)] + # Print the different file info + # print(HashChainFile) + for idx, (SrcFile, SrcHash) in enumerate (HashChainList): + if SrcFile in GlobalData.gFileHashDict: + DestHash = GlobalData.gFileHashDict[SrcFile] + else: + try: + with open(LongFilePath(SrcFile), 'rb') as f: + Content = f.read() + DestHash = hashlib.md5(Content).hexdigest() + GlobalData.gFileHashDict[SrcFile] = DestHash + except IOError as X: + # cache miss if SrcFile is removed in new version code + GlobalData.gFileHashDict[SrcFile] = 0 + EdkLogger.quiet("[cache insight]: first cache miss file in %s is %s" % (HashChainFile, SrcFile)) + return False + if SrcHash != DestHash: + EdkLogger.quiet("[cache insight]: first cache miss file in %s is %s" % (HashChainFile, SrcFile)) + return False + + return True ## Decide whether we can skip the left autogen and make process - def CanSkipbyPreMakefileCache(self, gDict): + def CanSkipbyMakeCache(self): + # For --binary-source only + # CanSkipbyMakeCache consume below dicts: + # gModuleMakeCacheStatus + # gHashChainStatus + # GenPreMakefileHashList produce gModuleMakeCacheStatus, gModuleHashFile dict. + # all these dicts might be produced in multiprocessing, so + # need check these remote dict + if not GlobalData.gBinCacheSource: return False - if gDict[(self.MetaFile.Path, self.Arch)].PreMakeCacheHit: - return True + if (self.MetaFile.Path, self.Arch) in GlobalData.gModuleMakeCacheStatus: + return GlobalData.gModuleMakeCacheStatus[(self.MetaFile.Path, self.Arch)] - if gDict[(self.MetaFile.Path, self.Arch)].CacheCrash: - return False - - # If Module is binary, do not skip by cache + # If Module is binary, which has special build rule, do not skip by cache. if self.IsBinaryModule: + print("[cache miss]: MakeCache: Skip BinaryModule:", self.MetaFile.Path, self.Arch) + GlobalData.gModuleMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False return False - # .inc is contains binary information so do not skip by hash as well + # see .inc as binary file, do not skip by hash for f_ext in self.SourceFileList: if '.inc' in str(f_ext): + print("[cache miss]: MakeCache: Skip '.inc' File:", self.MetaFile.Path, self.Arch) + GlobalData.gModuleMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False return False - # Get the module hash values from stored cache and currrent build - # then check whether cache hit based on the hash values - # if cache hit, restore all the files from cache - FileDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName) + ModuleCacheDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName) FfsDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name) ModuleHashPairList = [] # tuple list: [tuple(PreMakefileHash, MakeHash)] - ModuleHashPair = path.join(FileDir, self.Name + ".ModuleHashPair") - if not os.path.exists(ModuleHashPair): - EdkLogger.quiet("[cache warning]: Cannot find ModuleHashPair file: %s" % ModuleHashPair) - with GlobalData.cache_lock: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.CacheCrash = True - gDict[(self.MetaFile.Path, self.Arch)] = IR - return False - + ModuleHashPair = path.join(ModuleCacheDir, self.Name + ".ModuleHashPair") try: - with open(ModuleHashPair, 'r') as f: + with open(LongFilePath(ModuleHashPair), 'r') as f: ModuleHashPairList = json.load(f) except: + # ModuleHashPair might not exist for new added module + GlobalData.gModuleMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False EdkLogger.quiet("[cache warning]: fail to load ModuleHashPair file: %s" % ModuleHashPair) + print("[cache miss]: MakeCache:", self.MetaFile.Path, self.Arch) return False - self.GenPreMakefileHash(gDict) - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest: - EdkLogger.quiet("[cache warning]: PreMakefileHashHexDigest is missing for module %s[%s]" %(self.MetaFile.Path, self.Arch)) - return False - - MakeHashStr = None - CurrentPreMakeHash = gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest + # Check the PreMakeHash in ModuleHashPairList one by one for idx, (PreMakefileHash, MakeHash) in enumerate (ModuleHashPairList): - if PreMakefileHash == CurrentPreMakeHash: - MakeHashStr = str(MakeHash) + SourceHashDir = path.join(ModuleCacheDir, MakeHash) + SourceFfsHashDir = path.join(FfsDir, MakeHash) + PreMakeHashFileList_FilePah = path.join(ModuleCacheDir, self.Name + ".PreMakeHashFileList." + PreMakefileHash) + MakeHashFileList_FilePah = path.join(ModuleCacheDir, self.Name + ".MakeHashFileList." + MakeHash) - if not MakeHashStr: - return False + try: + with open(LongFilePath(MakeHashFileList_FilePah), 'r') as f: + MakeHashFileList = json.load(f) + except: + EdkLogger.quiet("[cache error]: fail to load MakeHashFileList file: %s" % MakeHashFileList_FilePah) + continue - TargetHashDir = path.join(FileDir, MakeHashStr) - TargetFfsHashDir = path.join(FfsDir, MakeHashStr) + HashMiss = False + for HashChainFile in MakeHashFileList: + HashChainStatus = None + if HashChainFile in GlobalData.gHashChainStatus: + HashChainStatus = GlobalData.gHashChainStatus[HashChainFile] + if HashChainStatus == False: + HashMiss = True + break + elif HashChainStatus == True: + continue + # Convert to path start with cache source dir + RelativePath = os.path.relpath(HashChainFile, self.WorkspaceDir) + NewFilePath = os.path.join(GlobalData.gBinCacheSource, RelativePath) + if self.CheckHashChainFile(NewFilePath): + GlobalData.gHashChainStatus[HashChainFile] = True + # Save the module self HashFile for GenPreMakefileHashList later usage + if self.Name + ".hashchain." in HashChainFile: + GlobalData.gModuleHashFile[(self.MetaFile.Path, self.Arch)] = HashChainFile + else: + GlobalData.gHashChainStatus[HashChainFile] = False + HashMiss = True + break - if not os.path.exists(TargetHashDir): - EdkLogger.quiet("[cache warning]: Cache folder is missing: %s" % TargetHashDir) - return False + if HashMiss: + continue - for root, dir, files in os.walk(TargetHashDir): - for f in files: - File = path.join(root, f) - self.CacheCopyFile(self.OutputDir, TargetHashDir, File) - if os.path.exists(TargetFfsHashDir): - for root, dir, files in os.walk(TargetFfsHashDir): + # PreMakefile cache hit, restore the module build result + for root, dir, files in os.walk(SourceHashDir): for f in files: File = path.join(root, f) - self.CacheCopyFile(self.FfsOutputDir, TargetFfsHashDir, File) - - if self.Name == "PcdPeim" or self.Name == "PcdDxe": - CreatePcdDatabaseCode(self, TemplateString(), TemplateString()) + self.CacheCopyFile(self.BuildDir, SourceHashDir, File) + if os.path.exists(SourceFfsHashDir): + for root, dir, files in os.walk(SourceFfsHashDir): + for f in files: + File = path.join(root, f) + self.CacheCopyFile(self.FfsOutputDir, SourceFfsHashDir, File) + + if self.Name == "PcdPeim" or self.Name == "PcdDxe": + CreatePcdDatabaseCode(self, TemplateString(), TemplateString()) + + print("[cache hit]: MakeCache:", self.MetaFile.Path, self.Arch) + GlobalData.gModuleMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = True + return True - with GlobalData.cache_lock: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.PreMakeCacheHit = True - gDict[(self.MetaFile.Path, self.Arch)] = IR - print("[cache hit]: checkpoint_PreMakefile:", self.MetaFile.Path, self.Arch) - #EdkLogger.quiet("cache hit: %s[%s]" % (self.MetaFile.Path, self.Arch)) - return True + print("[cache miss]: MakeCache:", self.MetaFile.Path, self.Arch) + GlobalData.gModuleMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False + return False - ## Decide whether we can skip the make process - def CanSkipbyMakeCache(self, gDict): - if not GlobalData.gBinCacheSource: + ## Decide whether we can skip the left autogen and make process + def CanSkipbyPreMakeCache(self): + # CanSkipbyPreMakeCache consume below dicts: + # gModulePreMakeCacheStatus + # gHashChainStatus + # gModuleHashFile + # GenPreMakefileHashList produce gModulePreMakeCacheStatus dict. + # all these dicts might be produced in multiprocessing, so + # need check these remote dicts + + if not GlobalData.gUseHashCache or GlobalData.gBinCacheDest: return False - if gDict[(self.MetaFile.Path, self.Arch)].MakeCacheHit: - return True - - if gDict[(self.MetaFile.Path, self.Arch)].CacheCrash: - return False + if (self.MetaFile.Path, self.Arch) in GlobalData.gModulePreMakeCacheStatus: + return GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] - # If Module is binary, do not skip by cache + # If Module is binary, which has special build rule, do not skip by cache. if self.IsBinaryModule: - print("[cache miss]: checkpoint_Makefile: binary module:", self.MetaFile.Path, self.Arch) + print("[cache miss]: PreMakeCache: Skip BinaryModule:", self.MetaFile.Path, self.Arch) + GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False return False - # .inc is contains binary information so do not skip by hash as well + # see .inc as binary file, do not skip by hash for f_ext in self.SourceFileList: if '.inc' in str(f_ext): - with GlobalData.cache_lock: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.MakeCacheHit = False - gDict[(self.MetaFile.Path, self.Arch)] = IR - print("[cache miss]: checkpoint_Makefile: .inc module:", self.MetaFile.Path, self.Arch) + print("[cache miss]: PreMakeCache: Skip '.inc' File:", self.MetaFile.Path, self.Arch) + GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False return False - # Get the module hash values from stored cache and currrent build - # then check whether cache hit based on the hash values - # if cache hit, restore all the files from cache - FileDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName) - FfsDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name) - - ModuleHashPairList = [] # tuple list: [tuple(PreMakefileHash, MakeHash)] - ModuleHashPair = path.join(FileDir, self.Name + ".ModuleHashPair") - if not os.path.exists(ModuleHashPair): - EdkLogger.quiet("[cache warning]: Cannot find ModuleHashPair file: %s" % ModuleHashPair) - with GlobalData.cache_lock: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.CacheCrash = True - gDict[(self.MetaFile.Path, self.Arch)] = IR - return False - - try: - with open(ModuleHashPair, 'r') as f: - ModuleHashPairList = json.load(f) - except: - EdkLogger.quiet("[cache warning]: fail to load ModuleHashPair file: %s" % ModuleHashPair) - return False - - self.GenMakeHash(gDict) - if not (self.MetaFile.Path, self.Arch) in gDict or \ - not gDict[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest: - EdkLogger.quiet("[cache warning]: MakeHashHexDigest is missing for module %s[%s]" %(self.MetaFile.Path, self.Arch)) - return False - - MakeHashStr = None - CurrentMakeHash = gDict[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest - for idx, (PreMakefileHash, MakeHash) in enumerate (ModuleHashPairList): - if MakeHash == CurrentMakeHash: - MakeHashStr = str(MakeHash) - - if not MakeHashStr: - print("[cache miss]: checkpoint_Makefile:", self.MetaFile.Path, self.Arch) - return False - - TargetHashDir = path.join(FileDir, MakeHashStr) - TargetFfsHashDir = path.join(FfsDir, MakeHashStr) - if not os.path.exists(TargetHashDir): - EdkLogger.quiet("[cache warning]: Cache folder is missing: %s" % TargetHashDir) - return False - - for root, dir, files in os.walk(TargetHashDir): - for f in files: - File = path.join(root, f) - self.CacheCopyFile(self.OutputDir, TargetHashDir, File) - - if os.path.exists(TargetFfsHashDir): - for root, dir, files in os.walk(TargetFfsHashDir): - for f in files: - File = path.join(root, f) - self.CacheCopyFile(self.FfsOutputDir, TargetFfsHashDir, File) - - if self.Name == "PcdPeim" or self.Name == "PcdDxe": - CreatePcdDatabaseCode(self, TemplateString(), TemplateString()) - with GlobalData.cache_lock: - IR = gDict[(self.MetaFile.Path, self.Arch)] - IR.MakeCacheHit = True - gDict[(self.MetaFile.Path, self.Arch)] = IR - print("[cache hit]: checkpoint_Makefile:", self.MetaFile.Path, self.Arch) - return True - - ## Show the first file name which causes cache miss - def PrintFirstMakeCacheMissFile(self, gDict): + # For --hash only in the incremental build if not GlobalData.gBinCacheSource: - return - - # skip if the module cache already crashed - if gDict[(self.MetaFile.Path, self.Arch)].CacheCrash: - return - - # skip binary module - if self.IsBinaryModule: - return + Files = [path.join(self.BuildDir, f) for f in os.listdir(self.BuildDir) if path.isfile(path.join(self.BuildDir, f))] + PreMakeHashFileList_FilePah = None + MakeTimeStamp = 0 + # Find latest PreMakeHashFileList file in self.BuildDir folder + for File in Files: + if ".PreMakeHashFileList." in File: + FileTimeStamp = os.stat(path.join(self.BuildDir, File))[8] + if FileTimeStamp > MakeTimeStamp: + MakeTimeStamp = FileTimeStamp + PreMakeHashFileList_FilePah = File + if not PreMakeHashFileList_FilePah: + GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False + return False - if not (self.MetaFile.Path, self.Arch) in gDict: - return + try: + with open(LongFilePath(PreMakeHashFileList_FilePah), 'r') as f: + PreMakeHashFileList = json.load(f) + except: + EdkLogger.quiet("[cache error]: fail to load PreMakeHashFileList file: %s" % PreMakeHashFileList_FilePah) + print("[cache miss]: PreMakeCache:", self.MetaFile.Path, self.Arch) + GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False + return False - # Only print cache miss file for the MakeCache not hit module - if gDict[(self.MetaFile.Path, self.Arch)].MakeCacheHit: - return + HashMiss = False + for HashChainFile in PreMakeHashFileList: + HashChainStatus = None + if HashChainFile in GlobalData.gHashChainStatus: + HashChainStatus = GlobalData.gHashChainStatus[HashChainFile] + if HashChainStatus == False: + HashMiss = True + break + elif HashChainStatus == True: + continue + if self.CheckHashChainFile(HashChainFile): + GlobalData.gHashChainStatus[HashChainFile] = True + # Save the module self HashFile for GenPreMakefileHashList later usage + if self.Name + ".hashchain." in HashChainFile: + GlobalData.gModuleHashFile[(self.MetaFile.Path, self.Arch)] = HashChainFile + else: + GlobalData.gHashChainStatus[HashChainFile] = False + HashMiss = True + break - if not gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain: - EdkLogger.quiet("[cache insight]: MakeHashChain is missing for: %s[%s]" % (self.MetaFile.Path, self.Arch)) - return + if HashMiss: + print("[cache miss]: PreMakeCache:", self.MetaFile.Path, self.Arch) + GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False + return False + else: + print("[cache hit]: PreMakeCache:", self.MetaFile.Path, self.Arch) + GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = True + return True - # Find the cache dir name through the .ModuleHashPair file info - FileDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName) + ModuleCacheDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName) + FfsDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name) ModuleHashPairList = [] # tuple list: [tuple(PreMakefileHash, MakeHash)] - ModuleHashPair = path.join(FileDir, self.Name + ".ModuleHashPair") - if not os.path.exists(ModuleHashPair): - EdkLogger.quiet("[cache insight]: Cannot find ModuleHashPair file for module: %s[%s]" % (self.MetaFile.Path, self.Arch)) - return - + ModuleHashPair = path.join(ModuleCacheDir, self.Name + ".ModuleHashPair") try: - with open(ModuleHashPair, 'r') as f: + with open(LongFilePath(ModuleHashPair), 'r') as f: ModuleHashPairList = json.load(f) except: - EdkLogger.quiet("[cache insight]: Cannot load ModuleHashPair file for module: %s[%s]" % (self.MetaFile.Path, self.Arch)) - return + # ModuleHashPair might not exist for new added module + GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False + EdkLogger.quiet("[cache warning]: fail to load ModuleHashPair file: %s" % ModuleHashPair) + print("[cache miss]: PreMakeCache:", self.MetaFile.Path, self.Arch) + return False - MakeHashSet = set() + # Check the PreMakeHash in ModuleHashPairList one by one for idx, (PreMakefileHash, MakeHash) in enumerate (ModuleHashPairList): - TargetHashDir = path.join(FileDir, str(MakeHash)) - if os.path.exists(TargetHashDir): - MakeHashSet.add(MakeHash) - if not MakeHashSet: - EdkLogger.quiet("[cache insight]: Cannot find valid cache dir for module: %s[%s]" % (self.MetaFile.Path, self.Arch)) - return - - TargetHash = list(MakeHashSet)[0] - TargetHashDir = path.join(FileDir, str(TargetHash)) - if len(MakeHashSet) > 1 : - EdkLogger.quiet("[cache insight]: found multiple cache dirs for this module, random select dir '%s' to search the first cache miss file: %s[%s]" % (TargetHash, self.MetaFile.Path, self.Arch)) + SourceHashDir = path.join(ModuleCacheDir, MakeHash) + SourceFfsHashDir = path.join(FfsDir, MakeHash) + PreMakeHashFileList_FilePah = path.join(ModuleCacheDir, self.Name + ".PreMakeHashFileList." + PreMakefileHash) + MakeHashFileList_FilePah = path.join(ModuleCacheDir, self.Name + ".MakeHashFileList." + MakeHash) - ListFile = path.join(TargetHashDir, self.Name + '.MakeHashChain') - if os.path.exists(ListFile): try: - f = open(ListFile, 'r') - CachedList = json.load(f) - f.close() + with open(LongFilePath(PreMakeHashFileList_FilePah), 'r') as f: + PreMakeHashFileList = json.load(f) except: - EdkLogger.quiet("[cache insight]: Cannot load MakeHashChain file: %s" % ListFile) - return - else: - EdkLogger.quiet("[cache insight]: Cannot find MakeHashChain file: %s" % ListFile) - return - - CurrentList = gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain - for idx, (file, hash) in enumerate (CurrentList): - (filecached, hashcached) = CachedList[idx] - if file != filecached: - EdkLogger.quiet("[cache insight]: first different file in %s[%s] is %s, the cached one is %s" % (self.MetaFile.Path, self.Arch, file, filecached)) - break - if hash != hashcached: - EdkLogger.quiet("[cache insight]: first cache miss file in %s[%s] is %s" % (self.MetaFile.Path, self.Arch, file)) - break - - return True + EdkLogger.quiet("[cache error]: fail to load PreMakeHashFileList file: %s" % PreMakeHashFileList_FilePah) + continue - ## Decide whether we can skip the ModuleAutoGen process - def CanSkipbyCache(self, gDict): - # Hashing feature is off - if not GlobalData.gBinCacheSource: - return False + HashMiss = False + for HashChainFile in PreMakeHashFileList: + HashChainStatus = None + if HashChainFile in GlobalData.gHashChainStatus: + HashChainStatus = GlobalData.gHashChainStatus[HashChainFile] + if HashChainStatus == False: + HashMiss = True + break + elif HashChainStatus == True: + continue + # Convert to path start with cache source dir + RelativePath = os.path.relpath(HashChainFile, self.WorkspaceDir) + NewFilePath = os.path.join(GlobalData.gBinCacheSource, RelativePath) + if self.CheckHashChainFile(NewFilePath): + GlobalData.gHashChainStatus[HashChainFile] = True + else: + GlobalData.gHashChainStatus[HashChainFile] = False + HashMiss = True + break - if self in GlobalData.gBuildHashSkipTracking: - return GlobalData.gBuildHashSkipTracking[self] + if HashMiss: + continue - # If library or Module is binary do not skip by hash - if self.IsBinaryModule: - GlobalData.gBuildHashSkipTracking[self] = False - return False + # PreMakefile cache hit, restore the module build result + for root, dir, files in os.walk(SourceHashDir): + for f in files: + File = path.join(root, f) + self.CacheCopyFile(self.BuildDir, SourceHashDir, File) + if os.path.exists(SourceFfsHashDir): + for root, dir, files in os.walk(SourceFfsHashDir): + for f in files: + File = path.join(root, f) + self.CacheCopyFile(self.FfsOutputDir, SourceFfsHashDir, File) + + if self.Name == "PcdPeim" or self.Name == "PcdDxe": + CreatePcdDatabaseCode(self, TemplateString(), TemplateString()) + + print("[cache hit]: PreMakeCache:", self.MetaFile.Path, self.Arch) + GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = True + return True - # .inc is contains binary information so do not skip by hash as well - for f_ext in self.SourceFileList: - if '.inc' in str(f_ext): - GlobalData.gBuildHashSkipTracking[self] = False - return False + print("[cache miss]: PreMakeCache:", self.MetaFile.Path, self.Arch) + GlobalData.gModulePreMakeCacheStatus[(self.MetaFile.Path, self.Arch)] = False + return False - if not (self.MetaFile.Path, self.Arch) in gDict: + ## Decide whether we can skip the Module build + def CanSkipbyCache(self, gHitSet): + # Hashing feature is off + if not GlobalData.gBinCacheSource: return False - if gDict[(self.MetaFile.Path, self.Arch)].PreMakeCacheHit: - GlobalData.gBuildHashSkipTracking[self] = True - return True - - if gDict[(self.MetaFile.Path, self.Arch)].MakeCacheHit: - GlobalData.gBuildHashSkipTracking[self] = True + if self in gHitSet: return True return False diff --git a/BaseTools/Source/Python/AutoGen/PlatformAutoGen.py b/BaseTools/Source/Python/AutoGen/PlatformAutoGen.py index debeb46f585..7bd24dad42f 100644 --- a/BaseTools/Source/Python/AutoGen/PlatformAutoGen.py +++ b/BaseTools/Source/Python/AutoGen/PlatformAutoGen.py @@ -148,7 +148,7 @@ def FillData_LibConstPcd(self): # @cached_class_function def __hash__(self): - return hash((self.MetaFile, self.Arch)) + return hash((self.MetaFile, self.Arch,self.ToolChain,self.BuildTarget)) @cached_class_function def __repr__(self): return "%s [%s]" % (self.MetaFile, self.Arch) @@ -975,6 +975,7 @@ def PackageList(self): continue ModuleData = self.BuildDatabase[ModuleFile, self.Arch, self.BuildTarget, self.ToolChain] RetVal.update(ModuleData.Packages) + RetVal.update(self.Platform.Packages) return list(RetVal) @cached_property diff --git a/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py b/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py index 9d8040905ea..668126aaac4 100644 --- a/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py +++ b/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py @@ -23,6 +23,7 @@ from Common.BuildToolError import * from Common.DataType import * from Common.Misc import * +import json ## Regular expression for splitting Dependency Expression string into tokens gDepexTokenPattern = re.compile("(\(|\)|\w+| \S+\.inf)") @@ -127,7 +128,7 @@ def _InitWorker(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, self.CreateBuildOptionsFile() self.CreatePcdTokenNumberFile() - self.CreateModuleHashInfo() + self.GeneratePlatformLevelHash() # # Merge Arch @@ -165,7 +166,7 @@ def FdfProfile(self): if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict: FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName] for FdRegion in FdDict.RegionList: - if str(FdRegion.RegionType) is 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList): + if str(FdRegion.RegionType) == 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList): if int(FdRegion.Offset) % 8 != 0: EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset)) FdfProfile = Fdf.Profile @@ -420,6 +421,7 @@ def PkgSet(self): continue ModuleData = self.BuildDatabase[ModuleFile, Arch, self.BuildTarget, self.ToolChain] PkgSet.update(ModuleData.Packages) + PkgSet.update(Platform.Packages) Pkgs[Arch] = list(PkgSet) return Pkgs @@ -527,12 +529,12 @@ def CreatePcdTokenNumberFile(self): PcdTokenNumber += str(Pa.PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName]) SaveFileOnChange(os.path.join(self.BuildDir, 'PcdTokenNumber'), PcdTokenNumber, False) - def CreateModuleHashInfo(self): + def GeneratePlatformLevelHash(self): # # Get set of workspace metafiles # AllWorkSpaceMetaFiles = self._GetMetaFiles(self.BuildTarget, self.ToolChain) - + AllWorkSpaceMetaFileList = sorted(AllWorkSpaceMetaFiles, key=lambda x: str(x)) # # Retrieve latest modified time of all metafiles # @@ -543,16 +545,35 @@ def CreateModuleHashInfo(self): self._SrcTimeStamp = SrcTimeStamp if GlobalData.gUseHashCache: + FileList = [] m = hashlib.md5() - for files in AllWorkSpaceMetaFiles: - if files.endswith('.dec'): + for file in AllWorkSpaceMetaFileList: + if file.endswith('.dec'): continue - f = open(files, 'rb') + f = open(file, 'rb') Content = f.read() f.close() m.update(Content) - SaveFileOnChange(os.path.join(self.BuildDir, 'AutoGen.hash'), m.hexdigest(), False) - GlobalData.gPlatformHash = m.hexdigest() + FileList.append((str(file), hashlib.md5(Content).hexdigest())) + + HashDir = path.join(self.BuildDir, "Hash_Platform") + HashFile = path.join(HashDir, 'Platform.hash.' + m.hexdigest()) + SaveFileOnChange(HashFile, m.hexdigest(), False) + HashChainFile = path.join(HashDir, 'Platform.hashchain.' + m.hexdigest()) + GlobalData.gPlatformHashFile = HashChainFile + try: + with open(HashChainFile, 'w') as f: + json.dump(FileList, f, indent=2) + except: + EdkLogger.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile) + + if GlobalData.gBinCacheDest: + # Copy platform hash files to cache destination + FileDir = path.join(GlobalData.gBinCacheDest, self.OutputDir, self.BuildTarget + "_" + self.ToolChain, "Hash_Platform") + CacheFileDir = FileDir + CreateDirectory(CacheFileDir) + CopyFileOnChange(HashFile, CacheFileDir) + CopyFileOnChange(HashChainFile, CacheFileDir) # # Write metafile list to build directory @@ -563,7 +584,7 @@ def CreateModuleHashInfo(self): if not os.path.exists(self.BuildDir): os.makedirs(self.BuildDir) with open(os.path.join(self.BuildDir, 'AutoGen'), 'w+') as file: - for f in AllWorkSpaceMetaFiles: + for f in AllWorkSpaceMetaFileList: print(f, file=file) return True @@ -571,15 +592,16 @@ def _GenPkgLevelHash(self, Pkg): if Pkg.PackageName in GlobalData.gPackageHash: return - PkgDir = os.path.join(self.BuildDir, Pkg.Arch, Pkg.PackageName) + PkgDir = os.path.join(self.BuildDir, Pkg.Arch, "Hash_Pkg", Pkg.PackageName) CreateDirectory(PkgDir) - HashFile = os.path.join(PkgDir, Pkg.PackageName + '.hash') + FileList = [] m = hashlib.md5() # Get .dec file's hash value f = open(Pkg.MetaFile.Path, 'rb') Content = f.read() f.close() m.update(Content) + FileList.append((str(Pkg.MetaFile.Path), hashlib.md5(Content).hexdigest())) # Get include files hash value if Pkg.Includes: for inc in sorted(Pkg.Includes, key=lambda x: str(x)): @@ -590,9 +612,28 @@ def _GenPkgLevelHash(self, Pkg): Content = f.read() f.close() m.update(Content) - SaveFileOnChange(HashFile, m.hexdigest(), False) + FileList.append((str(File_Path), hashlib.md5(Content).hexdigest())) GlobalData.gPackageHash[Pkg.PackageName] = m.hexdigest() + HashDir = PkgDir + HashFile = path.join(HashDir, Pkg.PackageName + '.hash.' + m.hexdigest()) + SaveFileOnChange(HashFile, m.hexdigest(), False) + HashChainFile = path.join(HashDir, Pkg.PackageName + '.hashchain.' + m.hexdigest()) + GlobalData.gPackageHashFile[(Pkg.PackageName, Pkg.Arch)] = HashChainFile + try: + with open(HashChainFile, 'w') as f: + json.dump(FileList, f, indent=2) + except: + EdkLogger.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile) + + if GlobalData.gBinCacheDest: + # Copy Pkg hash files to cache destination dir + FileDir = path.join(GlobalData.gBinCacheDest, self.OutputDir, self.BuildTarget + "_" + self.ToolChain, Pkg.Arch, "Hash_Pkg", Pkg.PackageName) + CacheFileDir = FileDir + CreateDirectory(CacheFileDir) + CopyFileOnChange(HashFile, CacheFileDir) + CopyFileOnChange(HashChainFile, CacheFileDir) + def _GetMetaFiles(self, Target, Toolchain): AllWorkSpaceMetaFiles = set() # diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py index 6838beb6820..a8de988253c 100644 --- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py +++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py @@ -31,6 +31,7 @@ from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass +from Common.Uefi.Capsule.CapsuleDependency import CapsuleDependencyClass from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass # @@ -306,6 +307,7 @@ def EncodeJsonFileParse (Json): OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None) + DepexExp = ConvertJsonValue (Config, 'Dependencies', str, Required = False, Default = None) # # Read binary input file @@ -330,7 +332,8 @@ def EncodeJsonFileParse (Json): OpenSslSignerPrivateCertFile, OpenSslOtherPublicCertFile, OpenSslTrustedPublicCertFile, - SigningToolPath + SigningToolPath, + DepexExp )) def GenerateOutputJson (PayloadJsonDescriptorList): @@ -348,7 +351,8 @@ def GenerateOutputJson (PayloadJsonDescriptorList): "OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile), "OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile), "OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile), - "SigningToolPath": str(PayloadDescriptor.SigningToolPath) + "SigningToolPath": str(PayloadDescriptor.SigningToolPath), + "Dependencies" : str(PayloadDescriptor.DepexExp) }for PayloadDescriptor in PayloadJsonDescriptorList ] } @@ -424,7 +428,8 @@ def __init__(self, OpenSslSignerPrivateCertFile = None, OpenSslOtherPublicCertFile = None, OpenSslTrustedPublicCertFile = None, - SigningToolPath = None + SigningToolPath = None, + DepexExp = None ): self.Payload = Payload self.Guid = Guid @@ -438,6 +443,7 @@ def __init__(self, self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile self.SigningToolPath = SigningToolPath + self.DepexExp = DepexExp self.UseSignTool = self.SignToolPfxFile is not None self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and @@ -446,6 +452,7 @@ def __init__(self, self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or self.OpenSslOtherPublicCertFile is not None or self.OpenSslTrustedPublicCertFile is not None) + self.UseDependency = self.DepexExp is not None def Validate(self, args): if self.UseSignTool and self.AnyOpenSsl: @@ -544,7 +551,8 @@ def Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer): args.OpenSslSignerPrivateCertFile, args.OpenSslOtherPublicCertFile, args.OpenSslTrustedPublicCertFile, - args.SigningToolPath + args.SigningToolPath, + None )) for SinglePayloadDescriptor in PayloadDescriptorList: try: @@ -564,6 +572,12 @@ def Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer): except: print ('GenerateCapsule: error: can not encode FMP Payload Header') sys.exit (1) + if SinglePayloadDescriptor.UseDependency: + CapsuleDependency.Payload = Result + CapsuleDependency.DepexExp = SinglePayloadDescriptor.DepexExp + Result = CapsuleDependency.Encode () + if args.Verbose: + CapsuleDependency.DumpInfo () if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool: # # Sign image with 64-bit MonotonicCount appended to end of image @@ -657,7 +671,8 @@ def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer): args.OpenSslSignerPrivateCertFile, args.OpenSslOtherPublicCertFile, args.OpenSslTrustedPublicCertFile, - args.SigningToolPath + args.SigningToolPath, + None )) # # Perform additional verification on payload descriptors @@ -700,7 +715,8 @@ def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer): PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, - PayloadDescriptorList[Index].SigningToolPath + PayloadDescriptorList[Index].SigningToolPath, + None )) else: PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload @@ -718,6 +734,7 @@ def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer): None, None, None, + None, None )) GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId @@ -736,7 +753,8 @@ def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer): PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, - PayloadDescriptorList[Index].SigningToolPath + PayloadDescriptorList[Index].SigningToolPath, + None )) JsonIndex = 0 for SinglePayloadDescriptor in PayloadDescriptorList: @@ -782,6 +800,23 @@ def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer): if args.Verbose: print ('--------') print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') + + PayloadSignature = struct.unpack (' +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +import struct +import json +import sys +import uuid +import re + +''' +CapsuleDependency +''' + +class OpConvert (object): + def __init__ (self): + # Opcode: (OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert) + self._DepexOperations = {0x00: (16, 16, 's', self.Str2Guid, self.Guid2Str), + 0x01: (4, 1, 'I', self.Str2Uint, self.Uint2Str), + 0x02: (1, 0, 's', self.Str2Utf8, self.Byte2Str), + } + + def Str2Uint (self, Data): + try: + Value = int (Data, 16) + except: + Message = '{Data} is not a valid integer value.'.format (Data = Data) + raise ValueError (Message) + if Value < 0 or Value > 0xFFFFFFFF: + Message = '{Data} is not an UINT32.'.format (Data = Data) + raise ValueError (Message) + return Value + + def Uint2Str (self, Data): + if Data < 0 or Data > 0xFFFFFFFF: + Message = '{Data} is not an UINT32.'.format (Data = Data) + raise ValueError (Message) + return "0x{Data:08x}".format (Data = Data) + + def Str2Guid (self, Data): + try: + Guid = uuid.UUID (Data) + except: + Message = '{Data} is not a valid registry format GUID value.'.format (Data = Data) + raise ValueError (Message) + return Guid.bytes_le + + def Guid2Str (self, Data): + try: + Guid = uuid.UUID (bytes_le = Data) + except: + Message = '{Data} is not a valid binary format GUID value.'.format (Data = Data) + raise ValueError (Message) + return str (Guid).upper () + + def Str2Utf8 (self, Data): + if isinstance (Data, str): + return Data.encode ('utf-8') + else: + Message = '{Data} is not a valid string.'.format (Data = Data) + raise ValueError (Message) + + def Byte2Str (self, Data): + if isinstance (Data, bytes): + if Data[-1:] == b'\x00': + return str (Data[:-1], 'utf-8') + else: + return str (Data, 'utf-8') + else: + Message = '{Data} is not a valid binary string.'.format (Data = Data) + raise ValueError (Message) + + def OpEncode (self, Opcode, Operand = None): + BinTemp = struct.pack ('': [4, 0x09, 2], + '>=': [4, 0x0A, 2], + '<': [4, 0x0B, 2], + '<=': [4, 0x0C, 2], + } + + def __init__ (self): + self.Payload = b'' + self._DepexExp = None + self._DepexList = [] + self._DepexDump = [] + self.Depex = b'' + self._Valid = False + self._DepexSize = 0 + self._opReferenceReverse = {v[1] : k for k, v in self._opReference.items ()} + self.OpConverter = OpConvert () + + @property + def DepexExp (self): + return self._DepexExp + + @DepexExp.setter + def DepexExp (self, DepexExp = ''): + if isinstance (DepexExp, str): + DepexExp = re.sub (r'\n',r' ',DepexExp) + DepexExp = re.sub (r'\(',r' ( ',DepexExp) + DepexExp = re.sub (r'\)',r' ) ',DepexExp) + DepexExp = re.sub (r'~',r' ~ ',DepexExp) + self._DepexList = re.findall(r"[^\s\"\']+|\"[^\"]*\"|\'[^\']*\'",DepexExp) + self._DepexExp = " ".join(self._DepexList) + + else: + Msg = 'Input Depex Expression is not valid string.' + raise ValueError (Msg) + + def IsValidOperator (self, op): + return op in self._opReference.keys () + + def IsValidUnaryOperator (self, op): + return op in self._opReference.keys () and self._opReference[op][2] == 1 + + def IsValidBinocularOperator (self, op): + return op in self._opReference.keys () and self._opReference[op][2] == 2 + + def IsValidGuid (self, operand): + try: + uuid.UUID (operand) + except: + return False + return True + + def IsValidVersion (self, operand): + try: + Value = int (operand, 16) + if Value < 0 or Value > 0xFFFFFFFF: + return False + except: + return False + return True + + def IsValidBoolean (self, operand): + try: + return operand.upper () in ['TRUE', 'FALSE'] + except: + return False + + def IsValidOperand (self, operand): + return self.IsValidVersion (operand) or self.IsValidGuid (operand) or self.IsValidBoolean (operand) + + def IsValidString (self, operand): + return operand[0] == "\"" and operand[-1] == "\"" and len(operand) >= 2 + + # Check if priority of current operater is greater than pervious op + def PriorityNotGreater (self, prevOp, currOp): + return self._opReference[currOp][0] <= self._opReference[prevOp][0] + + def ValidateDepex (self): + OpList = self._DepexList + + i = 0 + while i < len (OpList): + Op = OpList[i] + + if Op == 'DECLARE': + i += 1 + if i >= len (OpList): + Msg = 'No more Operand after {Op}.'.format (Op = OpList[i-1]) + raise IndexError (Msg) + # Check valid string + if not self.IsValidString(OpList[i]): + Msg = '{Operand} after {Op} is not a valid expression input.'.format (Operand = OpList[i], Op = OpList[i-1]) + raise ValueError (Msg) + + elif Op == '(': + # Expression cannot end with ( + if i == len (OpList) - 1: + Msg = 'Expression cannot end with \'(\'' + raise ValueError (Msg) + # The previous op after '(' cannot be a binocular operator + if self.IsValidBinocularOperator (OpList[i+1]) : + Msg = '{Op} after \'(\' is not a valid expression input.'.format (Op = OpList[i+1]) + raise ValueError (Msg) + + elif Op == ')': + # Expression cannot start with ) + if i == 0: + Msg = 'Expression cannot start with \')\'' + raise ValueError (Msg) + # The previous op before ')' cannot be an operator + if self.IsValidOperator (OpList[i-1]): + Msg = '{Op} before \')\' is not a valid expression input.'.format (Op = OpList[i-1]) + raise ValueError (Msg) + # The next op after ')' cannot be operand or unary operator + if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])): + Msg = '{Op} after \')\' is not a valid expression input.'.format (Op = OpList[i+1]) + raise ValueError (Msg) + + elif self.IsValidOperand (Op): + # The next expression of operand cannot be operand or unary operator + if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])): + Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op) + raise ValueError (Msg) + + elif self.IsValidOperator (Op): + # The next op of operator cannot binocular operator + if (i + 1) < len (OpList) and self.IsValidBinocularOperator (OpList[i+1]): + Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op) + raise ValueError (Msg) + # The first op can not be binocular operator + if i == 0 and self.IsValidBinocularOperator (Op): + Msg = 'Expression cannot start with an operator {Op}.'.format (Op = Op) + raise ValueError (Msg) + # The last op can not be operator + if i == len (OpList) - 1: + Msg = 'Expression cannot ended with an operator {Op}.'.format (Op = Op) + raise ValueError (Msg) + # The next op of unary operator cannot be guid / version + if self.IsValidUnaryOperator (Op) and (self.IsValidGuid (OpList[i+1]) or self.IsValidVersion (OpList[i+1])): + Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op) + raise ValueError (Msg) + + else: + Msg = '{Op} is not a valid expression input.'.format (Op = Op) + raise ValueError (Msg) + i += 1 + + def Encode (self): + # initialize + self.Depex = b'' + self._DepexDump = [] + OperandStack = [] + OpeartorStack = [] + OpList = self._DepexList + + self.ValidateDepex () + + # convert + i = 0 + while i < len (OpList): + Op = OpList[i] + if Op == 'DECLARE': + # This declare next expression value is a VERSION_STRING + i += 1 + self.Depex += self.OpConverter.OpEncode (0x02, OpList[i][1:-1]) + + elif Op == '(': + OpeartorStack.append (Op) + + elif Op == ')': + while (OpeartorStack and OpeartorStack[-1] != '('): + Operator = OpeartorStack.pop () + self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1]) + try: + OpeartorStack.pop () # pop out '(' + except: + Msg = 'Pop out \'(\' failed, too many \')\'' + raise ValueError (Msg) + + elif self.IsValidGuid (Op): + if not OperandStack: + OperandStack.append (self.OpConverter.OpEncode (0x00, Op)) + else: + # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison. + self.Depex += self.OpConverter.OpEncode (0x00, Op) + self.Depex += OperandStack.pop () + + elif self.IsValidVersion (Op): + if not OperandStack: + OperandStack.append (self.OpConverter.OpEncode (0x01, Op)) + else: + # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison. + self.Depex += self.OpConverter.OpEncode (0x01, Op) + self.Depex += OperandStack.pop () + + elif self.IsValidBoolean (Op): + if Op.upper () == 'FALSE': + self.Depex += self.OpConverter.OpEncode (0x07) + elif Op.upper () == 'TRUE': + self.Depex += self.OpConverter.OpEncode (0x06) + + elif self.IsValidOperator (Op): + while (OpeartorStack and OpeartorStack[-1] != '(' and self.PriorityNotGreater (OpeartorStack[-1], Op)): + Operator = OpeartorStack.pop () + self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1]) + OpeartorStack.append (Op) + + i += 1 + + while OpeartorStack: + Operator = OpeartorStack.pop () + if Operator == '(': + Msg = 'Too many \'(\'.' + raise ValueError (Msg) + self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1]) + self.Depex += self.OpConverter.OpEncode (0x0D) + + self._Valid = True + self._DepexSize = len (self.Depex) + return self.Depex + self.Payload + + def Decode (self, Buffer): + # initialize + self.Depex = Buffer + OperandStack = [] + DepexLen = 0 + + while True: + Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:]) + DepexLen += OperandSize + 1 + + if Opcode == 0x0D: + break + + elif Opcode == 0x02: + if not OperandStack: + OperandStack.append ('DECLARE \"{String}\"'.format (String = Operand)) + else: + PrevOperand = OperandStack.pop () + OperandStack.append ('{Operand} DECLARE \"{String}\"'.format (Operand = PrevOperand, String = Operand)) + + elif Opcode in [0x00, 0x01]: + OperandStack.append (Operand) + + elif Opcode == 0x06: + OperandStack.append ('TRUE') + + elif Opcode == 0x07: + OperandStack.append ('FALSE') + + elif self.IsValidOperator (self._opReferenceReverse[Opcode]): + Operator = self._opReferenceReverse[Opcode] + if self.IsValidUnaryOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 1: + Oprand = OperandStack.pop () + OperandStack.append (' ( {Operator} {Oprand} )'.format (Operator = Operator, Oprand = Oprand)) + elif self.IsValidBinocularOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 2: + Oprand1 = OperandStack.pop () + Oprand2 = OperandStack.pop () + OperandStack.append (' ( {Oprand1} {Operator} {Oprand2} )'.format (Operator = Operator, Oprand1 = Oprand1, Oprand2 = Oprand2)) + else: + Msg = 'No enough Operands for {Opcode:02X}.'.format (Opcode = Opcode) + raise ValueError (Msg) + + else: + Msg = '{Opcode:02X} is not a valid OpCode.'.format (Opcode = Opcode) + raise ValueError (Msg) + + self.DepexExp = OperandStack[0].strip (' ') + self.Payload = Buffer[DepexLen:] + self._Valid = True + self._DepexSize = DepexLen + return self.Payload + + + def DumpInfo (self): + DepexLen = 0 + Opcode = None + Buffer = self.Depex + + if self._Valid == True: + print ('EFI_FIRMWARE_IMAGE_DEP.Dependencies = {') + while Opcode != 0x0D: + Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:]) + DepexLen += OperandSize + 1 + if Operand: + print (' {Opcode:02X}, {Operand},'.format (Opcode = Opcode, Operand = Operand)) + else: + print (' {Opcode:02X},'.format (Opcode = Opcode)) + print ('}') + + print ('sizeof (EFI_FIRMWARE_IMAGE_DEP.Dependencies) = {Size:08X}'.format (Size = self._DepexSize)) + print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload))) diff --git a/BaseTools/Source/Python/Common/buildoptions.py b/BaseTools/Source/Python/Common/buildoptions.py deleted file mode 100644 index a717c58d8c9..00000000000 --- a/BaseTools/Source/Python/Common/buildoptions.py +++ /dev/null @@ -1,93 +0,0 @@ -## @file -# build a platform or a module -# -# Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
-# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
-# Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.
-# -# SPDX-License-Identifier: BSD-2-Clause-Patent -# - -# Version and Copyright -from Common.BuildVersion import gBUILD_VERSION -from optparse import OptionParser -VersionNumber = "0.60" + ' ' + gBUILD_VERSION -__version__ = "%prog Version " + VersionNumber -__copyright__ = "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved." - -gParamCheck = [] -def SingleCheckCallback(option, opt_str, value, parser): - if option not in gParamCheck: - setattr(parser.values, option.dest, value) - gParamCheck.append(option) - else: - parser.error("Option %s only allows one instance in command line!" % option) - -def MyOptionParser(): - Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]") - Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch", - help="ARCHS is one of list: IA32, X64, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.") - Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback, - help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.") - Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback, - help="Build the module specified by the INF file name argument.") - Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.", - action="append") - Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain", - help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.") - Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback, - help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.") - - Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback, - help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. When value is set to 0, tool automatically detect number of "\ - "processor threads, set value to 1 means disable multi-thread build, and set value to more than 1 means user specify the threads number to build.") - - Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback, - help="The name of the FDF file to use, which overrides the setting in the DSC file.") - Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[], - help="The name of FD to be generated. The name must be from [FD] section in FDF file.") - Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[], - help="The name of FV to be generated. The name must be from [FV] section in FDF file.") - Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[], - help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.") - Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.") - Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.") - - Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.") - - Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.") - Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.") - - Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode", - help="Make use of silent mode of (n)make.") - Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.") - Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\ - "including library instances selected, final dependency expression, "\ - "and warning messages, etc.") - Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.") - Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".") - - Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.") - Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'HASH', 'EXECUTION_ORDER'], dest="ReportType", default=[], - help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER]. "\ - "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]") - Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag", - help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\ - "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\ - "will override the setting in [BuildOptions] section of platform DSC.") - Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism") - Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.") - Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.") - Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files") - Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ") - Parser.add_option("-l", "--cmd-len", action="store", type="int", dest="CommandLength", help="Specify the maximum line length of build command. Default is 4096.") - Parser.add_option("--hash", action="store_true", dest="UseHashCache", default=False, help="Enable hash-based caching during build process.") - Parser.add_option("--binary-destination", action="store", type="string", dest="BinCacheDest", help="Generate a cache of binary files in the specified directory.") - Parser.add_option("--binary-source", action="store", type="string", dest="BinCacheSource", help="Consume a cache of binary files from the specified directory.") - Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=True, help="Enable GenFds multi thread to generate ffs file.") - Parser.add_option("--no-genfds-multi-thread", action="store_true", dest="NoGenfdsMultiThread", default=False, help="Disable GenFds multi thread to generate ffs file.") - Parser.add_option("--disable-include-path-check", action="store_true", dest="DisableIncludePathCheck", default=False, help="Disable the include path check for outside of package.") - (Opt, Args) = Parser.parse_args() - return (Opt, Args) - -BuildOption, BuildTarget = MyOptionParser() diff --git a/BaseTools/Source/Python/Ecc/Check.py b/BaseTools/Source/Python/Ecc/Check.py index b68cecddfd4..0fdc7e35c18 100644 --- a/BaseTools/Source/Python/Ecc/Check.py +++ b/BaseTools/Source/Python/Ecc/Check.py @@ -1,7 +1,7 @@ ## @file # This file is used to define checkpoints used by ECC tool # -# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2008 - 2020, Intel Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent # from __future__ import absolute_import @@ -1469,13 +1469,14 @@ def NamingConventionCheckVariableName(self, FileTable): EdkLogger.quiet("Checking naming convention of variable name ...") Pattern = re.compile(r'^[A-Zgm]+\S*[a-z]\S*$') - SqlCommand = """select ID, Name from %s where Model = %s""" % (FileTable, MODEL_IDENTIFIER_VARIABLE) + SqlCommand = """select ID, Name, Modifier from %s where Model = %s""" % (FileTable, MODEL_IDENTIFIER_VARIABLE) RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand) for Record in RecordSet: Var = Record[1] + Modifier = Record[2] if Var.startswith('CONST'): Var = Var[5:].lstrip() - if not Pattern.match(Var): + if not Pattern.match(Var) and not (Modifier.endswith('*') and Var.startswith('p')): if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Record[1]): EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, OtherMsg="The variable name [%s] does not follow the rules" % (Record[1]), BelongsToTable=FileTable, BelongsToItem=Record[0]) diff --git a/BaseTools/Source/Python/GenFds/GenFds.py b/BaseTools/Source/Python/GenFds/GenFds.py index d8bc28e4d0f..d5511f4c40e 100644 --- a/BaseTools/Source/Python/GenFds/GenFds.py +++ b/BaseTools/Source/Python/GenFds/GenFds.py @@ -20,7 +20,7 @@ from io import BytesIO import Common.LongFilePathOs as os -from Common.TargetTxtClassObject import TargetTxt +from Common.TargetTxtClassObject import TargetTxtDict from Common.DataType import * import Common.GlobalData as GlobalData from Common import EdkLogger @@ -210,6 +210,8 @@ def GenFdsApi(FdsCommandDict, WorkSpaceDataBase=None): BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, "target.txt")) if os.path.isfile(BuildConfigurationFile) == True: # if no build target given in command line, get it from target.txt + TargetObj = TargetTxtDict() + TargetTxt = TargetObj.Target if not GenFdsGlobalVariable.TargetName: BuildTargetList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET] if len(BuildTargetList) != 1: diff --git a/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py b/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py index 6e1ff7fe04b..dc1727c4666 100644 --- a/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py +++ b/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py @@ -23,9 +23,9 @@ from Common import EdkLogger from Common.Misc import SaveFileOnChange -from Common.TargetTxtClassObject import TargetTxt -from Common.ToolDefClassObject import ToolDef -from AutoGen.BuildEngine import BuildRuleObj +from Common.TargetTxtClassObject import TargetTxtDict +from Common.ToolDefClassObject import ToolDefDict +from AutoGen.BuildEngine import ToolBuildRule import Common.DataType as DataType from Common.Misc import PathClass from Common.LongFilePathSupport import OpenLongFilePath as open @@ -96,12 +96,15 @@ class GenFdsGlobalVariable: def _LoadBuildRule(): if GenFdsGlobalVariable.__BuildRuleDatabase: return GenFdsGlobalVariable.__BuildRuleDatabase - GenFdsGlobalVariable.__BuildRuleDatabase = BuildRuleObj - ToolDefinitionFile = TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF] + BuildRule = ToolBuildRule() + GenFdsGlobalVariable.__BuildRuleDatabase = BuildRule.ToolBuildRule + TargetObj = TargetTxtDict() + ToolDefinitionFile = TargetObj.Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF] if ToolDefinitionFile == '': ToolDefinitionFile = "Conf/tools_def.txt" if os.path.isfile(ToolDefinitionFile): - ToolDefinition = ToolDef.ToolsDefTxtDatabase + ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf"))) + ToolDefinition = ToolDefObj.ToolDef.ToolsDefTxtDatabase if DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY in ToolDefinition \ and GenFdsGlobalVariable.ToolChainTag in ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY] \ and ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY][GenFdsGlobalVariable.ToolChainTag]: @@ -830,6 +833,8 @@ def GetPcdValue (PcdPattern): # @param NameGuid The Guid name # def FindExtendTool(KeyStringList, CurrentArchList, NameGuid): + ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf"))) + ToolDef = ToolDefObj.ToolDef ToolDb = ToolDef.ToolsDefTxtDatabase # if user not specify filter, try to deduce it from global data. if KeyStringList is None or KeyStringList == []: diff --git a/BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py b/BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py index 7d5e4fc34a3..d962ab0adda 100644 --- a/BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py +++ b/BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py @@ -49,20 +49,23 @@ def parsePcdInfoFromMapFile(mapfilepath, efifilepath): if len(lines) == 0: return None firstline = lines[0].strip() + if re.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', firstline): + return _parseForXcodeAndClang9(lines, efifilepath) if (firstline.startswith("Archive member included ") and firstline.endswith(" file (symbol)")): return _parseForGCC(lines, efifilepath) if firstline.startswith("# Path:"): - return _parseForXcode(lines, efifilepath) + return _parseForXcodeAndClang9(lines, efifilepath) return _parseGeneral(lines, efifilepath) -def _parseForXcode(lines, efifilepath): +def _parseForXcodeAndClang9(lines, efifilepath): valuePattern = re.compile('^([\da-fA-FxX]+)([\s\S]*)([_]*_gPcd_BinaryPatch_([\w]+))') status = 0 pcds = [] for line in lines: line = line.strip() - if status == 0 and line == "# Symbols:": + if status == 0 and (re.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', line) \ + or line == "# Symbols:"): status = 1 continue if status == 1 and len(line) != 0: diff --git a/BaseTools/Source/Python/Trim/Trim.py b/BaseTools/Source/Python/Trim/Trim.py index 24c3fafa76f..c5638376e41 100644 --- a/BaseTools/Source/Python/Trim/Trim.py +++ b/BaseTools/Source/Python/Trim/Trim.py @@ -56,6 +56,10 @@ gAslCIncludePattern = re.compile(r'^(\s*)#include\s*[<"]\s*([-\\/\w.]+)\s*([>"])', re.MULTILINE) ## Patterns used to convert EDK conventions to EDK2 ECP conventions +## Regular expression for finding header file inclusions +gIncludePattern = re.compile(r"^[ \t]*[%]?[ \t]*include(?:[ \t]*(?:\\(?:\r\n|\r|\n))*[ \t]*)*(?:\(?[\"<]?[ \t]*)([-\w.\\/() \t]+)(?:[ \t]*[\">]?\)?)", re.MULTILINE | re.UNICODE | re.IGNORECASE) + + ## file cache to avoid circular include in ASL file gIncludedAslFile = [] @@ -253,9 +257,10 @@ def TrimPreprocessedVfr(Source, Target): # first for the included file; otherwise, only the path specified # in the IncludePathList will be searched. # -def DoInclude(Source, Indent='', IncludePathList=[], LocalSearchPath=None): +def DoInclude(Source, Indent='', IncludePathList=[], LocalSearchPath=None, IncludeFileList = None, filetype=None): NewFileContent = [] - + if IncludeFileList is None: + IncludeFileList = [] try: # # Search LocalSearchPath first if it is specified. @@ -288,24 +293,37 @@ def DoInclude(Source, Indent='', IncludePathList=[], LocalSearchPath=None): ExtraData= "%s -> %s" % (" -> ".join(gIncludedAslFile), IncludeFile)) return [] gIncludedAslFile.append(IncludeFile) - + IncludeFileList.append(IncludeFile.strip()) for Line in F: LocalSearchPath = None - Result = gAslIncludePattern.findall(Line) - if len(Result) == 0: - Result = gAslCIncludePattern.findall(Line) - if len(Result) == 0 or os.path.splitext(Result[0][1])[1].lower() not in [".asl", ".asi"]: + if filetype == "ASL": + Result = gAslIncludePattern.findall(Line) + if len(Result) == 0: + Result = gAslCIncludePattern.findall(Line) + if len(Result) == 0 or os.path.splitext(Result[0][1])[1].lower() not in [".asl", ".asi"]: + NewFileContent.append("%s%s" % (Indent, Line)) + continue + # + # We should first search the local directory if current file are using pattern #include "XXX" + # + if Result[0][2] == '"': + LocalSearchPath = os.path.dirname(IncludeFile) + CurrentIndent = Indent + Result[0][0] + IncludedFile = Result[0][1] + NewFileContent.extend(DoInclude(IncludedFile, CurrentIndent, IncludePathList, LocalSearchPath,IncludeFileList,filetype)) + NewFileContent.append("\n") + elif filetype == "ASM": + Result = gIncludePattern.findall(Line) + if len(Result) == 0: NewFileContent.append("%s%s" % (Indent, Line)) continue - # - # We should first search the local directory if current file are using pattern #include "XXX" - # - if Result[0][2] == '"': - LocalSearchPath = os.path.dirname(IncludeFile) - CurrentIndent = Indent + Result[0][0] - IncludedFile = Result[0][1] - NewFileContent.extend(DoInclude(IncludedFile, CurrentIndent, IncludePathList, LocalSearchPath)) - NewFileContent.append("\n") + + IncludedFile = Result[0] + + IncludedFile = IncludedFile.strip() + IncludedFile = os.path.normpath(IncludedFile) + NewFileContent.extend(DoInclude(IncludedFile, '', IncludePathList, LocalSearchPath,IncludeFileList,filetype)) + NewFileContent.append("\n") gIncludedAslFile.pop() @@ -320,7 +338,7 @@ def DoInclude(Source, Indent='', IncludePathList=[], LocalSearchPath=None): # @param Target File to store the trimmed content # @param IncludePathFile The file to log the external include path # -def TrimAslFile(Source, Target, IncludePathFile): +def TrimAslFile(Source, Target, IncludePathFile,AslDeps = False): CreateDirectory(os.path.dirname(Target)) SourceDir = os.path.dirname(Source) @@ -349,8 +367,11 @@ def TrimAslFile(Source, Target, IncludePathFile): EdkLogger.warn("Trim", "Invalid include line in include list file.", IncludePathFile, LineNum) except: EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=IncludePathFile) - - Lines = DoInclude(Source, '', IncludePathList) + AslIncludes = [] + Lines = DoInclude(Source, '', IncludePathList,IncludeFileList=AslIncludes,filetype='ASL') + AslIncludes = [item for item in AslIncludes if item !=Source] + if AslDeps and AslIncludes: + SaveFileOnChange(os.path.join(os.path.dirname(Target),os.path.basename(Source))+".trim.deps", " \\\n".join([Source+":"] +AslIncludes),False) # # Undef MIN and MAX to avoid collision in ASL source code @@ -364,6 +385,54 @@ def TrimAslFile(Source, Target, IncludePathFile): except: EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=Target) +## Trim ASM file +# +# Output ASM include statement with the content the included file +# +# @param Source File to be trimmed +# @param Target File to store the trimmed content +# @param IncludePathFile The file to log the external include path +# +def TrimAsmFile(Source, Target, IncludePathFile): + CreateDirectory(os.path.dirname(Target)) + + SourceDir = os.path.dirname(Source) + if SourceDir == '': + SourceDir = '.' + + # + # Add source directory as the first search directory + # + IncludePathList = [SourceDir] + # + # If additional include path file is specified, append them all + # to the search directory list. + # + if IncludePathFile: + try: + LineNum = 0 + with open(IncludePathFile, 'r') as File: + FileLines = File.readlines() + for Line in FileLines: + LineNum += 1 + if Line.startswith("/I") or Line.startswith ("-I"): + IncludePathList.append(Line[2:].strip()) + else: + EdkLogger.warn("Trim", "Invalid include line in include list file.", IncludePathFile, LineNum) + except: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=IncludePathFile) + AsmIncludes = [] + Lines = DoInclude(Source, '', IncludePathList,IncludeFileList=AsmIncludes,filetype='ASM') + AsmIncludes = [item for item in AsmIncludes if item != Source] + if AsmIncludes: + SaveFileOnChange(os.path.join(os.path.dirname(Target),os.path.basename(Source))+".trim.deps", " \\\n".join([Source+":"] +AsmIncludes),False) + # save all lines trimmed + try: + with open(Target, 'w') as File: + File.writelines(Lines) + except: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=Target) + def GenerateVfrBinSec(ModuleName, DebugDir, OutputFile): VfrNameList = [] if os.path.isdir(DebugDir): @@ -440,8 +509,12 @@ def Options(): help="The input file is preprocessed VFR file"), make_option("--Vfr-Uni-Offset", dest="FileType", const="VfrOffsetBin", action="store_const", help="The input file is EFI image"), + make_option("--asl-deps", dest="AslDeps", const="True", action="store_const", + help="Generate Asl dependent files."), make_option("-a", "--asl-file", dest="FileType", const="Asl", action="store_const", help="The input file is ASL file"), + make_option( "--asm-file", dest="FileType", const="Asm", action="store_const", + help="The input file is asm file"), make_option("-c", "--convert-hex", dest="ConvertHex", action="store_true", help="Convert standard hex format (0xabcd) to MASM format (abcdh)"), @@ -515,9 +588,11 @@ def Main(): elif CommandOptions.FileType == "Asl": if CommandOptions.OutputFile is None: CommandOptions.OutputFile = os.path.splitext(InputFile)[0] + '.iii' - TrimAslFile(InputFile, CommandOptions.OutputFile, CommandOptions.IncludePathFile) + TrimAslFile(InputFile, CommandOptions.OutputFile, CommandOptions.IncludePathFile,CommandOptions.AslDeps) elif CommandOptions.FileType == "VfrOffsetBin": GenerateVfrBinSec(CommandOptions.ModuleName, CommandOptions.DebugDir, CommandOptions.OutputFile) + elif CommandOptions.FileType == "Asm": + TrimAsmFile(InputFile, CommandOptions.OutputFile, CommandOptions.IncludePathFile) else : if CommandOptions.OutputFile is None: CommandOptions.OutputFile = os.path.splitext(InputFile)[0] + '.iii' diff --git a/BaseTools/Source/Python/Workspace/DscBuildData.py b/BaseTools/Source/Python/Workspace/DscBuildData.py index 9192077f906..c65a0dd346e 100644 --- a/BaseTools/Source/Python/Workspace/DscBuildData.py +++ b/BaseTools/Source/Python/Workspace/DscBuildData.py @@ -19,8 +19,8 @@ from types import * from Common.Expression import * from CommonDataClass.CommonClass import SkuInfoClass -from Common.TargetTxtClassObject import TargetTxt -from Common.ToolDefClassObject import ToolDef +from Common.TargetTxtClassObject import TargetTxtDict +from Common.ToolDefClassObject import ToolDefDict from .MetaDataTable import * from .MetaFileTable import * from .MetaFileParser import * @@ -719,6 +719,24 @@ def OverrideDuplicateModule(self): self._RawData.DisableOverrideComponent(Components[(file_guid_str,str(ModuleFile))]) Components[(file_guid_str,str(ModuleFile))] = ModuleId self._RawData._PostProcessed = False + + ## Retrieve packages this Platform depends on + @cached_property + def Packages(self): + RetVal = set() + RecordList = self._RawData[MODEL_META_DATA_PACKAGE, self._Arch] + Macros = self._Macros + for Record in RecordList: + File = PathClass(NormPath(Record[0], Macros), GlobalData.gWorkspace, Arch=self._Arch) + # check the file validation + ErrorCode, ErrorInfo = File.Validate('.dec') + if ErrorCode != 0: + LineNo = Record[-1] + EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo) + # parse this package now. we need it to get protocol/ppi/guid value + RetVal.add(self._Bdb[File, self._Arch, self._Target, self._Toolchain]) + return RetVal + ## Retrieve [Components] section information @property def Modules(self): @@ -896,7 +914,8 @@ def _ValidatePcd(self, PcdCName, TokenSpaceGuid, Setting, PcdType, LineNo): continue ModuleData = self._Bdb[ModuleFile, self._Arch, self._Target, self._Toolchain] PkgSet.update(ModuleData.Packages) - + if self.Packages: + PkgSet.update(self.Packages) self._DecPcds, self._GuidDict = GetDeclaredPcd(self, self._Bdb, self._Arch, self._Target, self._Toolchain, PkgSet) self._GuidDict.update(GlobalData.gPlatformPcds) @@ -3277,6 +3296,8 @@ def AddModule(self, FilePath): @property def ToolChainFamily(self): self._ToolChainFamily = TAB_COMPILER_MSFT + TargetObj = TargetTxtDict() + TargetTxt = TargetObj.Target BuildConfigurationFile = os.path.normpath(os.path.join(GlobalData.gConfDirectory, "target.txt")) if os.path.isfile(BuildConfigurationFile) == True: ToolDefinitionFile = TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF] @@ -3284,7 +3305,8 @@ def ToolChainFamily(self): ToolDefinitionFile = "tools_def.txt" ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile)) if os.path.isfile(ToolDefinitionFile) == True: - ToolDefinition = ToolDef.ToolsDefTxtDatabase + ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf"))) + ToolDefinition = ToolDefObj.ToolDef.ToolsDefTxtDatabase if TAB_TOD_DEFINES_FAMILY not in ToolDefinition \ or self._Toolchain not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \ or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][self._Toolchain]: @@ -3320,6 +3342,8 @@ def DecPcds(self): continue ModuleData = self._Bdb[ModuleFile, self._Arch, self._Target, self._Toolchain] PkgSet.update(ModuleData.Packages) + if self.Packages: + PkgSet.update(self.Packages) self._DecPcds, self._GuidDict = GetDeclaredPcd(self, self._Bdb, self._Arch, self._Target, self._Toolchain, PkgSet) self._GuidDict.update(GlobalData.gPlatformPcds) return self._DecPcds diff --git a/BaseTools/Source/Python/Workspace/MetaFileParser.py b/BaseTools/Source/Python/Workspace/MetaFileParser.py index 806fc322c56..a3b6edbd15e 100644 --- a/BaseTools/Source/Python/Workspace/MetaFileParser.py +++ b/BaseTools/Source/Python/Workspace/MetaFileParser.py @@ -160,6 +160,7 @@ def __init__(self, FilePath, FileType, Arch, Table, Owner= -1, From= -1): self.MetaFile = FilePath self._FileDir = self.MetaFile.Dir self._Defines = {} + self._Packages = [] self._FileLocalMacros = {} self._SectionsMacroDict = defaultdict(dict) @@ -328,6 +329,7 @@ def _SectionHeaderParser(self): S1 = ItemList[1].upper() else: S1 = TAB_ARCH_COMMON + S1 = ReplaceMacro(S1, self._Macros) ArchList.add(S1) # S2 may be Platform or ModuleType @@ -351,6 +353,13 @@ def _SectionHeaderParser(self): # If the section information is needed later, it should be stored in database self._ValueList[0] = self._SectionName + ## [packages] section parser + @ParseMacro + def _PackageParser(self): + self._CurrentLine = CleanString(self._CurrentLine) + self._Packages.append(self._CurrentLine) + self._ValueList[0] = self._CurrentLine + ## [defines] section parser @ParseMacro def _DefineParser(self): @@ -848,6 +857,7 @@ class DscParser(MetaFileParser): TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE, TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS, TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION, + TAB_PACKAGES.upper() : MODEL_META_DATA_PACKAGE, TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : MODEL_PCD_FIXED_AT_BUILD, TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : MODEL_PCD_PATCHABLE_IN_MODULE, TAB_PCDS_FEATURE_FLAG_NULL.upper() : MODEL_PCD_FEATURE_FLAG, @@ -1339,6 +1349,7 @@ def _PostProcess(self): MODEL_META_DATA_DEFINE : self.__ProcessDefine, MODEL_META_DATA_GLOBAL_DEFINE : self.__ProcessDefine, MODEL_META_DATA_INCLUDE : self.__ProcessDirective, + MODEL_META_DATA_PACKAGE : self.__ProcessPackages, MODEL_META_DATA_CONDITIONAL_STATEMENT_IF : self.__ProcessDirective, MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE : self.__ProcessDirective, MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF : self.__ProcessDirective, @@ -1601,46 +1612,50 @@ def __ProcessDirective(self): # First search the include file under the same directory as DSC file # IncludedFile1 = PathClass(IncludedFile, self.MetaFile.Dir) - ErrorCode, ErrorInfo1 = IncludedFile1.Validate() - if ErrorCode != 0: - # - # Also search file under the WORKSPACE directory - # - IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace) - ErrorCode, ErrorInfo2 = IncludedFile1.Validate() + if self._Enabled: + ErrorCode, ErrorInfo1 = IncludedFile1.Validate() if ErrorCode != 0: - EdkLogger.error('parser', ErrorCode, File=self._FileWithError, - Line=self._LineIndex + 1, ExtraData=ErrorInfo1 + "\n" + ErrorInfo2) - - self._FileWithError = IncludedFile1 + # + # Also search file under the WORKSPACE directory + # + IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace) + ErrorCode, ErrorInfo2 = IncludedFile1.Validate() + if ErrorCode != 0: + EdkLogger.error('parser', ErrorCode, File=self._FileWithError, + Line=self._LineIndex + 1, ExtraData=ErrorInfo1 + "\n" + ErrorInfo2) + + self._FileWithError = IncludedFile1 + + FromItem = self._Content[self._ContentIndex - 1][0] + if self._InSubsection: + Owner = self._Content[self._ContentIndex - 1][8] + else: + Owner = self._Content[self._ContentIndex - 1][0] + IncludedFileTable = MetaFileStorage(self._RawTable.DB, IncludedFile1, MODEL_FILE_DSC, False, FromItem=FromItem) + Parser = DscParser(IncludedFile1, self._FileType, self._Arch, IncludedFileTable, + Owner=Owner, From=FromItem) + + self.IncludedFiles.add (IncludedFile1) + + # set the parser status with current status + Parser._SectionName = self._SectionName + Parser._SubsectionType = self._SubsectionType + Parser._InSubsection = self._InSubsection + Parser._SectionType = self._SectionType + Parser._Scope = self._Scope + Parser._Enabled = self._Enabled + # Parse the included file + Parser.StartParse() + # Insert all records in the table for the included file into dsc file table + Records = IncludedFileTable.GetAll() + if Records: + self._Content[self._ContentIndex:self._ContentIndex] = Records + self._Content.pop(self._ContentIndex - 1) + self._ValueList = None + self._ContentIndex -= 1 - FromItem = self._Content[self._ContentIndex - 1][0] - if self._InSubsection: - Owner = self._Content[self._ContentIndex - 1][8] - else: - Owner = self._Content[self._ContentIndex - 1][0] - IncludedFileTable = MetaFileStorage(self._RawTable.DB, IncludedFile1, MODEL_FILE_DSC, False, FromItem=FromItem) - Parser = DscParser(IncludedFile1, self._FileType, self._Arch, IncludedFileTable, - Owner=Owner, From=FromItem) - - self.IncludedFiles.add (IncludedFile1) - - # set the parser status with current status - Parser._SectionName = self._SectionName - Parser._SubsectionType = self._SubsectionType - Parser._InSubsection = self._InSubsection - Parser._SectionType = self._SectionType - Parser._Scope = self._Scope - Parser._Enabled = self._Enabled - # Parse the included file - Parser.StartParse() - # Insert all records in the table for the included file into dsc file table - Records = IncludedFileTable.GetAll() - if Records: - self._Content[self._ContentIndex:self._ContentIndex] = Records - self._Content.pop(self._ContentIndex - 1) - self._ValueList = None - self._ContentIndex -= 1 + def __ProcessPackages(self): + self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros) def __ProcessSkuId(self): self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=True) @@ -1720,6 +1735,7 @@ def DisableOverrideComponent(self,module_id): MODEL_META_DATA_COMPONENT : _ComponentParser, MODEL_META_DATA_BUILD_OPTION : _BuildOptionParser, MODEL_UNKNOWN : MetaFileParser._Skip, + MODEL_META_DATA_PACKAGE : MetaFileParser._PackageParser, MODEL_META_DATA_USER_EXTENSION : MetaFileParser._SkipUserExtension, MODEL_META_DATA_SECTION_HEADER : MetaFileParser._SectionHeaderParser, MODEL_META_DATA_SUBSECTION_HEADER : _SubsectionHeaderParser, diff --git a/BaseTools/Source/Python/Workspace/WorkspaceCommon.py b/BaseTools/Source/Python/Workspace/WorkspaceCommon.py index 0b11ec2d597..913e710fd9f 100644 --- a/BaseTools/Source/Python/Workspace/WorkspaceCommon.py +++ b/BaseTools/Source/Python/Workspace/WorkspaceCommon.py @@ -37,6 +37,8 @@ def __missing__(self, key): # def GetPackageList(Platform, BuildDatabase, Arch, Target, Toolchain): PkgSet = set() + if Platform.Packages: + PkgSet.update(Platform.Packages) for ModuleFile in Platform.Modules: Data = BuildDatabase[ModuleFile, Arch, Target, Toolchain] PkgSet.update(Data.Packages) diff --git a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py index ab7b4506c1c..9420eaa608e 100644 --- a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py +++ b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py @@ -186,6 +186,10 @@ def GetPackageList(self, Platform, Arch, TargetName, ToolChainTag): for Package in LibObj.Packages: if Package not in PackageList: PackageList.append(Package) + for Package in Pa.Packages: + if Package in PackageList: + continue + PackageList.append(Package) return PackageList diff --git a/BaseTools/Source/Python/basetool_tiano_python_path_env.yaml b/BaseTools/Source/Python/basetool_tiano_python_path_env.yaml new file mode 100644 index 00000000000..59369ccc657 --- /dev/null +++ b/BaseTools/Source/Python/basetool_tiano_python_path_env.yaml @@ -0,0 +1,11 @@ +## @file +# Add this folder to the pypath so modules can be easily +# loaded +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "global", + "flags": ["set_pypath"] +} diff --git a/BaseTools/Source/Python/build/build.py b/BaseTools/Source/Python/build/build.py index bcd832c525f..34acdccbdbd 100755 --- a/BaseTools/Source/Python/build/build.py +++ b/BaseTools/Source/Python/build/build.py @@ -24,9 +24,9 @@ import multiprocessing from threading import Thread,Event,BoundedSemaphore import threading -from subprocess import Popen,PIPE +from subprocess import Popen,PIPE, STDOUT from collections import OrderedDict, defaultdict -from Common.buildoptions import BuildOption,BuildTarget + from AutoGen.PlatformAutoGen import PlatformAutoGen from AutoGen.ModuleAutoGen import ModuleAutoGen from AutoGen.WorkspaceAutoGen import WorkspaceAutoGen @@ -35,8 +35,9 @@ from AutoGen import GenMake from Common import Misc as Utils -from Common.TargetTxtClassObject import TargetTxt -from Common.ToolDefClassObject import ToolDef +from Common.TargetTxtClassObject import TargetTxtDict +from Common.ToolDefClassObject import ToolDefDict +from buildoptions import MyOptionParser from Common.Misc import PathClass,SaveFileOnChange,RemoveDirectory from Common.StringUtils import NormPath from Common.MultipleWorkspace import MultipleWorkspace as mws @@ -57,7 +58,8 @@ from AutoGen.DataPipe import MemoryDataPipe from AutoGen.ModuleAutoGenHelper import WorkSpaceInfo, PlatformInfo from GenFds.FdfParser import FdfParser - +from AutoGen.IncludesAutoGen import IncludesAutoGen +from GenFds.GenFds import resetFdsGlobalVariable ## standard targets of build command gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run'] @@ -175,18 +177,31 @@ def NormFile(FilePath, Workspace): # @param To The stream message put on # @param ExitFlag The flag used to indicate stopping reading # -def ReadMessage(From, To, ExitFlag): +def ReadMessage(From, To, ExitFlag,MemTo=None): while True: # read one line a time Line = From.readline() # empty string means "end" if Line is not None and Line != b"": - To(Line.rstrip().decode(encoding='utf-8', errors='ignore')) + LineStr = Line.rstrip().decode(encoding='utf-8', errors='ignore') + if MemTo is not None: + if "Note: including file:" == LineStr.lstrip()[:21]: + MemTo.append(LineStr) + else: + To(LineStr) + MemTo.append(LineStr) + else: + To(LineStr) else: break if ExitFlag.isSet(): break +class MakeSubProc(Popen): + def __init__(self,*args, **argv): + super(MakeSubProc,self).__init__(*args, **argv) + self.ProcOut = [] + ## Launch an external program # # This method will call subprocess.Popen to execute an external program with @@ -197,7 +212,7 @@ def ReadMessage(From, To, ExitFlag): # @param Command A list or string containing the call of the program # @param WorkingDir The directory in which the program will be running # -def LaunchCommand(Command, WorkingDir): +def LaunchCommand(Command, WorkingDir,ModuleAuto = None): BeginTime = time.time() # if working directory doesn't exist, Popen() will raise an exception if not os.path.isdir(WorkingDir): @@ -216,22 +231,17 @@ def LaunchCommand(Command, WorkingDir): EndOfProcedure = None try: # launch the command - Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True) + Proc = MakeSubProc(Command, stdout=PIPE, stderr=STDOUT, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True) # launch two threads to read the STDOUT and STDERR EndOfProcedure = Event() EndOfProcedure.clear() if Proc.stdout: - StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure)) + StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure,Proc.ProcOut)) StdOutThread.setName("STDOUT-Redirector") StdOutThread.setDaemon(False) StdOutThread.start() - if Proc.stderr: - StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure)) - StdErrThread.setName("STDERR-Redirector") - StdErrThread.setDaemon(False) - StdErrThread.start() # waiting for program exit Proc.wait() @@ -247,8 +257,6 @@ def LaunchCommand(Command, WorkingDir): if Proc.stdout: StdOutThread.join() - if Proc.stderr: - StdErrThread.join() # check the return code of the program if Proc.returncode != 0: @@ -263,6 +271,15 @@ def LaunchCommand(Command, WorkingDir): EdkLogger.info(RespContent) EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir)) + if ModuleAuto: + iau = IncludesAutoGen(WorkingDir,ModuleAuto) + if ModuleAuto.ToolChainFamily == TAB_COMPILER_MSFT: + iau.CreateDepsFileForMsvc(Proc.ProcOut) + else: + iau.UpdateDepsFileforNonMsvc() + iau.UpdateDepsFileforTrim() + iau.CreateModuleDeps() + iau.CreateDepsInclude() return "%dms" % (int(round((time.time() - BeginTime) * 1000))) ## The smallest unit that can be built in multi-thread build mode @@ -598,7 +615,7 @@ def IsReady(self): # def AddDependency(self, Dependency): for Dep in Dependency: - if not Dep.BuildObject.IsBinaryModule and not Dep.BuildObject.CanSkipbyCache(GlobalData.gCacheIR): + if not Dep.BuildObject.IsBinaryModule and not Dep.BuildObject.CanSkipbyCache(GlobalData.gModuleCacheHit): self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list ## The thread wrapper of LaunchCommand function @@ -608,13 +625,16 @@ def AddDependency(self, Dependency): # def _CommandThread(self, Command, WorkingDir): try: - self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir) + self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir,self.BuildItem.BuildObject) self.CompleteFlag = True - # Run hash operation post dependency, to account for libs - if GlobalData.gUseHashCache and self.BuildItem.BuildObject.IsLibrary: - HashFile = path.join(self.BuildItem.BuildObject.BuildDir, self.BuildItem.BuildObject.Name + ".hash") - SaveFileOnChange(HashFile, self.BuildItem.BuildObject.GenModuleHash(), True) + # Run hash operation post dependency to account for libs + # Run if --hash or --binary-destination + if GlobalData.gUseHashCache and not GlobalData.gBinCacheSource: + self.BuildItem.BuildObject.GenModuleHash() + if GlobalData.gBinCacheDest: + self.BuildItem.BuildObject.GenCMakeHash() + except: # # TRICK: hide the output of threads left running, so that the user can @@ -631,14 +651,6 @@ def _CommandThread(self, Command, WorkingDir): BuildTask._ErrorMessage = "%s broken\n %s [%s]" % \ (threading.currentThread().getName(), Command, WorkingDir) - # Set the value used by hash invalidation flow in GlobalData.gModuleBuildTracking to 'SUCCESS' - # If Module or Lib is being tracked, it did not fail header check test, and built successfully - if (self.BuildItem.BuildObject in GlobalData.gModuleBuildTracking and - GlobalData.gModuleBuildTracking[self.BuildItem.BuildObject] != 'FAIL_METAFILE' and - not BuildTask._ErrorFlag.isSet() - ): - GlobalData.gModuleBuildTracking[self.BuildItem.BuildObject] = 'SUCCESS' - # indicate there's a thread is available for another build task BuildTask._RunningQueueLock.acquire() BuildTask._RunningQueue.pop(self.BuildItem) @@ -720,11 +732,13 @@ def __init__(self, Target, WorkspaceDir, BuildOptions,log_q): self.ConfDirectory = BuildOptions.ConfDirectory self.SpawnMode = True self.BuildReport = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType) - self.TargetTxt = TargetTxt - self.ToolDef = ToolDef self.AutoGenTime = 0 self.MakeTime = 0 self.GenFdsTime = 0 + TargetObj = TargetTxtDict() + ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"),"Conf"))) + self.TargetTxt = TargetObj.Target + self.ToolDef = ToolDefObj.ToolDef GlobalData.BuildOptionPcd = BuildOptions.OptionPcd if BuildOptions.OptionPcd else [] #Set global flag for build mode GlobalData.gIgnoreSource = BuildOptions.IgnoreSources @@ -805,19 +819,30 @@ def __init__(self, Target, WorkspaceDir, BuildOptions,log_q): EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild)) if self.Prebuild: self.LaunchPrebuild() - self.TargetTxt = TargetTxt - self.ToolDef = ToolDef + TargetObj = TargetTxtDict() + ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf"))) + self.TargetTxt = TargetObj.Target + self.ToolDef = ToolDefObj.ToolDef if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)): self.InitBuild() self.AutoGenMgr = None EdkLogger.info("") os.chdir(self.WorkspaceDir) - GlobalData.gCacheIR = Manager().dict() self.log_q = log_q GlobalData.file_lock = mp.Lock() - GlobalData.cache_lock = mp.Lock() - def StartAutoGen(self,mqueue, DataPipe,SkipAutoGen,PcdMaList,share_data): + # Init cache data for local only + GlobalData.gPackageHashFile = dict() + GlobalData.gModulePreMakeCacheStatus = dict() + GlobalData.gModuleMakeCacheStatus = dict() + GlobalData.gHashChainStatus = dict() + GlobalData.gCMakeHashFile = dict() + GlobalData.gModuleHashFile = dict() + GlobalData.gFileHashDict = dict() + GlobalData.gModuleAllCacheStatus = set() + GlobalData.gModuleCacheHit = set() + + def StartAutoGen(self,mqueue, DataPipe,SkipAutoGen,PcdMaList,cqueue): try: if SkipAutoGen: return True,0 @@ -827,29 +852,27 @@ def StartAutoGen(self,mqueue, DataPipe,SkipAutoGen,PcdMaList,share_data): if FfsCmd is None: FfsCmd = {} GlobalData.FfsCmd = FfsCmd - GlobalData.libConstPcd = DataPipe.Get("LibConstPcd") - GlobalData.Refes = DataPipe.Get("REFS") - auto_workers = [AutoGenWorkerInProcess(mqueue,DataPipe.dump_file,feedback_q,GlobalData.file_lock,GlobalData.cache_lock,share_data,self.log_q,error_event) for _ in range(self.ThreadNumber)] + auto_workers = [AutoGenWorkerInProcess(mqueue,DataPipe.dump_file,feedback_q,GlobalData.file_lock,cqueue,self.log_q,error_event) for _ in range(self.ThreadNumber)] self.AutoGenMgr = AutoGenManager(auto_workers,feedback_q,error_event) self.AutoGenMgr.start() for w in auto_workers: w.start() if PcdMaList is not None: for PcdMa in PcdMaList: - if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]: - PcdMa.GenModuleFilesHash(share_data) - PcdMa.GenPreMakefileHash(share_data) - if PcdMa.CanSkipbyPreMakefileCache(share_data): - continue + # SourceFileList calling sequence impact the makefile string sequence. + # Create cached SourceFileList here to unify its calling sequence for both + # CanSkipbyPreMakeCache and CreateCodeFile/CreateMakeFile. + RetVal = PcdMa.SourceFileList + # Force cache miss for PCD driver + if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and self.Target in [None, "", "all"]: + cqueue.put((PcdMa.MetaFile.Path, PcdMa.Arch, "PreMakeCache", False)) PcdMa.CreateCodeFile(False) PcdMa.CreateMakeFile(False,GenFfsList = DataPipe.Get("FfsCommand").get((PcdMa.MetaFile.Path, PcdMa.Arch),[])) + # Force cache miss for PCD driver if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]: - PcdMa.GenMakeHeaderFilesHash(share_data) - PcdMa.GenMakeHash(share_data) - if PcdMa.CanSkipbyMakeCache(share_data): - continue + cqueue.put((PcdMa.MetaFile.Path, PcdMa.Arch, "MakeCache", False)) self.AutoGenMgr.join() rt = self.AutoGenMgr.Status @@ -1160,38 +1183,6 @@ def LaunchPostbuild(self): EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!') EdkLogger.info("\n- Postbuild Done -\n") - ## Error handling for hash feature - # - # On BuildTask error, iterate through the Module Build tracking - # dictionary to determine wheather a module failed to build. Invalidate - # the hash associated with that module by removing it from storage. - # - # - def invalidateHash(self): - # Only for hashing feature - if not GlobalData.gUseHashCache: - return - - # GlobalData.gModuleBuildTracking contains only modules or libs that cannot be skipped by hash - for Ma in GlobalData.gModuleBuildTracking: - # Skip invalidating for Successful Module/Lib builds - if GlobalData.gModuleBuildTracking[Ma] == 'SUCCESS': - continue - - # The module failed to build, failed to start building, or failed the header check test from this point on - - # Remove .hash from build - ModuleHashFile = os.path.join(Ma.BuildDir, Ma.Name + ".hash") - if os.path.exists(ModuleHashFile): - os.remove(ModuleHashFile) - - # Remove .hash file from cache - if GlobalData.gBinCacheDest: - FileDir = os.path.join(GlobalData.gBinCacheDest, Ma.PlatformInfo.OutputDir, Ma.BuildTarget + "_" + Ma.ToolChain, Ma.Arch, Ma.SourceDir, Ma.MetaFile.BaseName) - HashFile = os.path.join(FileDir, Ma.Name + '.hash') - if os.path.exists(HashFile): - os.remove(HashFile) - ## Build a module or platform # # Create autogen code and makefile for a module or platform, and the launch @@ -1229,7 +1220,8 @@ def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMak self.Progress.Start("Generating makefile and code") data_pipe_file = os.path.join(AutoGenObject.BuildDir, "GlobalVar_%s_%s.bin" % (str(AutoGenObject.Guid),AutoGenObject.Arch)) AutoGenObject.DataPipe.dump(data_pipe_file) - autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList, GlobalData.gCacheIR) + cqueue = mp.Queue() + autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList, cqueue) AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt") with open(AutoGenIdFile,"w") as fw: fw.write("Arch=%s\n" % "|".join((AutoGenObject.Workspace.ArchList))) @@ -1270,28 +1262,49 @@ def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMak LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir) self.CreateAsBuiltInf() if GlobalData.gBinCacheDest: - self.UpdateBuildCache() + self.GenDestCache() + elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource: + # Only for --hash + # Update PreMakeCacheChain files + self.GenLocalPreMakeCache() self.BuildModules = [] return True # build library if Target == 'libraries': - for Lib in AutoGenObject.LibraryBuildDirectoryList: + DirList = [] + for Lib in AutoGenObject.LibraryAutoGenList: + if not Lib.IsBinaryModule: + DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib)) + for Lib, LibAutoGen in DirList: NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild'] - LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) + LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen) return True # build module if Target == 'modules': - for Lib in AutoGenObject.LibraryBuildDirectoryList: + DirList = [] + for Lib in AutoGenObject.LibraryAutoGenList: + if not Lib.IsBinaryModule: + DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib)) + for Lib, LibAutoGen in DirList: NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild'] - LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) - for Mod in AutoGenObject.ModuleBuildDirectoryList: + LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen) + + DirList = [] + for ModuleAutoGen in AutoGenObject.ModuleAutoGenList: + if not ModuleAutoGen.IsBinaryModule: + DirList.append((os.path.join(AutoGenObject.BuildDir, ModuleAutoGen.BuildDir),ModuleAutoGen)) + for Mod,ModAutoGen in DirList: NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild'] - LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) + LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,ModAutoGen) self.CreateAsBuiltInf() if GlobalData.gBinCacheDest: - self.UpdateBuildCache() + self.GenDestCache() + elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource: + # Only for --hash + # Update PreMakeCacheChain files + self.GenLocalPreMakeCache() self.BuildModules = [] return True @@ -1387,7 +1400,11 @@ def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeF AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir) self.CreateAsBuiltInf() if GlobalData.gBinCacheDest: - self.UpdateBuildCache() + self.GenDestCache() + elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource: + # Only for --hash + # Update PreMakeCacheChain files + self.GenLocalPreMakeCache() self.BuildModules = [] return True @@ -1835,13 +1852,7 @@ def _BuildModule(self): if GlobalData.gEnableGenfdsMultiThread and self.Fdf: CmdListDict = self._GenFfsCmd(Wa.ArchList) - # Add Platform and Package level hash in share_data for module hash calculation later - if GlobalData.gBinCacheSource or GlobalData.gBinCacheDest: - GlobalData.gCacheIR[('PlatformHash')] = GlobalData.gPlatformHash - for PkgName in GlobalData.gPackageHash.keys(): - GlobalData.gCacheIR[(PkgName, 'PackageHash')] = GlobalData.gPackageHash[PkgName] GlobalData.file_lock = mp.Lock() - GlobalData.cache_lock = mp.Lock() GlobalData.FfsCmd = CmdListDict self.Progress.Stop("done!") @@ -1853,8 +1864,6 @@ def _BuildModule(self): AutoGenStart = time.time() GlobalData.gGlobalDefines['ARCH'] = Arch Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch) - GlobalData.libConstPcd = Pa.DataPipe.Get("LibConstPcd") - GlobalData.Refes = Pa.DataPipe.Get("REFS") for Module in Pa.Platform.Modules: if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name: Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe) @@ -1865,13 +1874,11 @@ def _BuildModule(self): Ma.Workspace = Wa MaList.append(Ma) - if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]: - Ma.GenModuleFilesHash(GlobalData.gCacheIR) - Ma.GenPreMakefileHash(GlobalData.gCacheIR) - if Ma.CanSkipbyPreMakefileCache(GlobalData.gCacheIR): - self.HashSkipModules.append(Ma) - EdkLogger.quiet("cache hit: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch)) + if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and self.Target in [None, "", "all"]: + if Ma.CanSkipbyPreMakeCache(): continue + else: + self.PreMakeCacheMiss.add(Ma) # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds' if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']: @@ -1894,19 +1901,12 @@ def _BuildModule(self): return True if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]: - Ma.GenMakeHeaderFilesHash(GlobalData.gCacheIR) - Ma.GenMakeHash(GlobalData.gCacheIR) - if Ma.CanSkipbyMakeCache(GlobalData.gCacheIR): - self.HashSkipModules.append(Ma) - EdkLogger.quiet("cache hit: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch)) + if Ma.CanSkipbyMakeCache(): continue else: - EdkLogger.quiet("cache miss: %s[%s]" % (Ma.MetaFile.Path, Ma.Arch)) - Ma.PrintFirstMakeCacheMissFile(GlobalData.gCacheIR) + self.MakeCacheMiss.add(Ma) self.BuildModules.append(Ma) - # Initialize all modules in tracking to 'FAIL' - GlobalData.gModuleBuildTracking[Ma] = 'FAIL' self.AutoGenTime += int(round((time.time() - AutoGenStart))) MakeStart = time.time() for Ma in self.BuildModules: @@ -1917,7 +1917,6 @@ def _BuildModule(self): # we need a full version of makefile for platform ExitFlag.set() BuildTask.WaitForComplete() - self.invalidateHash() Pa.CreateMakeFile(False) EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule) # Start task scheduler @@ -1927,7 +1926,6 @@ def _BuildModule(self): # in case there's an interruption. we need a full version of makefile for platform Pa.CreateMakeFile(False) if BuildTask.HasError(): - self.invalidateHash() EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule) self.MakeTime += int(round((time.time() - MakeStart))) @@ -1936,11 +1934,14 @@ def _BuildModule(self): BuildTask.WaitForComplete() self.CreateAsBuiltInf() if GlobalData.gBinCacheDest: - self.UpdateBuildCache() + self.GenDestCache() + elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource: + # Only for --hash + # Update PreMakeCacheChain files + self.GenLocalPreMakeCache() self.BuildModules = [] self.MakeTime += int(round((time.time() - MakeContiue))) if BuildTask.HasError(): - self.invalidateHash() EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule) self.BuildReport.AddPlatformReport(Wa, MaList) @@ -1993,7 +1994,6 @@ def _BuildModule(self): # Save MAP buffer into MAP file. # self._SaveMapFile (MapBuffer, Wa) - self.invalidateHash() def _GenFfsCmd(self,ArchList): # convert dictionary of Cmd:(Inf,Arch) @@ -2064,7 +2064,7 @@ def SetupMakeSetting(self,Wa): if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict: FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName] for FdRegion in FdDict.RegionList: - if str(FdRegion.RegionType) is 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList): + if str(FdRegion.RegionType) == 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList): if int(FdRegion.Offset) % 8 != 0: EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset)) Wa.FdfProfile = Fdf.Profile @@ -2099,20 +2099,13 @@ def PerformAutoGen(self,BuildTarget,ToolChain): self.BuildReport.AddPlatformReport(Wa) Wa.CreateMakeFile(False) - # Add ffs build to makefile + # Add ffs build to makefile CmdListDict = {} if GlobalData.gEnableGenfdsMultiThread and self.Fdf: CmdListDict = self._GenFfsCmd(Wa.ArchList) - # Add Platform and Package level hash in share_data for module hash calculation later - if GlobalData.gBinCacheSource or GlobalData.gBinCacheDest: - GlobalData.gCacheIR[('PlatformHash')] = GlobalData.gPlatformHash - for PkgName in GlobalData.gPackageHash.keys(): - GlobalData.gCacheIR[(PkgName, 'PackageHash')] = GlobalData.gPackageHash[PkgName] - self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime))) BuildModules = [] - TotalModules = [] for Arch in Wa.ArchList: PcdMaList = [] AutoGenStart = time.time() @@ -2123,7 +2116,7 @@ def PerformAutoGen(self,BuildTarget,ToolChain): ModuleList = [] for Inf in Pa.Platform.Modules: ModuleList.append(Inf) - # Add the INF only list in FDF + # Add the INF only list in FDF if GlobalData.gFdfParser is not None: for InfName in GlobalData.gFdfParser.Profile.InfList: Inf = PathClass(NormPath(InfName), self.WorkspaceDir, Arch) @@ -2137,58 +2130,73 @@ def PerformAutoGen(self,BuildTarget,ToolChain): Pa.DataPipe.DataContainer = {"LibraryBuildDirectoryList":Pa.LibraryBuildDirectoryList} Pa.DataPipe.DataContainer = {"ModuleBuildDirectoryList":Pa.ModuleBuildDirectoryList} Pa.DataPipe.DataContainer = {"FdsCommandDict": Wa.GenFdsCommandDict} + # Prepare the cache share data for multiprocessing + Pa.DataPipe.DataContainer = {"gPlatformHashFile":GlobalData.gPlatformHashFile} ModuleCodaFile = {} for ma in Pa.ModuleAutoGenList: ModuleCodaFile[(ma.MetaFile.File,ma.MetaFile.Root,ma.Arch,ma.MetaFile.Path)] = [item.Target for item in ma.CodaTargetList] Pa.DataPipe.DataContainer = {"ModuleCodaFile":ModuleCodaFile} + # ModuleList contains all driver modules only for Module in ModuleList: - # Get ModuleAutoGen object to generate C code file and makefile + # Get ModuleAutoGen object to generate C code file and makefile Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe) - if Ma is None: continue if Ma.PcdIsDriver: Ma.PlatformInfo = Pa Ma.Workspace = Wa PcdMaList.append(Ma) - TotalModules.append(Ma) - # Initialize all modules in tracking to 'FAIL' - GlobalData.gModuleBuildTracking[Ma] = 'FAIL' - + self.AllDrivers.add(Ma) + self.AllModules.add(Ma) mqueue = mp.Queue() + cqueue = mp.Queue() for m in Pa.GetAllModuleInfo: mqueue.put(m) + module_file,module_root,module_path,module_basename,\ + module_originalpath,module_arch,IsLib = m + Ma = ModuleAutoGen(Wa, PathClass(module_path, Wa), BuildTarget,\ + ToolChain, Arch, self.PlatformFile,Pa.DataPipe) + self.AllModules.add(Ma) data_pipe_file = os.path.join(Pa.BuildDir, "GlobalVar_%s_%s.bin" % (str(Pa.Guid),Pa.Arch)) Pa.DataPipe.dump(data_pipe_file) - autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList,GlobalData.gCacheIR) - - # Skip cache hit modules - if GlobalData.gBinCacheSource: - for Ma in TotalModules: - if (Ma.MetaFile.Path, Ma.Arch) in GlobalData.gCacheIR and \ - GlobalData.gCacheIR[(Ma.MetaFile.Path, Ma.Arch)].PreMakeCacheHit: - self.HashSkipModules.append(Ma) - continue - if (Ma.MetaFile.Path, Ma.Arch) in GlobalData.gCacheIR and \ - GlobalData.gCacheIR[(Ma.MetaFile.Path, Ma.Arch)].MakeCacheHit: - self.HashSkipModules.append(Ma) - continue - BuildModules.append(Ma) - else: - BuildModules.extend(TotalModules) + autogen_rt, errorcode = self.StartAutoGen(mqueue, Pa.DataPipe, self.SkipAutoGen, PcdMaList, cqueue) if not autogen_rt: self.AutoGenMgr.TerminateWorkers() self.AutoGenMgr.join(1) raise FatalError(errorcode) + + if GlobalData.gUseHashCache: + for item in GlobalData.gModuleAllCacheStatus: + (MetaFilePath, Arch, CacheStr, Status) = item + Ma = ModuleAutoGen(Wa, PathClass(MetaFilePath, Wa), BuildTarget,\ + ToolChain, Arch, self.PlatformFile,Pa.DataPipe) + if CacheStr == "PreMakeCache" and Status == False: + self.PreMakeCacheMiss.add(Ma) + if CacheStr == "PreMakeCache" and Status == True: + self.PreMakeCacheHit.add(Ma) + GlobalData.gModuleCacheHit.add(Ma) + if CacheStr == "MakeCache" and Status == False: + self.MakeCacheMiss.add(Ma) + if CacheStr == "MakeCache" and Status == True: + self.MakeCacheHit.add(Ma) + GlobalData.gModuleCacheHit.add(Ma) self.AutoGenTime += int(round((time.time() - AutoGenStart))) AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt") with open(AutoGenIdFile,"w") as fw: fw.write("Arch=%s\n" % "|".join((Wa.ArchList))) fw.write("BuildDir=%s\n" % Wa.BuildDir) fw.write("PlatformGuid=%s\n" % str(Wa.AutoGenObjectList[0].Guid)) + + if GlobalData.gBinCacheSource: + BuildModules.extend(self.MakeCacheMiss) + elif GlobalData.gUseHashCache and not GlobalData.gBinCacheDest: + BuildModules.extend(self.PreMakeCacheMiss) + else: + BuildModules.extend(self.AllDrivers) + self.Progress.Stop("done!") return Wa, BuildModules @@ -2198,6 +2206,7 @@ def _MultiThreadBuildPlatform(self): GlobalData.gGlobalDefines['TARGET'] = BuildTarget index = 0 for ToolChain in self.ToolChainList: + resetFdsGlobalVariable() GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index] @@ -2218,18 +2227,9 @@ def _MultiThreadBuildPlatform(self): GlobalData.gAutoGenPhase = False if GlobalData.gBinCacheSource: - EdkLogger.quiet("Total cache hit driver num: %s, cache miss driver num: %s" % (len(set(self.HashSkipModules)), len(set(self.BuildModules)))) - CacheHitMa = set() - CacheNotHitMa = set() - for IR in GlobalData.gCacheIR.keys(): - if 'PlatformHash' in IR or 'PackageHash' in IR: - continue - if GlobalData.gCacheIR[IR].PreMakeCacheHit or GlobalData.gCacheIR[IR].MakeCacheHit: - CacheHitMa.add(IR) - else: - # There might be binary module or module which has .inc files, not count for cache miss - CacheNotHitMa.add(IR) - EdkLogger.quiet("Total module num: %s, cache hit module num: %s" % (len(CacheHitMa)+len(CacheNotHitMa), len(CacheHitMa))) + EdkLogger.quiet("[cache Summary]: Total module num: %s" % len(self.AllModules)) + EdkLogger.quiet("[cache Summary]: PreMakecache miss num: %s " % len(self.PreMakeCacheMiss)) + EdkLogger.quiet("[cache Summary]: Makecache miss num: %s " % len(self.MakeCacheMiss)) for Arch in Wa.ArchList: MakeStart = time.time() @@ -2242,7 +2242,6 @@ def _MultiThreadBuildPlatform(self): # we need a full version of makefile for platform ExitFlag.set() BuildTask.WaitForComplete() - self.invalidateHash() Pa.CreateMakeFile(False) EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule) # Start task scheduler @@ -2252,7 +2251,6 @@ def _MultiThreadBuildPlatform(self): # in case there's an interruption. we need a full version of makefile for platform if BuildTask.HasError(): - self.invalidateHash() EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule) self.MakeTime += int(round((time.time() - MakeStart))) @@ -2266,7 +2264,15 @@ def _MultiThreadBuildPlatform(self): BuildTask.WaitForComplete() self.CreateAsBuiltInf() if GlobalData.gBinCacheDest: - self.UpdateBuildCache() + self.GenDestCache() + elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource: + # Only for --hash + # Update PreMakeCacheChain files + self.GenLocalPreMakeCache() + # + # Get Module List + # + ModuleList = {ma.Guid.upper(): ma for ma in self.BuildModules} self.BuildModules = [] self.MakeTime += int(round((time.time() - MakeContiue))) # @@ -2274,7 +2280,6 @@ def _MultiThreadBuildPlatform(self): # has been signaled. # if BuildTask.HasError(): - self.invalidateHash() EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule) # Create MAP file when Load Fix Address is enabled. @@ -2285,10 +2290,6 @@ def _MultiThreadBuildPlatform(self): # if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000: EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platorm with IA32 or ARM arch modules") - # - # Get Module List - # - ModuleList = {ma.Guid.upper():ma for ma in self.BuildModules} # # Rebase module to the preferred memory address before GenFds @@ -2315,7 +2316,6 @@ def _MultiThreadBuildPlatform(self): # self._SaveMapFile(MapBuffer, Wa) self.CreateGuidedSectionToolsFile(Wa) - self.invalidateHash() ## Generate GuidedSectionTools.txt in the FV directories. # def CreateGuidedSectionToolsFile(self,Wa): @@ -2371,6 +2371,12 @@ def GetFullPathOfTool (self, tool): ## Launch the module or platform build # def Launch(self): + self.AllDrivers = set() + self.AllModules = set() + self.PreMakeCacheMiss = set() + self.PreMakeCacheHit = set() + self.MakeCacheMiss = set() + self.MakeCacheHit = set() if not self.ModuleFile: if not self.SpawnMode or self.Target not in ["", "all"]: self.SpawnMode = False @@ -2388,23 +2394,16 @@ def CreateAsBuiltInf(self): for Module in self.BuildModules: Module.CreateAsBuiltInf() - def UpdateBuildCache(self): - all_lib_set = set() - all_mod_set = set() - for Module in self.BuildModules: - Module.CopyModuleToCache() - all_mod_set.add(Module) - for Module in self.HashSkipModules: + def GenDestCache(self): + for Module in self.AllModules: + Module.GenPreMakefileHashList() + Module.GenMakefileHashList() Module.CopyModuleToCache() - all_mod_set.add(Module) - for Module in all_mod_set: - for lib in Module.LibraryAutoGenList: - all_lib_set.add(lib) - for lib in all_lib_set: - lib.CopyModuleToCache() - all_lib_set.clear() - all_mod_set.clear() - self.HashSkipModules = [] + + def GenLocalPreMakeCache(self): + for Module in self.PreMakeCacheMiss: + Module.GenPreMakefileHashList() + ## Do some clean-up works when error occurred def Relinquish(self): OldLogLevel = EdkLogger.GetLevel() @@ -2444,9 +2443,15 @@ def LogBuildTime(Time): else: return None def ThreadNum(): + OptionParser = MyOptionParser() + if not OptionParser.BuildOption and not OptionParser.BuildTarget: + OptionParser.GetOption() + BuildOption, BuildTarget = OptionParser.BuildOption, OptionParser.BuildTarget ThreadNumber = BuildOption.ThreadNumber + GlobalData.gCmdConfDir = BuildOption.ConfDirectory if ThreadNumber is None: - ThreadNumber = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER] + TargetObj = TargetTxtDict() + ThreadNumber = TargetObj.Target.TargetTxtDictionary[TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER] if ThreadNumber == '': ThreadNumber = 0 else: @@ -2481,7 +2486,10 @@ def Main(): # # Parse the options and args # - Option, Target = BuildOption, BuildTarget + OptionParser = MyOptionParser() + if not OptionParser.BuildOption and not OptionParser.BuildTarget: + OptionParser.GetOption() + Option, Target = OptionParser.BuildOption, OptionParser.BuildTarget GlobalData.gOptions = Option GlobalData.gCaseInsensitive = Option.CaseInsensitive diff --git a/BaseTools/Source/Python/build/buildoptions.py b/BaseTools/Source/Python/build/buildoptions.py new file mode 100644 index 00000000000..61ab2db9a4c --- /dev/null +++ b/BaseTools/Source/Python/build/buildoptions.py @@ -0,0 +1,105 @@ +## @file +# build a platform or a module +# +# Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
+# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +# Version and Copyright +from Common.BuildVersion import gBUILD_VERSION +from optparse import OptionParser +VersionNumber = "0.60" + ' ' + gBUILD_VERSION +__version__ = "%prog Version " + VersionNumber +__copyright__ = "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved." + +gParamCheck = [] +def SingleCheckCallback(option, opt_str, value, parser): + if option not in gParamCheck: + setattr(parser.values, option.dest, value) + gParamCheck.append(option) + else: + parser.error("Option %s only allows one instance in command line!" % option) + + +class MyOptionParser(): + + def __new__(cls, *args, **kw): + if not hasattr(cls, '_instance'): + orig = super(MyOptionParser, cls) + cls._instance = orig.__new__(cls, *args, **kw) + return cls._instance + + def __init__(self): + if not hasattr(self, 'BuildOption'): + self.BuildOption = None + if not hasattr(self, 'BuildTarget'): + self.BuildTarget = None + + def GetOption(self): + Parser = OptionParser(description=__copyright__, version=__version__, prog="build.exe", usage="%prog [options] [all|fds|genc|genmake|clean|cleanall|cleanlib|modules|libraries|run]") + Parser.add_option("-a", "--arch", action="append", type="choice", choices=['IA32', 'X64', 'EBC', 'ARM', 'AARCH64'], dest="TargetArch", + help="ARCHS is one of list: IA32, X64, ARM, AARCH64 or EBC, which overrides target.txt's TARGET_ARCH definition. To specify more archs, please repeat this option.") + Parser.add_option("-p", "--platform", action="callback", type="string", dest="PlatformFile", callback=SingleCheckCallback, + help="Build the platform specified by the DSC file name argument, overriding target.txt's ACTIVE_PLATFORM definition.") + Parser.add_option("-m", "--module", action="callback", type="string", dest="ModuleFile", callback=SingleCheckCallback, + help="Build the module specified by the INF file name argument.") + Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Using the TARGET to build the platform, overriding target.txt's TARGET definition.", + action="append") + Parser.add_option("-t", "--tagname", action="append", type="string", dest="ToolChain", + help="Using the Tool Chain Tagname to build the platform, overriding target.txt's TOOL_CHAIN_TAG definition.") + Parser.add_option("-x", "--sku-id", action="callback", type="string", dest="SkuId", callback=SingleCheckCallback, + help="Using this name of SKU ID to build the platform, overriding SKUID_IDENTIFIER in DSC file.") + + Parser.add_option("-n", action="callback", type="int", dest="ThreadNumber", callback=SingleCheckCallback, + help="Build the platform using multi-threaded compiler. The value overrides target.txt's MAX_CONCURRENT_THREAD_NUMBER. When value is set to 0, tool automatically detect number of "\ + "processor threads, set value to 1 means disable multi-thread build, and set value to more than 1 means user specify the threads number to build.") + + Parser.add_option("-f", "--fdf", action="callback", type="string", dest="FdfFile", callback=SingleCheckCallback, + help="The name of the FDF file to use, which overrides the setting in the DSC file.") + Parser.add_option("-r", "--rom-image", action="append", type="string", dest="RomImage", default=[], + help="The name of FD to be generated. The name must be from [FD] section in FDF file.") + Parser.add_option("-i", "--fv-image", action="append", type="string", dest="FvImage", default=[], + help="The name of FV to be generated. The name must be from [FV] section in FDF file.") + Parser.add_option("-C", "--capsule-image", action="append", type="string", dest="CapName", default=[], + help="The name of Capsule to be generated. The name must be from [Capsule] section in FDF file.") + Parser.add_option("-u", "--skip-autogen", action="store_true", dest="SkipAutoGen", help="Skip AutoGen step.") + Parser.add_option("-e", "--re-parse", action="store_true", dest="Reparse", help="Re-parse all meta-data files.") + + Parser.add_option("-c", "--case-insensitive", action="store_true", dest="CaseInsensitive", default=False, help="Don't check case of file name.") + + Parser.add_option("-w", "--warning-as-error", action="store_true", dest="WarningAsError", help="Treat warning in tools as error.") + Parser.add_option("-j", "--log", action="store", dest="LogFile", help="Put log in specified file as well as on console.") + + Parser.add_option("-s", "--silent", action="store_true", type=None, dest="SilentMode", + help="Make use of silent mode of (n)make.") + Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.") + Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\ + "including library instances selected, final dependency expression, "\ + "and warning messages, etc.") + Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.") + Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".") + + Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.") + Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'HASH', 'EXECUTION_ORDER'], dest="ReportType", default=[], + help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER]. "\ + "To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]") + Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag", + help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\ + "This option can also be specified by setting *_*_*_BUILD_FLAGS in [BuildOptions] section of platform DSC. If they are both specified, this value "\ + "will override the setting in [BuildOptions] section of platform DSC.") + Parser.add_option("-N", "--no-cache", action="store_true", dest="DisableCache", default=False, help="Disable build cache mechanism") + Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.") + Parser.add_option("--check-usage", action="store_true", dest="CheckUsage", default=False, help="Check usage content of entries listed in INF file.") + Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files") + Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ") + Parser.add_option("-l", "--cmd-len", action="store", type="int", dest="CommandLength", help="Specify the maximum line length of build command. Default is 4096.") + Parser.add_option("--hash", action="store_true", dest="UseHashCache", default=False, help="Enable hash-based caching during build process.") + Parser.add_option("--binary-destination", action="store", type="string", dest="BinCacheDest", help="Generate a cache of binary files in the specified directory.") + Parser.add_option("--binary-source", action="store", type="string", dest="BinCacheSource", help="Consume a cache of binary files from the specified directory.") + Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=True, help="Enable GenFds multi thread to generate ffs file.") + Parser.add_option("--no-genfds-multi-thread", action="store_true", dest="NoGenfdsMultiThread", default=False, help="Disable GenFds multi thread to generate ffs file.") + Parser.add_option("--disable-include-path-check", action="store_true", dest="DisableIncludePathCheck", default=False, help="Disable the include path check for outside of package.") + self.BuildOption, self.BuildTarget = Parser.parse_args() diff --git a/BaseTools/basetools_calling_path_env.yaml b/BaseTools/basetools_calling_path_env.yaml new file mode 100644 index 00000000000..f33f6ea38b4 --- /dev/null +++ b/BaseTools/basetools_calling_path_env.yaml @@ -0,0 +1,11 @@ +## @file +# Set shell variable BASE_TOOL_PATH to this folder +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "global", + "flags": ["set_shell_var"], + "var_name": "BASE_TOOLS_PATH" +} diff --git a/BaseTools/basetools_path_env.yaml b/BaseTools/basetools_path_env.yaml new file mode 100644 index 00000000000..6bdddcd0960 --- /dev/null +++ b/BaseTools/basetools_path_env.yaml @@ -0,0 +1,11 @@ +## @file +# Set shell variable EDK_TOOL_PATH to this folder +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "global", + "flags": ["set_shell_var", "set_build_var"], + "var_name": "EDK_TOOLS_PATH" +} diff --git a/BaseTools/set_vsprefix_envs.bat b/BaseTools/set_vsprefix_envs.bat index 6dff25d9300..9966a5a4ed5 100644 --- a/BaseTools/set_vsprefix_envs.bat +++ b/BaseTools/set_vsprefix_envs.bat @@ -158,6 +158,11 @@ if defined VCToolsInstallDir ( ) ) ) +if not defined WINSDK_PATH_FOR_RC_EXE ( + if defined WINSDK10_PREFIX ( + set "WINSDK_PATH_FOR_RC_EXE=%WINSDK10_PREFIX%x86" + ) +) :SetVS2017 if not defined VS150COMNTOOLS ( @@ -209,6 +214,11 @@ if defined VCToolsInstallDir ( ) ) ) +if not defined WINSDK_PATH_FOR_RC_EXE ( + if defined WINSDK10_PREFIX ( + set "WINSDK_PATH_FOR_RC_EXE=%WINSDK10_PREFIX%x86" + ) +) :SetWinDDK if not defined WINDDK3790_PREFIX ( diff --git a/CryptoPkg/CryptoPkg.ci.yaml b/CryptoPkg/CryptoPkg.ci.yaml new file mode 100644 index 00000000000..f54ebfb22e7 --- /dev/null +++ b/CryptoPkg/CryptoPkg.ci.yaml @@ -0,0 +1,47 @@ +## @file +# CI configuration for CryptoPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "CompilerPlugin": { + "DscPath": "CryptoPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "CryptoPkg/CryptoPkg.dec", + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "CryptoPkg.dsc", + "IgnoreInf": [] + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined ci/Plugin/SpellCheck + "SpellCheck": { + "skip": True, + "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files + "ExtendWords": [], # words to extend to the dictionary for this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + } +} diff --git a/CryptoPkg/Include/Library/TlsLib.h b/CryptoPkg/Include/Library/TlsLib.h index 9875cb6e746..3af7d4bc095 100644 --- a/CryptoPkg/Include/Library/TlsLib.h +++ b/CryptoPkg/Include/Library/TlsLib.h @@ -396,6 +396,26 @@ TlsSetVerify ( IN UINT32 VerifyMode ); +/** + Set the specified host name to be verified. + + @param[in] Tls Pointer to the TLS object. + @param[in] Flags The setting flags during the validation. + @param[in] HostName The specified host name to be verified. + + @retval EFI_SUCCESS The HostName setting was set successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_ABORTED Invalid HostName setting. + +**/ +EFI_STATUS +EFIAPI +TlsSetVerifyHost ( + IN VOID *Tls, + IN UINT32 Flags, + IN CHAR8 *HostName + ); + /** Sets a TLS/SSL session ID to be used during TLS/SSL connect. diff --git a/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf b/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf index a98be2cd959..1bbe4f435ae 100644 --- a/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf +++ b/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf @@ -58,6 +58,7 @@ SysCall/CrtWrapper.c SysCall/TimerWrapper.c SysCall/BaseMemAllocation.c + SysCall/inet_pton.c [Sources.Ia32] Rand/CryptRandTsc.c @@ -101,6 +102,6 @@ GCC:*_CLANG35_*_CC_FLAGS = -std=c99 GCC:*_CLANG38_*_CC_FLAGS = -std=c99 - GCC:*_CLANG9_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types XCODE:*_*_*_CC_FLAGS = -std=c99 diff --git a/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf b/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf index 7b07dd13d2f..c836c257f84 100644 --- a/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf +++ b/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf @@ -96,6 +96,6 @@ GCC:*_CLANG35_*_CC_FLAGS = -std=c99 GCC:*_CLANG38_*_CC_FLAGS = -std=c99 - GCC:*_CLANG9_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types XCODE:*_*_*_CC_FLAGS = -std=c99 diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c index 454dbbd476d..d24e1fdf680 100644 --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c @@ -7,7 +7,7 @@ 3) RsaSetKey 4) RsaPkcs1Verify -Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -250,7 +250,7 @@ RsaSetKey ( If RsaContext is NULL, then return FALSE. If MessageHash is NULL, then return FALSE. If Signature is NULL, then return FALSE. - If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE. + If HashSize is not equal to the size of MD5, SHA-1, SHA-256, SHA-384 or SHA-512 digest, then return FALSE. @param[in] RsaContext Pointer to RSA context for signature verification. @param[in] MessageHash Pointer to octet message hash to be checked. @@ -288,7 +288,7 @@ RsaPkcs1Verify ( // // Determine the message digest algorithm according to digest size. - // Only MD5, SHA-1 or SHA-256 algorithm is supported. + // Only MD5, SHA-1, SHA-256, SHA-384 or SHA-512 algorithm is supported. // switch (HashSize) { case MD5_DIGEST_SIZE: @@ -303,6 +303,14 @@ RsaPkcs1Verify ( DigestType = NID_sha256; break; + case SHA384_DIGEST_SIZE: + DigestType = NID_sha384; + break; + + case SHA512_DIGEST_SIZE: + DigestType = NID_sha512; + break; + default: return FALSE; } diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c index e3dd4844c44..7cd5fecf04c 100644 --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c @@ -7,7 +7,7 @@ 3) RsaCheckKey 4) RsaPkcs1Sign -Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -276,7 +276,7 @@ RsaCheckKey ( If RsaContext is NULL, then return FALSE. If MessageHash is NULL, then return FALSE. - If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE. + If HashSize is not equal to the size of MD5, SHA-1, SHA-256, SHA-384 or SHA-512 digest, then return FALSE. If SigSize is large enough but Signature is NULL, then return FALSE. @param[in] RsaContext Pointer to RSA context for signature generation. @@ -326,7 +326,7 @@ RsaPkcs1Sign ( // // Determine the message digest algorithm according to digest size. - // Only MD5, SHA-1 or SHA-256 algorithm is supported. + // Only MD5, SHA-1, SHA-256, SHA-384 or SHA-512 algorithm is supported. // switch (HashSize) { case MD5_DIGEST_SIZE: @@ -341,6 +341,14 @@ RsaPkcs1Sign ( DigestType = NID_sha256; break; + case SHA384_DIGEST_SIZE: + DigestType = NID_sha384; + break; + + case SHA512_DIGEST_SIZE: + DigestType = NID_sha512; + break; + default: return FALSE; } diff --git a/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf b/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf index d9e29ef660a..bff308a4f5e 100644 --- a/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf +++ b/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf @@ -107,6 +107,6 @@ GCC:*_CLANG35_*_CC_FLAGS = -std=c99 GCC:*_CLANG38_*_CC_FLAGS = -std=c99 - GCC:*_CLANG9_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types XCODE:*_*_*_CC_FLAGS = -std=c99 diff --git a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf index b4faaf3f80f..cc0b65fd250 100644 --- a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf +++ b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf @@ -104,4 +104,4 @@ GCC:*_CLANG35_*_CC_FLAGS = -std=c99 GCC:*_CLANG38_*_CC_FLAGS = -std=c99 - GCC:*_CLANG9_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types diff --git a/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c b/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c index 71a2ef34ed2..42235ab96ac 100644 --- a/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c +++ b/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c @@ -115,6 +115,11 @@ QuickSortWorker ( // -- String Manipulation Routines -- // +char *strchr(const char *str, int ch) +{ + return ScanMem8 (str, AsciiStrSize (str), (UINT8)ch); +} + /* Scan a string for the last occurrence of a character */ char *strrchr (const char *str, int c) { diff --git a/CryptoPkg/Library/BaseCryptLib/SysCall/inet_pton.c b/CryptoPkg/Library/BaseCryptLib/SysCall/inet_pton.c new file mode 100644 index 00000000000..32e1ab8690e --- /dev/null +++ b/CryptoPkg/Library/BaseCryptLib/SysCall/inet_pton.c @@ -0,0 +1,257 @@ +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions copyright (c) 1999, 2000 + * Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by Intel Corporation and + * its contributors. + * + * 4. Neither the name of Intel Corporation or its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id: inet_pton.c,v 1.1.1.1 2003/11/19 01:51:30 kyu3 Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4 (const char *src, u_char *dst); +static int inet_pton6 (const char *src, u_char *dst); + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +inet_pton( + int af, + const char *src, + void *dst + ) +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4( + const char *src, + u_char *dst + ) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + u_int new = *tp * 10 + (u_int)(pch - digits); + + if (new > 255) + return (0); + *tp = (u_char)new; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6( + const char *src, + u_char *dst + ) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = (int)(tp - colonp); + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} diff --git a/CryptoPkg/Library/Include/CrtLibSupport.h b/CryptoPkg/Library/Include/CrtLibSupport.h index 5806f50f748..5a20ba636ff 100644 --- a/CryptoPkg/Library/Include/CrtLibSupport.h +++ b/CryptoPkg/Library/Include/CrtLibSupport.h @@ -74,20 +74,36 @@ SPDX-License-Identifier: BSD-2-Clause-Patent // Definitions for global constants used by CRT library routines // #define EINVAL 22 /* Invalid argument */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ #define INT_MAX 0x7FFFFFFF /* Maximum (signed) int value */ #define LONG_MAX 0X7FFFFFFFL /* max value for a long */ #define LONG_MIN (-LONG_MAX-1) /* min value for a long */ #define ULONG_MAX 0xFFFFFFFF /* Maximum unsigned long value */ #define CHAR_BIT 8 /* Number of bits in a char */ +// +// Address families. +// +#define AF_INET 2 /* internetwork: UDP, TCP, etc. */ +#define AF_INET6 24 /* IP version 6 */ + +// +// Define constants based on RFC0883, RFC1034, RFC 1035 +// +#define NS_INT16SZ 2 /*%< #/bytes of data in a u_int16_t */ +#define NS_INADDRSZ 4 /*%< IPv4 T_A */ +#define NS_IN6ADDRSZ 16 /*%< IPv6 T_AAAA */ + // // Basic types mapping // typedef UINTN size_t; +typedef UINTN u_int; typedef INTN ssize_t; typedef INT32 time_t; typedef UINT8 __uint8_t; typedef UINT8 sa_family_t; +typedef UINT8 u_char; typedef UINT32 uid_t; typedef UINT32 gid_t; @@ -147,6 +163,7 @@ int isupper (int); int tolower (int); int strcmp (const char *, const char *); int strncasecmp (const char *, const char *, size_t); +char *strchr (const char *, int); char *strrchr (const char *, int); unsigned long strtoul (const char *, char **, int); long strtol (const char *, char **, int); @@ -175,6 +192,7 @@ void abort (void) __attribute__((__noreturn__)); #else void abort (void); #endif +int inet_pton (int, const char *, void *); // // Macros that directly map functions to BaseLib, BaseMemoryLib, and DebugLib functions @@ -188,7 +206,6 @@ void abort (void); #define strcpy(strDest,strSource) AsciiStrCpyS(strDest,MAX_STRING_SIZE,strSource) #define strncpy(strDest,strSource,count) AsciiStrnCpyS(strDest,MAX_STRING_SIZE,strSource,(UINTN)count) #define strcat(strDest,strSource) AsciiStrCatS(strDest,MAX_STRING_SIZE,strSource) -#define strchr(str,ch) ScanMem8((VOID *)(str),AsciiStrSize(str),(UINT8)ch) #define strncmp(string1,string2,count) (int)(AsciiStrnCmp(string1,string2,(UINTN)(count))) #define strcasecmp(str1,str2) (int)AsciiStriCmp(str1,str2) #define sprintf(buf,...) AsciiSPrint(buf,MAX_STRING_SIZE,__VA_ARGS__) diff --git a/CryptoPkg/Library/Include/arpa/inet.h b/CryptoPkg/Library/Include/arpa/inet.h new file mode 100644 index 00000000000..988e4e0a73e --- /dev/null +++ b/CryptoPkg/Library/Include/arpa/inet.h @@ -0,0 +1,9 @@ +/** @file + Include file to support building third-party standard C / BSD sockets code. + + Copyright (C) 2019, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include diff --git a/CryptoPkg/Library/Include/arpa/nameser.h b/CryptoPkg/Library/Include/arpa/nameser.h new file mode 100644 index 00000000000..988e4e0a73e --- /dev/null +++ b/CryptoPkg/Library/Include/arpa/nameser.h @@ -0,0 +1,9 @@ +/** @file + Include file to support building third-party standard C / BSD sockets code. + + Copyright (C) 2019, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include diff --git a/CryptoPkg/Library/Include/internal/dso_conf.h b/CryptoPkg/Library/Include/internal/dso_conf.h index e69de29bb2d..43c891588bc 100644 --- a/CryptoPkg/Library/Include/internal/dso_conf.h +++ b/CryptoPkg/Library/Include/internal/dso_conf.h @@ -0,0 +1,16 @@ +/* WARNING: do not edit! */ +/* Generated from crypto/include/internal/dso_conf.h.in */ +/* + * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_DSO_CONF_H +# define HEADER_DSO_CONF_H +# define DSO_NONE +# define DSO_EXTENSION ".so" +#endif diff --git a/CryptoPkg/Library/Include/netinet/in.h b/CryptoPkg/Library/Include/netinet/in.h new file mode 100644 index 00000000000..988e4e0a73e --- /dev/null +++ b/CryptoPkg/Library/Include/netinet/in.h @@ -0,0 +1,9 @@ +/** @file + Include file to support building third-party standard C / BSD sockets code. + + Copyright (C) 2019, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include diff --git a/CryptoPkg/Library/Include/sys/param.h b/CryptoPkg/Library/Include/sys/param.h new file mode 100644 index 00000000000..988e4e0a73e --- /dev/null +++ b/CryptoPkg/Library/Include/sys/param.h @@ -0,0 +1,9 @@ +/** @file + Include file to support building third-party standard C / BSD sockets code. + + Copyright (C) 2019, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include diff --git a/CryptoPkg/Library/Include/sys/shm.h b/CryptoPkg/Library/Include/sys/shm.h new file mode 100644 index 00000000000..dc0b8e81c8b --- /dev/null +++ b/CryptoPkg/Library/Include/sys/shm.h @@ -0,0 +1,9 @@ +/** @file + Include file to support building the third-party cryptographic library. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include diff --git a/CryptoPkg/Library/Include/sys/socket.h b/CryptoPkg/Library/Include/sys/socket.h new file mode 100644 index 00000000000..988e4e0a73e --- /dev/null +++ b/CryptoPkg/Library/Include/sys/socket.h @@ -0,0 +1,9 @@ +/** @file + Include file to support building third-party standard C / BSD sockets code. + + Copyright (C) 2019, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include diff --git a/CryptoPkg/Library/Include/sys/utsname.h b/CryptoPkg/Library/Include/sys/utsname.h new file mode 100644 index 00000000000..dc0b8e81c8b --- /dev/null +++ b/CryptoPkg/Library/Include/sys/utsname.h @@ -0,0 +1,9 @@ +/** @file + Include file to support building the third-party cryptographic library. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include diff --git a/CryptoPkg/Library/OpensslLib/OpensslLib.inf b/CryptoPkg/Library/OpensslLib/OpensslLib.inf index b40d82783b4..3fa52f55432 100644 --- a/CryptoPkg/Library/OpensslLib/OpensslLib.inf +++ b/CryptoPkg/Library/OpensslLib/OpensslLib.inf @@ -22,9 +22,8 @@ # [Sources] - buildinf.h - rand_pool_noise.h $(OPENSSL_PATH)/e_os.h + $(OPENSSL_PATH)/ms/uplink.h # Autogenerated files list starts here $(OPENSSL_PATH)/crypto/aes/aes_cbc.c $(OPENSSL_PATH)/crypto/aes/aes_cfb.c @@ -34,9 +33,7 @@ $(OPENSSL_PATH)/crypto/aes/aes_misc.c $(OPENSSL_PATH)/crypto/aes/aes_ofb.c $(OPENSSL_PATH)/crypto/aes/aes_wrap.c - $(OPENSSL_PATH)/crypto/aes/aes_locl.h $(OPENSSL_PATH)/crypto/aria/aria.c - $(OPENSSL_PATH)/crypto/arm_arch.h $(OPENSSL_PATH)/crypto/asn1/a_bitstr.c $(OPENSSL_PATH)/crypto/asn1/a_d2i_fp.c $(OPENSSL_PATH)/crypto/asn1/a_digest.c @@ -101,21 +98,12 @@ $(OPENSSL_PATH)/crypto/asn1/x_sig.c $(OPENSSL_PATH)/crypto/asn1/x_spki.c $(OPENSSL_PATH)/crypto/asn1/x_val.c - $(OPENSSL_PATH)/crypto/asn1/standard_methods.h - $(OPENSSL_PATH)/crypto/asn1/charmap.h - $(OPENSSL_PATH)/crypto/asn1/tbl_standard.h - $(OPENSSL_PATH)/crypto/asn1/asn1_item_list.h - $(OPENSSL_PATH)/crypto/asn1/asn1_locl.h $(OPENSSL_PATH)/crypto/async/arch/async_null.c $(OPENSSL_PATH)/crypto/async/arch/async_posix.c $(OPENSSL_PATH)/crypto/async/arch/async_win.c $(OPENSSL_PATH)/crypto/async/async.c $(OPENSSL_PATH)/crypto/async/async_err.c $(OPENSSL_PATH)/crypto/async/async_wait.c - $(OPENSSL_PATH)/crypto/async/arch/async_win.h - $(OPENSSL_PATH)/crypto/async/async_locl.h - $(OPENSSL_PATH)/crypto/async/arch/async_posix.h - $(OPENSSL_PATH)/crypto/async/arch/async_null.h $(OPENSSL_PATH)/crypto/bio/b_addr.c $(OPENSSL_PATH)/crypto/bio/b_dump.c $(OPENSSL_PATH)/crypto/bio/b_sock.c @@ -138,7 +126,6 @@ $(OPENSSL_PATH)/crypto/bio/bss_mem.c $(OPENSSL_PATH)/crypto/bio/bss_null.c $(OPENSSL_PATH)/crypto/bio/bss_sock.c - $(OPENSSL_PATH)/crypto/bio/bio_lcl.h $(OPENSSL_PATH)/crypto/bn/bn_add.c $(OPENSSL_PATH)/crypto/bn/bn_asm.c $(OPENSSL_PATH)/crypto/bn/bn_blind.c @@ -170,9 +157,6 @@ $(OPENSSL_PATH)/crypto/bn/bn_srp.c $(OPENSSL_PATH)/crypto/bn/bn_word.c $(OPENSSL_PATH)/crypto/bn/bn_x931p.c - $(OPENSSL_PATH)/crypto/bn/rsaz_exp.h - $(OPENSSL_PATH)/crypto/bn/bn_prime.h - $(OPENSSL_PATH)/crypto/bn/bn_lcl.h $(OPENSSL_PATH)/crypto/buffer/buf_err.c $(OPENSSL_PATH)/crypto/buffer/buffer.c $(OPENSSL_PATH)/crypto/cmac/cm_ameth.c @@ -181,7 +165,6 @@ $(OPENSSL_PATH)/crypto/comp/c_zlib.c $(OPENSSL_PATH)/crypto/comp/comp_err.c $(OPENSSL_PATH)/crypto/comp/comp_lib.c - $(OPENSSL_PATH)/crypto/comp/comp_lcl.h $(OPENSSL_PATH)/crypto/conf/conf_api.c $(OPENSSL_PATH)/crypto/conf/conf_def.c $(OPENSSL_PATH)/crypto/conf/conf_err.c @@ -190,8 +173,6 @@ $(OPENSSL_PATH)/crypto/conf/conf_mod.c $(OPENSSL_PATH)/crypto/conf/conf_sap.c $(OPENSSL_PATH)/crypto/conf/conf_ssl.c - $(OPENSSL_PATH)/crypto/conf/conf_lcl.h - $(OPENSSL_PATH)/crypto/conf/conf_def.h $(OPENSSL_PATH)/crypto/cpt_err.c $(OPENSSL_PATH)/crypto/cryptlib.c $(OPENSSL_PATH)/crypto/ctype.c @@ -215,8 +196,6 @@ $(OPENSSL_PATH)/crypto/des/set_key.c $(OPENSSL_PATH)/crypto/des/str2key.c $(OPENSSL_PATH)/crypto/des/xcbc_enc.c - $(OPENSSL_PATH)/crypto/des/spr.h - $(OPENSSL_PATH)/crypto/des/des_locl.h $(OPENSSL_PATH)/crypto/dh/dh_ameth.c $(OPENSSL_PATH)/crypto/dh/dh_asn1.c $(OPENSSL_PATH)/crypto/dh/dh_check.c @@ -231,7 +210,6 @@ $(OPENSSL_PATH)/crypto/dh/dh_prn.c $(OPENSSL_PATH)/crypto/dh/dh_rfc5114.c $(OPENSSL_PATH)/crypto/dh/dh_rfc7919.c - $(OPENSSL_PATH)/crypto/dh/dh_locl.h $(OPENSSL_PATH)/crypto/dso/dso_dl.c $(OPENSSL_PATH)/crypto/dso/dso_dlfcn.c $(OPENSSL_PATH)/crypto/dso/dso_err.c @@ -239,7 +217,6 @@ $(OPENSSL_PATH)/crypto/dso/dso_openssl.c $(OPENSSL_PATH)/crypto/dso/dso_vms.c $(OPENSSL_PATH)/crypto/dso/dso_win32.c - $(OPENSSL_PATH)/crypto/dso/dso_locl.h $(OPENSSL_PATH)/crypto/ebcdic.c $(OPENSSL_PATH)/crypto/err/err.c $(OPENSSL_PATH)/crypto/err/err_prn.c @@ -304,13 +281,11 @@ $(OPENSSL_PATH)/crypto/evp/pmeth_fn.c $(OPENSSL_PATH)/crypto/evp/pmeth_gn.c $(OPENSSL_PATH)/crypto/evp/pmeth_lib.c - $(OPENSSL_PATH)/crypto/evp/evp_locl.h $(OPENSSL_PATH)/crypto/ex_data.c $(OPENSSL_PATH)/crypto/getenv.c $(OPENSSL_PATH)/crypto/hmac/hm_ameth.c $(OPENSSL_PATH)/crypto/hmac/hm_pmeth.c $(OPENSSL_PATH)/crypto/hmac/hmac.c - $(OPENSSL_PATH)/crypto/hmac/hmac_lcl.h $(OPENSSL_PATH)/crypto/init.c $(OPENSSL_PATH)/crypto/kdf/hkdf.c $(OPENSSL_PATH)/crypto/kdf/kdf_err.c @@ -318,13 +293,10 @@ $(OPENSSL_PATH)/crypto/kdf/tls1_prf.c $(OPENSSL_PATH)/crypto/lhash/lh_stats.c $(OPENSSL_PATH)/crypto/lhash/lhash.c - $(OPENSSL_PATH)/crypto/lhash/lhash_lcl.h $(OPENSSL_PATH)/crypto/md4/md4_dgst.c $(OPENSSL_PATH)/crypto/md4/md4_one.c - $(OPENSSL_PATH)/crypto/md4/md4_locl.h $(OPENSSL_PATH)/crypto/md5/md5_dgst.c $(OPENSSL_PATH)/crypto/md5/md5_one.c - $(OPENSSL_PATH)/crypto/md5/md5_locl.h $(OPENSSL_PATH)/crypto/mem.c $(OPENSSL_PATH)/crypto/mem_clr.c $(OPENSSL_PATH)/crypto/mem_dbg.c @@ -339,7 +311,6 @@ $(OPENSSL_PATH)/crypto/modes/ofb128.c $(OPENSSL_PATH)/crypto/modes/wrap128.c $(OPENSSL_PATH)/crypto/modes/xts128.c - $(OPENSSL_PATH)/crypto/modes/modes_lcl.h $(OPENSSL_PATH)/crypto/o_dir.c $(OPENSSL_PATH)/crypto/o_fips.c $(OPENSSL_PATH)/crypto/o_fopen.c @@ -351,9 +322,6 @@ $(OPENSSL_PATH)/crypto/objects/obj_err.c $(OPENSSL_PATH)/crypto/objects/obj_lib.c $(OPENSSL_PATH)/crypto/objects/obj_xref.c - $(OPENSSL_PATH)/crypto/objects/obj_dat.h - $(OPENSSL_PATH)/crypto/objects/obj_xref.h - $(OPENSSL_PATH)/crypto/objects/obj_lcl.h $(OPENSSL_PATH)/crypto/ocsp/ocsp_asn.c $(OPENSSL_PATH)/crypto/ocsp/ocsp_cl.c $(OPENSSL_PATH)/crypto/ocsp/ocsp_err.c @@ -364,7 +332,6 @@ $(OPENSSL_PATH)/crypto/ocsp/ocsp_srv.c $(OPENSSL_PATH)/crypto/ocsp/ocsp_vfy.c $(OPENSSL_PATH)/crypto/ocsp/v3_ocsp.c - $(OPENSSL_PATH)/crypto/ocsp/ocsp_lcl.h $(OPENSSL_PATH)/crypto/pem/pem_all.c $(OPENSSL_PATH)/crypto/pem/pem_err.c $(OPENSSL_PATH)/crypto/pem/pem_info.c @@ -392,7 +359,6 @@ $(OPENSSL_PATH)/crypto/pkcs12/p12_sbag.c $(OPENSSL_PATH)/crypto/pkcs12/p12_utl.c $(OPENSSL_PATH)/crypto/pkcs12/pk12err.c - $(OPENSSL_PATH)/crypto/pkcs12/p12_lcl.h $(OPENSSL_PATH)/crypto/pkcs7/bio_pk7.c $(OPENSSL_PATH)/crypto/pkcs7/pk7_asn1.c $(OPENSSL_PATH)/crypto/pkcs7/pk7_attr.c @@ -401,7 +367,6 @@ $(OPENSSL_PATH)/crypto/pkcs7/pk7_mime.c $(OPENSSL_PATH)/crypto/pkcs7/pk7_smime.c $(OPENSSL_PATH)/crypto/pkcs7/pkcs7err.c - $(OPENSSL_PATH)/crypto/ppc_arch.h $(OPENSSL_PATH)/crypto/rand/drbg_ctr.c $(OPENSSL_PATH)/crypto/rand/drbg_lib.c $(OPENSSL_PATH)/crypto/rand/rand_egd.c @@ -410,10 +375,8 @@ $(OPENSSL_PATH)/crypto/rand/rand_unix.c $(OPENSSL_PATH)/crypto/rand/rand_vms.c $(OPENSSL_PATH)/crypto/rand/rand_win.c - $(OPENSSL_PATH)/crypto/rand/rand_lcl.h $(OPENSSL_PATH)/crypto/rc4/rc4_enc.c $(OPENSSL_PATH)/crypto/rc4/rc4_skey.c - $(OPENSSL_PATH)/crypto/rc4/rc4_locl.h $(OPENSSL_PATH)/crypto/rsa/rsa_ameth.c $(OPENSSL_PATH)/crypto/rsa/rsa_asn1.c $(OPENSSL_PATH)/crypto/rsa/rsa_chk.c @@ -436,24 +399,18 @@ $(OPENSSL_PATH)/crypto/rsa/rsa_ssl.c $(OPENSSL_PATH)/crypto/rsa/rsa_x931.c $(OPENSSL_PATH)/crypto/rsa/rsa_x931g.c - $(OPENSSL_PATH)/crypto/rsa/rsa_locl.h - $(OPENSSL_PATH)/crypto/s390x_arch.h $(OPENSSL_PATH)/crypto/sha/keccak1600.c $(OPENSSL_PATH)/crypto/sha/sha1_one.c $(OPENSSL_PATH)/crypto/sha/sha1dgst.c $(OPENSSL_PATH)/crypto/sha/sha256.c $(OPENSSL_PATH)/crypto/sha/sha512.c - $(OPENSSL_PATH)/crypto/sha/sha_locl.h $(OPENSSL_PATH)/crypto/siphash/siphash.c $(OPENSSL_PATH)/crypto/siphash/siphash_ameth.c $(OPENSSL_PATH)/crypto/siphash/siphash_pmeth.c - $(OPENSSL_PATH)/crypto/siphash/siphash_local.h $(OPENSSL_PATH)/crypto/sm3/m_sm3.c $(OPENSSL_PATH)/crypto/sm3/sm3.c - $(OPENSSL_PATH)/crypto/sm3/sm3_locl.h $(OPENSSL_PATH)/crypto/sm4/sm4.c $(OPENSSL_PATH)/crypto/stack/stack.c - $(OPENSSL_PATH)/crypto/sparc_arch.h $(OPENSSL_PATH)/crypto/threads_none.c $(OPENSSL_PATH)/crypto/threads_pthread.c $(OPENSSL_PATH)/crypto/threads_win.c @@ -463,8 +420,6 @@ $(OPENSSL_PATH)/crypto/ui/ui_null.c $(OPENSSL_PATH)/crypto/ui/ui_openssl.c $(OPENSSL_PATH)/crypto/ui/ui_util.c - $(OPENSSL_PATH)/crypto/ui/ui_locl.h - $(OPENSSL_PATH)/crypto/vms_rms.h $(OPENSSL_PATH)/crypto/uid.c $(OPENSSL_PATH)/crypto/x509/by_dir.c $(OPENSSL_PATH)/crypto/x509/by_file.c @@ -502,7 +457,6 @@ $(OPENSSL_PATH)/crypto/x509/x_req.c $(OPENSSL_PATH)/crypto/x509/x_x509.c $(OPENSSL_PATH)/crypto/x509/x_x509a.c - $(OPENSSL_PATH)/crypto/x509/x509_lcl.h $(OPENSSL_PATH)/crypto/x509v3/pcy_cache.c $(OPENSSL_PATH)/crypto/x509v3/pcy_data.c $(OPENSSL_PATH)/crypto/x509v3/pcy_lib.c @@ -540,11 +494,57 @@ $(OPENSSL_PATH)/crypto/x509v3/v3_tlsf.c $(OPENSSL_PATH)/crypto/x509v3/v3_utl.c $(OPENSSL_PATH)/crypto/x509v3/v3err.c + $(OPENSSL_PATH)/crypto/hmac/hmac_lcl.h + $(OPENSSL_PATH)/crypto/dh/dh_locl.h + $(OPENSSL_PATH)/crypto/bio/bio_lcl.h + $(OPENSSL_PATH)/crypto/conf/conf_def.h + $(OPENSSL_PATH)/crypto/conf/conf_lcl.h + $(OPENSSL_PATH)/crypto/lhash/lhash_lcl.h + $(OPENSSL_PATH)/crypto/sha/sha_locl.h + $(OPENSSL_PATH)/crypto/md5/md5_locl.h + $(OPENSSL_PATH)/crypto/store/store_locl.h + $(OPENSSL_PATH)/crypto/dso/dso_locl.h + $(OPENSSL_PATH)/crypto/pkcs12/p12_lcl.h + $(OPENSSL_PATH)/crypto/arm_arch.h + $(OPENSSL_PATH)/crypto/mips_arch.h + $(OPENSSL_PATH)/crypto/ppc_arch.h + $(OPENSSL_PATH)/crypto/s390x_arch.h + $(OPENSSL_PATH)/crypto/sparc_arch.h + $(OPENSSL_PATH)/crypto/vms_rms.h + $(OPENSSL_PATH)/crypto/bn/bn_lcl.h + $(OPENSSL_PATH)/crypto/bn/bn_prime.h + $(OPENSSL_PATH)/crypto/bn/rsaz_exp.h + $(OPENSSL_PATH)/crypto/ui/ui_locl.h + $(OPENSSL_PATH)/crypto/md4/md4_locl.h + $(OPENSSL_PATH)/crypto/rc4/rc4_locl.h + $(OPENSSL_PATH)/crypto/asn1/asn1_item_list.h + $(OPENSSL_PATH)/crypto/asn1/asn1_locl.h + $(OPENSSL_PATH)/crypto/asn1/charmap.h + $(OPENSSL_PATH)/crypto/asn1/standard_methods.h + $(OPENSSL_PATH)/crypto/asn1/tbl_standard.h + $(OPENSSL_PATH)/crypto/evp/evp_locl.h + $(OPENSSL_PATH)/crypto/rand/rand_lcl.h + $(OPENSSL_PATH)/crypto/ocsp/ocsp_lcl.h + $(OPENSSL_PATH)/crypto/modes/modes_lcl.h + $(OPENSSL_PATH)/crypto/comp/comp_lcl.h + $(OPENSSL_PATH)/crypto/rsa/rsa_locl.h + $(OPENSSL_PATH)/crypto/x509/x509_lcl.h + $(OPENSSL_PATH)/crypto/async/arch/async_null.h + $(OPENSSL_PATH)/crypto/async/arch/async_posix.h + $(OPENSSL_PATH)/crypto/async/arch/async_win.h + $(OPENSSL_PATH)/crypto/sm3/sm3_locl.h + $(OPENSSL_PATH)/crypto/des/des_locl.h + $(OPENSSL_PATH)/crypto/des/spr.h + $(OPENSSL_PATH)/crypto/siphash/siphash_local.h + $(OPENSSL_PATH)/crypto/aes/aes_locl.h + $(OPENSSL_PATH)/crypto/async/async_locl.h + $(OPENSSL_PATH)/crypto/x509v3/ext_dat.h $(OPENSSL_PATH)/crypto/x509v3/pcy_int.h - $(OPENSSL_PATH)/crypto/x509v3/v3_admis.h $(OPENSSL_PATH)/crypto/x509v3/standard_exts.h - $(OPENSSL_PATH)/crypto/x509v3/ext_dat.h - $(OPENSSL_PATH)/ms/uplink.h + $(OPENSSL_PATH)/crypto/x509v3/v3_admis.h + $(OPENSSL_PATH)/crypto/objects/obj_dat.h + $(OPENSSL_PATH)/crypto/objects/obj_lcl.h + $(OPENSSL_PATH)/crypto/objects/obj_xref.h $(OPENSSL_PATH)/ssl/bio_ssl.c $(OPENSSL_PATH)/ssl/d1_lib.c $(OPENSSL_PATH)/ssl/d1_msg.c @@ -589,15 +589,16 @@ $(OPENSSL_PATH)/ssl/t1_trce.c $(OPENSSL_PATH)/ssl/tls13_enc.c $(OPENSSL_PATH)/ssl/tls_srp.c - $(OPENSSL_PATH)/ssl/record/record_locl.h $(OPENSSL_PATH)/ssl/statem/statem.h $(OPENSSL_PATH)/ssl/statem/statem_locl.h + $(OPENSSL_PATH)/ssl/packet_locl.h + $(OPENSSL_PATH)/ssl/ssl_cert_table.h $(OPENSSL_PATH)/ssl/ssl_locl.h $(OPENSSL_PATH)/ssl/record/record.h - $(OPENSSL_PATH)/ssl/ssl_cert_table.h - $(OPENSSL_PATH)/ssl/packet_locl.h + $(OPENSSL_PATH)/ssl/record/record_locl.h # Autogenerated files list ends here - + buildinf.h + rand_pool_noise.h ossl_store.c rand_pool.c @@ -662,7 +663,7 @@ GCC:*_*_AARCH64_CC_FLAGS = $(OPENSSL_FLAGS) -Wno-error=maybe-uninitialized -Wno-format -Wno-error=unused-but-set-variable GCC:*_CLANG35_*_CC_FLAGS = -std=c99 -Wno-error=uninitialized GCC:*_CLANG38_*_CC_FLAGS = -std=c99 -Wno-error=uninitialized - GCC:*_CLANG9_*_CC_FLAGS = -std=c99 -Wno-error=uninitialized -Wno-error=incompatible-pointer-types -Wno-error=pointer-sign -Wno-error=implicit-function-declaration -Wno-error=ignored-pragma-optimize + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=uninitialized -Wno-error=incompatible-pointer-types -Wno-error=pointer-sign -Wno-error=implicit-function-declaration -Wno-error=ignored-pragma-optimize # suppress the following warnings in openssl so we don't break the build with warnings-as-errors: # 1295: Deprecated declaration - give arg types diff --git a/CryptoPkg/Library/OpensslLib/OpensslLibCrypto.inf b/CryptoPkg/Library/OpensslLib/OpensslLibCrypto.inf index 0a60196c8a9..f1f9fbb938b 100644 --- a/CryptoPkg/Library/OpensslLib/OpensslLibCrypto.inf +++ b/CryptoPkg/Library/OpensslLib/OpensslLibCrypto.inf @@ -33,9 +33,7 @@ $(OPENSSL_PATH)/crypto/aes/aes_misc.c $(OPENSSL_PATH)/crypto/aes/aes_ofb.c $(OPENSSL_PATH)/crypto/aes/aes_wrap.c - $(OPENSSL_PATH)/crypto/aes/aes_locl.h $(OPENSSL_PATH)/crypto/aria/aria.c - $(OPENSSL_PATH)/crypto/arm_arch.h $(OPENSSL_PATH)/crypto/asn1/a_bitstr.c $(OPENSSL_PATH)/crypto/asn1/a_d2i_fp.c $(OPENSSL_PATH)/crypto/asn1/a_digest.c @@ -100,21 +98,12 @@ $(OPENSSL_PATH)/crypto/asn1/x_sig.c $(OPENSSL_PATH)/crypto/asn1/x_spki.c $(OPENSSL_PATH)/crypto/asn1/x_val.c - $(OPENSSL_PATH)/crypto/asn1/standard_methods.h - $(OPENSSL_PATH)/crypto/asn1/charmap.h - $(OPENSSL_PATH)/crypto/asn1/tbl_standard.h - $(OPENSSL_PATH)/crypto/asn1/asn1_item_list.h - $(OPENSSL_PATH)/crypto/asn1/asn1_locl.h $(OPENSSL_PATH)/crypto/async/arch/async_null.c $(OPENSSL_PATH)/crypto/async/arch/async_posix.c $(OPENSSL_PATH)/crypto/async/arch/async_win.c - $(OPENSSL_PATH)/crypto/async/arch/async_posix.h - $(OPENSSL_PATH)/crypto/async/arch/async_null.h - $(OPENSSL_PATH)/crypto/async/arch/async_win.h $(OPENSSL_PATH)/crypto/async/async.c $(OPENSSL_PATH)/crypto/async/async_err.c $(OPENSSL_PATH)/crypto/async/async_wait.c - $(OPENSSL_PATH)/crypto/async/async_locl.h $(OPENSSL_PATH)/crypto/bio/b_addr.c $(OPENSSL_PATH)/crypto/bio/b_dump.c $(OPENSSL_PATH)/crypto/bio/b_sock.c @@ -137,7 +126,6 @@ $(OPENSSL_PATH)/crypto/bio/bss_mem.c $(OPENSSL_PATH)/crypto/bio/bss_null.c $(OPENSSL_PATH)/crypto/bio/bss_sock.c - $(OPENSSL_PATH)/crypto/bio/bio_lcl.h $(OPENSSL_PATH)/crypto/bn/bn_add.c $(OPENSSL_PATH)/crypto/bn/bn_asm.c $(OPENSSL_PATH)/crypto/bn/bn_blind.c @@ -169,9 +157,6 @@ $(OPENSSL_PATH)/crypto/bn/bn_srp.c $(OPENSSL_PATH)/crypto/bn/bn_word.c $(OPENSSL_PATH)/crypto/bn/bn_x931p.c - $(OPENSSL_PATH)/crypto/bn/rsaz_exp.h - $(OPENSSL_PATH)/crypto/bn/bn_prime.h - $(OPENSSL_PATH)/crypto/bn/bn_lcl.h $(OPENSSL_PATH)/crypto/buffer/buf_err.c $(OPENSSL_PATH)/crypto/buffer/buffer.c $(OPENSSL_PATH)/crypto/cmac/cm_ameth.c @@ -180,7 +165,6 @@ $(OPENSSL_PATH)/crypto/comp/c_zlib.c $(OPENSSL_PATH)/crypto/comp/comp_err.c $(OPENSSL_PATH)/crypto/comp/comp_lib.c - $(OPENSSL_PATH)/crypto/comp/comp_lcl.h $(OPENSSL_PATH)/crypto/conf/conf_api.c $(OPENSSL_PATH)/crypto/conf/conf_def.c $(OPENSSL_PATH)/crypto/conf/conf_err.c @@ -189,8 +173,6 @@ $(OPENSSL_PATH)/crypto/conf/conf_mod.c $(OPENSSL_PATH)/crypto/conf/conf_sap.c $(OPENSSL_PATH)/crypto/conf/conf_ssl.c - $(OPENSSL_PATH)/crypto/conf/conf_lcl.h - $(OPENSSL_PATH)/crypto/conf/conf_def.h $(OPENSSL_PATH)/crypto/cpt_err.c $(OPENSSL_PATH)/crypto/cryptlib.c $(OPENSSL_PATH)/crypto/ctype.c @@ -214,8 +196,6 @@ $(OPENSSL_PATH)/crypto/des/set_key.c $(OPENSSL_PATH)/crypto/des/str2key.c $(OPENSSL_PATH)/crypto/des/xcbc_enc.c - $(OPENSSL_PATH)/crypto/des/spr.h - $(OPENSSL_PATH)/crypto/des/des_locl.h $(OPENSSL_PATH)/crypto/dh/dh_ameth.c $(OPENSSL_PATH)/crypto/dh/dh_asn1.c $(OPENSSL_PATH)/crypto/dh/dh_check.c @@ -230,7 +210,6 @@ $(OPENSSL_PATH)/crypto/dh/dh_prn.c $(OPENSSL_PATH)/crypto/dh/dh_rfc5114.c $(OPENSSL_PATH)/crypto/dh/dh_rfc7919.c - $(OPENSSL_PATH)/crypto/dh/dh_locl.h $(OPENSSL_PATH)/crypto/dso/dso_dl.c $(OPENSSL_PATH)/crypto/dso/dso_dlfcn.c $(OPENSSL_PATH)/crypto/dso/dso_err.c @@ -238,7 +217,6 @@ $(OPENSSL_PATH)/crypto/dso/dso_openssl.c $(OPENSSL_PATH)/crypto/dso/dso_vms.c $(OPENSSL_PATH)/crypto/dso/dso_win32.c - $(OPENSSL_PATH)/crypto/dso/dso_locl.h $(OPENSSL_PATH)/crypto/ebcdic.c $(OPENSSL_PATH)/crypto/err/err.c $(OPENSSL_PATH)/crypto/err/err_prn.c @@ -280,7 +258,6 @@ $(OPENSSL_PATH)/crypto/evp/evp_pkey.c $(OPENSSL_PATH)/crypto/evp/m_md2.c $(OPENSSL_PATH)/crypto/evp/m_md4.c - $(OPENSSL_PATH)/crypto/md4/md4_locl.h $(OPENSSL_PATH)/crypto/evp/m_md5.c $(OPENSSL_PATH)/crypto/evp/m_md5_sha1.c $(OPENSSL_PATH)/crypto/evp/m_mdc2.c @@ -304,13 +281,11 @@ $(OPENSSL_PATH)/crypto/evp/pmeth_fn.c $(OPENSSL_PATH)/crypto/evp/pmeth_gn.c $(OPENSSL_PATH)/crypto/evp/pmeth_lib.c - $(OPENSSL_PATH)/crypto/evp/evp_locl.h $(OPENSSL_PATH)/crypto/ex_data.c $(OPENSSL_PATH)/crypto/getenv.c $(OPENSSL_PATH)/crypto/hmac/hm_ameth.c $(OPENSSL_PATH)/crypto/hmac/hm_pmeth.c $(OPENSSL_PATH)/crypto/hmac/hmac.c - $(OPENSSL_PATH)/crypto/hmac/hmac_lcl.h $(OPENSSL_PATH)/crypto/init.c $(OPENSSL_PATH)/crypto/kdf/hkdf.c $(OPENSSL_PATH)/crypto/kdf/kdf_err.c @@ -318,12 +293,10 @@ $(OPENSSL_PATH)/crypto/kdf/tls1_prf.c $(OPENSSL_PATH)/crypto/lhash/lh_stats.c $(OPENSSL_PATH)/crypto/lhash/lhash.c - $(OPENSSL_PATH)/crypto/lhash/lhash_lcl.h $(OPENSSL_PATH)/crypto/md4/md4_dgst.c $(OPENSSL_PATH)/crypto/md4/md4_one.c $(OPENSSL_PATH)/crypto/md5/md5_dgst.c $(OPENSSL_PATH)/crypto/md5/md5_one.c - $(OPENSSL_PATH)/crypto/md5/md5_locl.h $(OPENSSL_PATH)/crypto/mem.c $(OPENSSL_PATH)/crypto/mem_clr.c $(OPENSSL_PATH)/crypto/mem_dbg.c @@ -338,7 +311,6 @@ $(OPENSSL_PATH)/crypto/modes/ofb128.c $(OPENSSL_PATH)/crypto/modes/wrap128.c $(OPENSSL_PATH)/crypto/modes/xts128.c - $(OPENSSL_PATH)/crypto/modes/modes_lcl.h $(OPENSSL_PATH)/crypto/o_dir.c $(OPENSSL_PATH)/crypto/o_fips.c $(OPENSSL_PATH)/crypto/o_fopen.c @@ -350,9 +322,6 @@ $(OPENSSL_PATH)/crypto/objects/obj_err.c $(OPENSSL_PATH)/crypto/objects/obj_lib.c $(OPENSSL_PATH)/crypto/objects/obj_xref.c - $(OPENSSL_PATH)/crypto/objects/obj_dat.h - $(OPENSSL_PATH)/crypto/objects/obj_xref.h - $(OPENSSL_PATH)/crypto/objects/obj_lcl.h $(OPENSSL_PATH)/crypto/ocsp/ocsp_asn.c $(OPENSSL_PATH)/crypto/ocsp/ocsp_cl.c $(OPENSSL_PATH)/crypto/ocsp/ocsp_err.c @@ -363,7 +332,6 @@ $(OPENSSL_PATH)/crypto/ocsp/ocsp_srv.c $(OPENSSL_PATH)/crypto/ocsp/ocsp_vfy.c $(OPENSSL_PATH)/crypto/ocsp/v3_ocsp.c - $(OPENSSL_PATH)/crypto/ocsp/ocsp_lcl.h $(OPENSSL_PATH)/crypto/pem/pem_all.c $(OPENSSL_PATH)/crypto/pem/pem_err.c $(OPENSSL_PATH)/crypto/pem/pem_info.c @@ -399,8 +367,6 @@ $(OPENSSL_PATH)/crypto/pkcs7/pk7_mime.c $(OPENSSL_PATH)/crypto/pkcs7/pk7_smime.c $(OPENSSL_PATH)/crypto/pkcs7/pkcs7err.c - $(OPENSSL_PATH)/crypto/pkcs12/p12_lcl.h - $(OPENSSL_PATH)/crypto/ppc_arch.h $(OPENSSL_PATH)/crypto/rand/drbg_ctr.c $(OPENSSL_PATH)/crypto/rand/drbg_lib.c $(OPENSSL_PATH)/crypto/rand/rand_egd.c @@ -409,10 +375,8 @@ $(OPENSSL_PATH)/crypto/rand/rand_unix.c $(OPENSSL_PATH)/crypto/rand/rand_vms.c $(OPENSSL_PATH)/crypto/rand/rand_win.c - $(OPENSSL_PATH)/crypto/rand/rand_lcl.h $(OPENSSL_PATH)/crypto/rc4/rc4_enc.c $(OPENSSL_PATH)/crypto/rc4/rc4_skey.c - $(OPENSSL_PATH)/crypto/rc4/rc4_locl.h $(OPENSSL_PATH)/crypto/rsa/rsa_ameth.c $(OPENSSL_PATH)/crypto/rsa/rsa_asn1.c $(OPENSSL_PATH)/crypto/rsa/rsa_chk.c @@ -435,24 +399,18 @@ $(OPENSSL_PATH)/crypto/rsa/rsa_ssl.c $(OPENSSL_PATH)/crypto/rsa/rsa_x931.c $(OPENSSL_PATH)/crypto/rsa/rsa_x931g.c - $(OPENSSL_PATH)/crypto/rsa/rsa_locl.h $(OPENSSL_PATH)/crypto/sha/keccak1600.c $(OPENSSL_PATH)/crypto/sha/sha1_one.c $(OPENSSL_PATH)/crypto/sha/sha1dgst.c $(OPENSSL_PATH)/crypto/sha/sha256.c $(OPENSSL_PATH)/crypto/sha/sha512.c - $(OPENSSL_PATH)/crypto/sha/sha_locl.h $(OPENSSL_PATH)/crypto/siphash/siphash.c $(OPENSSL_PATH)/crypto/siphash/siphash_ameth.c $(OPENSSL_PATH)/crypto/siphash/siphash_pmeth.c - $(OPENSSL_PATH)/crypto/siphash/siphash_local.h $(OPENSSL_PATH)/crypto/sm3/m_sm3.c $(OPENSSL_PATH)/crypto/sm3/sm3.c - $(OPENSSL_PATH)/crypto/sm3/sm3_locl.h $(OPENSSL_PATH)/crypto/sm4/sm4.c $(OPENSSL_PATH)/crypto/stack/stack.c - $(OPENSSL_PATH)/crypto/s390x_arch.h - $(OPENSSL_PATH)/crypto/sparc_arch.h $(OPENSSL_PATH)/crypto/threads_none.c $(OPENSSL_PATH)/crypto/threads_pthread.c $(OPENSSL_PATH)/crypto/threads_win.c @@ -462,9 +420,7 @@ $(OPENSSL_PATH)/crypto/ui/ui_null.c $(OPENSSL_PATH)/crypto/ui/ui_openssl.c $(OPENSSL_PATH)/crypto/ui/ui_util.c - $(OPENSSL_PATH)/crypto/ui/ui_locl.h $(OPENSSL_PATH)/crypto/uid.c - $(OPENSSL_PATH)/crypto/vms_rms.h $(OPENSSL_PATH)/crypto/x509/by_dir.c $(OPENSSL_PATH)/crypto/x509/by_file.c $(OPENSSL_PATH)/crypto/x509/t_crl.c @@ -501,7 +457,6 @@ $(OPENSSL_PATH)/crypto/x509/x_req.c $(OPENSSL_PATH)/crypto/x509/x_x509.c $(OPENSSL_PATH)/crypto/x509/x_x509a.c - $(OPENSSL_PATH)/crypto/x509/x509_lcl.h $(OPENSSL_PATH)/crypto/x509v3/pcy_cache.c $(OPENSSL_PATH)/crypto/x509v3/pcy_data.c $(OPENSSL_PATH)/crypto/x509v3/pcy_lib.c @@ -539,10 +494,57 @@ $(OPENSSL_PATH)/crypto/x509v3/v3_tlsf.c $(OPENSSL_PATH)/crypto/x509v3/v3_utl.c $(OPENSSL_PATH)/crypto/x509v3/v3err.c + $(OPENSSL_PATH)/crypto/hmac/hmac_lcl.h + $(OPENSSL_PATH)/crypto/dh/dh_locl.h + $(OPENSSL_PATH)/crypto/bio/bio_lcl.h + $(OPENSSL_PATH)/crypto/conf/conf_def.h + $(OPENSSL_PATH)/crypto/conf/conf_lcl.h + $(OPENSSL_PATH)/crypto/lhash/lhash_lcl.h + $(OPENSSL_PATH)/crypto/sha/sha_locl.h + $(OPENSSL_PATH)/crypto/md5/md5_locl.h + $(OPENSSL_PATH)/crypto/store/store_locl.h + $(OPENSSL_PATH)/crypto/dso/dso_locl.h + $(OPENSSL_PATH)/crypto/pkcs12/p12_lcl.h + $(OPENSSL_PATH)/crypto/arm_arch.h + $(OPENSSL_PATH)/crypto/mips_arch.h + $(OPENSSL_PATH)/crypto/ppc_arch.h + $(OPENSSL_PATH)/crypto/s390x_arch.h + $(OPENSSL_PATH)/crypto/sparc_arch.h + $(OPENSSL_PATH)/crypto/vms_rms.h + $(OPENSSL_PATH)/crypto/bn/bn_lcl.h + $(OPENSSL_PATH)/crypto/bn/bn_prime.h + $(OPENSSL_PATH)/crypto/bn/rsaz_exp.h + $(OPENSSL_PATH)/crypto/ui/ui_locl.h + $(OPENSSL_PATH)/crypto/md4/md4_locl.h + $(OPENSSL_PATH)/crypto/rc4/rc4_locl.h + $(OPENSSL_PATH)/crypto/asn1/asn1_item_list.h + $(OPENSSL_PATH)/crypto/asn1/asn1_locl.h + $(OPENSSL_PATH)/crypto/asn1/charmap.h + $(OPENSSL_PATH)/crypto/asn1/standard_methods.h + $(OPENSSL_PATH)/crypto/asn1/tbl_standard.h + $(OPENSSL_PATH)/crypto/evp/evp_locl.h + $(OPENSSL_PATH)/crypto/rand/rand_lcl.h + $(OPENSSL_PATH)/crypto/ocsp/ocsp_lcl.h + $(OPENSSL_PATH)/crypto/modes/modes_lcl.h + $(OPENSSL_PATH)/crypto/comp/comp_lcl.h + $(OPENSSL_PATH)/crypto/rsa/rsa_locl.h + $(OPENSSL_PATH)/crypto/x509/x509_lcl.h + $(OPENSSL_PATH)/crypto/async/arch/async_null.h + $(OPENSSL_PATH)/crypto/async/arch/async_posix.h + $(OPENSSL_PATH)/crypto/async/arch/async_win.h + $(OPENSSL_PATH)/crypto/sm3/sm3_locl.h + $(OPENSSL_PATH)/crypto/des/des_locl.h + $(OPENSSL_PATH)/crypto/des/spr.h + $(OPENSSL_PATH)/crypto/siphash/siphash_local.h + $(OPENSSL_PATH)/crypto/aes/aes_locl.h + $(OPENSSL_PATH)/crypto/async/async_locl.h + $(OPENSSL_PATH)/crypto/x509v3/ext_dat.h $(OPENSSL_PATH)/crypto/x509v3/pcy_int.h - $(OPENSSL_PATH)/crypto/x509v3/v3_admis.h $(OPENSSL_PATH)/crypto/x509v3/standard_exts.h - $(OPENSSL_PATH)/crypto/x509v3/ext_dat.h + $(OPENSSL_PATH)/crypto/x509v3/v3_admis.h + $(OPENSSL_PATH)/crypto/objects/obj_dat.h + $(OPENSSL_PATH)/crypto/objects/obj_lcl.h + $(OPENSSL_PATH)/crypto/objects/obj_xref.h # Autogenerated files list ends here buildinf.h rand_pool_noise.h @@ -610,7 +612,7 @@ GCC:*_*_AARCH64_CC_FLAGS = $(OPENSSL_FLAGS) -Wno-error=maybe-uninitialized -Wno-format -Wno-error=unused-but-set-variable GCC:*_CLANG35_*_CC_FLAGS = -std=c99 -Wno-error=uninitialized GCC:*_CLANG38_*_CC_FLAGS = -std=c99 -Wno-error=uninitialized - GCC:*_CLANG9_*_CC_FLAGS = -std=c99 -Wno-error=uninitialized -Wno-error=incompatible-pointer-types -Wno-error=pointer-sign -Wno-error=implicit-function-declaration -Wno-error=ignored-pragma-optimize + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=uninitialized -Wno-error=incompatible-pointer-types -Wno-error=pointer-sign -Wno-error=implicit-function-declaration -Wno-error=ignored-pragma-optimize # suppress the following warnings in openssl so we don't break the build with warnings-as-errors: # 1295: Deprecated declaration - give arg types diff --git a/CryptoPkg/Library/OpensslLib/openssl b/CryptoPkg/Library/OpensslLib/openssl index 50eaac9f333..c3656cc594d 160000 --- a/CryptoPkg/Library/OpensslLib/openssl +++ b/CryptoPkg/Library/OpensslLib/openssl @@ -1 +1 @@ -Subproject commit 50eaac9f3337667259de725451f201e784599687 +Subproject commit c3656cc594daac8167721dde7220f0e59ae146fc diff --git a/CryptoPkg/Library/OpensslLib/process_files.pl b/CryptoPkg/Library/OpensslLib/process_files.pl index e13c0acb4dd..bbcfa0d0e70 100755 --- a/CryptoPkg/Library/OpensslLib/process_files.pl +++ b/CryptoPkg/Library/OpensslLib/process_files.pl @@ -2,7 +2,7 @@ # # This script runs the OpenSSL Configure script, then processes the # resulting file list into our local OpensslLib[Crypto].inf and also -# takes a copy of opensslconf.h. +# takes copies of opensslconf.h and dso_conf.h. # # This only needs to be done once by a developer when updating to a # new version of OpenSSL (or changing options, etc.). Normal users @@ -106,6 +106,14 @@ BEGIN ) == 0 || die "Failed to generate opensslconf.h!\n"; + # Generate dso_conf.h per config data + system( + "perl -I. -Mconfigdata util/dofile.pl " . + "crypto/include/internal/dso_conf.h.in " . + "> include/internal/dso_conf.h" + ) == 0 || + die "Failed to generate dso_conf.h!\n"; + chdir($basedir) || die "Cannot change to base directory \"" . $basedir . "\""; @@ -144,6 +152,34 @@ BEGIN } } + +# +# Update the perl script to generate the missing header files +# +my @dir_list = (); +for (keys %{$unified_info{dirinfo}}){ + push @dir_list,$_; +} + +my $dir = getcwd(); +my @files = (); +my @headers = (); +chdir ("openssl"); +foreach(@dir_list){ + @files = glob($_."/*.h"); + push @headers, @files; +} +chdir ($dir); + +foreach (@headers){ + if(/ssl/){ + push @sslfilelist, ' $(OPENSSL_PATH)/' . $_ . "\r\n"; + next; + } + push @cryptofilelist, ' $(OPENSSL_PATH)/' . $_ . "\r\n"; +} + + # # Update OpensslLib.inf with autogenerated file list # @@ -221,12 +257,17 @@ BEGIN print "Done!"; # -# Copy opensslconf.h generated from OpenSSL Configuration +# Copy opensslconf.h and dso_conf.h generated from OpenSSL Configuration # print "\n--> Duplicating opensslconf.h into Include/openssl ... "; copy($OPENSSL_PATH . "/include/openssl/opensslconf.h", $OPENSSL_PATH . "/../../Include/openssl/") || die "Cannot copy opensslconf.h!"; +print "Done!"; +print "\n--> Duplicating dso_conf.h into Include/internal ... "; +copy($OPENSSL_PATH . "/include/internal/dso_conf.h", + $OPENSSL_PATH . "/../../Include/internal/") || + die "Cannot copy dso_conf.h!"; print "Done!\n"; print "\nProcessing Files Done!\n"; diff --git a/CryptoPkg/Library/TlsLib/TlsConfig.c b/CryptoPkg/Library/TlsLib/TlsConfig.c index 74b577d60ee..307eb57896d 100644 --- a/CryptoPkg/Library/TlsLib/TlsConfig.c +++ b/CryptoPkg/Library/TlsLib/TlsConfig.c @@ -1,7 +1,7 @@ /** @file SSL/TLS Configuration Library Wrapper Implementation over OpenSSL. -Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
(C) Copyright 2016 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -497,6 +497,62 @@ TlsSetVerify ( SSL_set_verify (TlsConn->Ssl, VerifyMode, NULL); } +/** + Set the specified host name to be verified. + + @param[in] Tls Pointer to the TLS object. + @param[in] Flags The setting flags during the validation. + @param[in] HostName The specified host name to be verified. + + @retval EFI_SUCCESS The HostName setting was set successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_ABORTED Invalid HostName setting. + +**/ +EFI_STATUS +EFIAPI +TlsSetVerifyHost ( + IN VOID *Tls, + IN UINT32 Flags, + IN CHAR8 *HostName + ) +{ + TLS_CONNECTION *TlsConn; + X509_VERIFY_PARAM *VerifyParam; + UINTN BinaryAddressSize; + UINT8 BinaryAddress[MAX (NS_INADDRSZ, NS_IN6ADDRSZ)]; + INTN ParamStatus; + + TlsConn = (TLS_CONNECTION *) Tls; + if (TlsConn == NULL || TlsConn->Ssl == NULL || HostName == NULL) { + return EFI_INVALID_PARAMETER; + } + + SSL_set_hostflags(TlsConn->Ssl, Flags); + + VerifyParam = SSL_get0_param (TlsConn->Ssl); + ASSERT (VerifyParam != NULL); + + BinaryAddressSize = 0; + if (inet_pton (AF_INET6, HostName, BinaryAddress) == 1) { + BinaryAddressSize = NS_IN6ADDRSZ; + } else if (inet_pton (AF_INET, HostName, BinaryAddress) == 1) { + BinaryAddressSize = NS_INADDRSZ; + } + + if (BinaryAddressSize > 0) { + DEBUG ((DEBUG_VERBOSE, "%a:%a: parsed \"%a\" as an IPv%c address " + "literal\n", gEfiCallerBaseName, __FUNCTION__, HostName, + (UINTN)((BinaryAddressSize == NS_IN6ADDRSZ) ? '6' : '4'))); + ParamStatus = X509_VERIFY_PARAM_set1_ip (VerifyParam, BinaryAddress, + BinaryAddressSize); + } else { + ParamStatus = X509_VERIFY_PARAM_set1_host (VerifyParam, HostName, 0); + } + + return (ParamStatus == 1) ? EFI_SUCCESS : EFI_ABORTED; +} + /** Sets a TLS/SSL session ID to be used during TLS/SSL connect. diff --git a/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c b/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c index 907d46a495e..a6ac30c32a6 100644 --- a/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c +++ b/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c @@ -124,18 +124,21 @@ DtPlatformDxeEntryPoint ( Status = gRT->GetVariable(DT_ACPI_VARIABLE_NAME, &gDtPlatformFormSetGuid, NULL, &BufferSize, &DtAcpiPref); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, "%a: no DT/ACPI preference found, defaulting to DT\n", - __FUNCTION__)); - DtAcpiPref.Pref = DT_ACPI_SELECT_DT; + DEBUG ((DEBUG_WARN, "%a: no DT/ACPI preference found, defaulting to %a\n", + __FUNCTION__, PcdGetBool (PcdDefaultDtPref) ? "DT" : "ACPI")); + DtAcpiPref.Pref = PcdGetBool (PcdDefaultDtPref) ? DT_ACPI_SELECT_DT + : DT_ACPI_SELECT_ACPI; } } if (!EFI_ERROR (Status) && DtAcpiPref.Pref != DT_ACPI_SELECT_ACPI && DtAcpiPref.Pref != DT_ACPI_SELECT_DT) { - DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to DT\n", - __FUNCTION__, DT_ACPI_VARIABLE_NAME)); - DtAcpiPref.Pref = DT_ACPI_SELECT_DT; + DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to %a\n", + __FUNCTION__, DT_ACPI_VARIABLE_NAME, + PcdGetBool (PcdDefaultDtPref) ? "DT" : "ACPI")); + DtAcpiPref.Pref = PcdGetBool (PcdDefaultDtPref) ? DT_ACPI_SELECT_DT + : DT_ACPI_SELECT_ACPI; Status = EFI_INVALID_PARAMETER; // trigger setvar below } diff --git a/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf b/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf index b68f154182a..450ea29b4a2 100644 --- a/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf +++ b/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf @@ -46,6 +46,9 @@ gEdkiiPlatformHasAcpiGuid gFdtTableGuid +[Pcd] + gEmbeddedTokenSpaceGuid.PcdDefaultDtPref + [Depex] gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid diff --git a/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c b/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c new file mode 100644 index 00000000000..4b0afe47de4 --- /dev/null +++ b/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c @@ -0,0 +1,257 @@ +/** @file + + Copyright (c) 2019, Linaro, Ltd. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +/** + Set IOMMU attribute for a system memory. + + If the IOMMU protocol exists, the system memory cannot be used + for DMA by default. + + When a device requests a DMA access for a system memory, + the device driver need use SetAttribute() to update the IOMMU + attribute to request DMA access (read and/or write). + + The DeviceHandle is used to identify which device submits the request. + The IOMMU implementation need translate the device path to an IOMMU device + ID, and set IOMMU hardware register accordingly. + 1) DeviceHandle can be a standard PCI device. + The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ. + The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE. + The memory for BusMasterCommonBuffer need set + EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE. + After the memory is used, the memory need set 0 to keep it being + protected. + 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc). + The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or + EDKII_IOMMU_ACCESS_WRITE. + + @param[in] This The protocol instance pointer. + @param[in] DeviceHandle The device who initiates the DMA access + request. + @param[in] Mapping The mapping value returned from Map(). + @param[in] IoMmuAccess The IOMMU access. + + @retval EFI_SUCCESS The IoMmuAccess is set for the memory range + specified by DeviceAddress and Length. + @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by + Map(). + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination + of access. + @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU. + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported + by the IOMMU. + @retval EFI_UNSUPPORTED The IOMMU does not support the memory range + specified by Mapping. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + modify the IOMMU access. + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while + attempting the operation. + +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuSetAttribute ( + IN EDKII_IOMMU_PROTOCOL *This, + IN EFI_HANDLE DeviceHandle, + IN VOID *Mapping, + IN UINT64 IoMmuAccess + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Provides the controller-specific addresses required to access system memory + from a DMA bus master. On SEV guest, the DMA operations must be performed on + shared buffer hence we allocate a bounce buffer to map the HostAddress to a + DeviceAddress. The Encryption attribute is removed from the DeviceAddress + buffer. + + @param This The protocol instance pointer. + @param Operation Indicates if the bus master is going to read or + write to system memory. + @param HostAddress The system memory address to map to the PCI + controller. + @param NumberOfBytes On input the number of bytes to map. On output + the number of bytes that were mapped. + @param DeviceAddress The resulting map address for the bus master + PCI controller to use to access the hosts + HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned + NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common + buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested + address. + +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuMap ( + IN EDKII_IOMMU_PROTOCOL *This, + IN EDKII_IOMMU_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + DMA_MAP_OPERATION DmaOperation; + + switch (Operation) { + case EdkiiIoMmuOperationBusMasterRead: + case EdkiiIoMmuOperationBusMasterRead64: + DmaOperation = MapOperationBusMasterRead; + break; + + case EdkiiIoMmuOperationBusMasterWrite: + case EdkiiIoMmuOperationBusMasterWrite64: + DmaOperation = MapOperationBusMasterWrite; + break; + + case EdkiiIoMmuOperationBusMasterCommonBuffer: + case EdkiiIoMmuOperationBusMasterCommonBuffer64: + DmaOperation = MapOperationBusMasterCommonBuffer; + break; + + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return DmaMap (DmaOperation, HostAddress, NumberOfBytes, + DeviceAddress, Mapping); +} + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This The protocol instance pointer. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by + Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system + memory. +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuUnmap ( + IN EDKII_IOMMU_PROTOCOL *This, + IN VOID *Mapping + ) +{ + return DmaUnmap (Mapping); +} + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param This The protocol instance pointer. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, + EfiBootServicesData or EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory + address of the allocated range. + @param Attributes The requested bit mask of attributes for the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal + attribute bits are MEMORY_WRITE_COMBINE and + MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuAllocateBuffer ( + IN EDKII_IOMMU_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + return DmaAllocateBuffer (MemoryType, Pages, HostAddress); +} + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This The protocol instance pointer. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated + range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and + Pages was not allocated with AllocateBuffer(). + +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuFreeBuffer ( + IN EDKII_IOMMU_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + return DmaFreeBuffer (Pages, HostAddress); +} + +STATIC EDKII_IOMMU_PROTOCOL mNonCoherentIoMmuOps = { + EDKII_IOMMU_PROTOCOL_REVISION, + NonCoherentIoMmuSetAttribute, + NonCoherentIoMmuMap, + NonCoherentIoMmuUnmap, + NonCoherentIoMmuAllocateBuffer, + NonCoherentIoMmuFreeBuffer, +}; + + +EFI_STATUS +EFIAPI +NonCoherentIoMmuDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return gBS->InstallMultipleProtocolInterfaces (&ImageHandle, + &gEdkiiIoMmuProtocolGuid, &mNonCoherentIoMmuOps, + NULL); +} diff --git a/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf b/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf new file mode 100644 index 00000000000..de70cfb4cad --- /dev/null +++ b/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf @@ -0,0 +1,43 @@ +#/** @file +# +# Copyright (c) 2019, Linaro, Ltd. All rights reserved.
+# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR +# IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 1.27 + BASE_NAME = NonCoherentIoMmuDxe + FILE_GUID = 7ed510aa-9cdc-49d2-a306-6e11e359f9b3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = NonCoherentIoMmuDxeEntryPoint + +[Sources] + NonCoherentIoMmuDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + DmaLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEdkiiIoMmuProtocolGuid ## PRODUCES + +[Depex] + TRUE diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec index bbaadc5a17a..69922802f47 100644 --- a/EmbeddedPkg/EmbeddedPkg.dec +++ b/EmbeddedPkg/EmbeddedPkg.dec @@ -185,3 +185,14 @@ # truncation on overflow to specify negative offsets. # gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset|0x0|UINT64|0x0000058 + + # + # Highest address value supported by the device for DMA addressing. Note + # that this value should be strictly greater than PcdDmaDeviceOffset. + # + gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit|0xFFFFFFFFFFFFFFFF|UINT64|0x000005A + + # + # Selection between DT and ACPI as a default + # + gEmbeddedTokenSpaceGuid.PcdDefaultDtPref|TRUE|BOOLEAN|0x0000059 diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc index a8a151eb40c..8842acc4cbf 100644 --- a/EmbeddedPkg/EmbeddedPkg.dsc +++ b/EmbeddedPkg/EmbeddedPkg.dsc @@ -238,6 +238,11 @@ EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf + EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf { + + DmaLib|EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf + } + [Components.ARM] EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf diff --git a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c b/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c index 78220f6358a..11534576543 100644 --- a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c +++ b/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c @@ -40,6 +40,8 @@ typedef struct { STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; STATIC LIST_ENTRY UncachedAllocationList; +STATIC PHYSICAL_ADDRESS mDmaHostAddressLimit; + STATIC PHYSICAL_ADDRESS HostToDeviceAddress ( @@ -49,6 +51,102 @@ HostToDeviceAddress ( return (PHYSICAL_ADDRESS)(UINTN)Address + PcdGet64 (PcdDmaDeviceOffset); } +/** + Allocates one or more 4KB pages of a certain memory type at a specified + alignment. + + Allocates the number of 4KB pages specified by Pages of a certain memory type + with an alignment specified by Alignment. The allocated buffer is returned. + If Pages is 0, then NULL is returned. If there is not enough memory at the + specified alignment remaining to satisfy the request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param MemoryType The type of memory to allocate. + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. + Must be a power of two. + If Alignment is zero, then byte alignment is + used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +STATIC +VOID * +InternalAllocateAlignedPages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Memory; + UINTN AlignedMemory; + UINTN AlignmentMask; + UINTN UnalignedPages; + UINTN RealPages; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Pages == 0) { + return NULL; + } + if (Alignment > EFI_PAGE_SIZE) { + // + // Calculate the total number of pages since alignment is larger than page + // size. + // + AlignmentMask = Alignment - 1; + RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); + // + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not + // overflow. + // + ASSERT (RealPages > Pages); + + Memory = mDmaHostAddressLimit; + Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, RealPages, + &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask; + UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory); + if (UnalignedPages > 0) { + // + // Free first unaligned page(s). + // + Status = gBS->FreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages); + UnalignedPages = RealPages - Pages - UnalignedPages; + if (UnalignedPages > 0) { + // + // Free last unaligned page(s). + // + Status = gBS->FreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + } else { + // + // Do not over-allocate pages in this case. + // + Memory = mDmaHostAddressLimit; + Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, + &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = (UINTN)Memory; + } + return (VOID *)AlignedMemory; +} + /** Provides the DMA controller-specific addresses needed to access system memory. @@ -111,7 +209,30 @@ DmaMap ( return EFI_OUT_OF_RESOURCES; } - if (Operation != MapOperationBusMasterRead && + if (((UINTN)HostAddress + *NumberOfBytes) > mDmaHostAddressLimit) { + + if (Operation == MapOperationBusMasterCommonBuffer) { + goto CommonBufferError; + } + + AllocSize = ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment); + Map->BufferAddress = InternalAllocateAlignedPages (EfiBootServicesData, + EFI_SIZE_TO_PAGES (AllocSize), + mCpu->DmaBufferAlignment); + if (Map->BufferAddress == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMapInfo; + } + + if (Map->Operation == MapOperationBusMasterRead) { + CopyMem (Map->BufferAddress, (VOID *)(UINTN)Map->HostAddress, + *NumberOfBytes); + } + mCpu->FlushDataCache (mCpu, (UINTN)Map->BufferAddress, AllocSize, + EfiCpuFlushTypeWriteBack); + + *DeviceAddress = HostToDeviceAddress (Map->BufferAddress); + } else if (Operation != MapOperationBusMasterRead && ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) != 0) || ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) != 0))) { @@ -128,12 +249,7 @@ DmaMap ( // on uncached buffers. // if (Operation == MapOperationBusMasterCommonBuffer) { - DEBUG ((DEBUG_ERROR, - "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only " - "supported\non memory regions that were allocated using " - "DmaAllocateBuffer ()\n", __FUNCTION__)); - Status = EFI_UNSUPPORTED; - goto FreeMapInfo; + goto CommonBufferError; } // @@ -199,6 +315,12 @@ DmaMap ( return EFI_SUCCESS; +CommonBufferError: + DEBUG ((DEBUG_ERROR, + "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only " + "supported\non memory regions that were allocated using " + "DmaAllocateBuffer ()\n", __FUNCTION__)); + Status = EFI_UNSUPPORTED; FreeMapInfo: FreePool (Map); @@ -229,6 +351,7 @@ DmaUnmap ( MAP_INFO_INSTANCE *Map; EFI_STATUS Status; VOID *Buffer; + UINTN AllocSize; if (Mapping == NULL) { ASSERT (FALSE); @@ -238,7 +361,17 @@ DmaUnmap ( Map = (MAP_INFO_INSTANCE *)Mapping; Status = EFI_SUCCESS; - if (Map->DoubleBuffer) { + if (((UINTN)Map->HostAddress + Map->NumberOfBytes) > mDmaHostAddressLimit) { + AllocSize = ALIGN_VALUE (Map->NumberOfBytes, mCpu->DmaBufferAlignment); + if (Map->Operation == MapOperationBusMasterWrite) { + mCpu->FlushDataCache (mCpu, (UINTN)Map->BufferAddress, AllocSize, + EfiCpuFlushTypeInvalidate); + CopyMem ((VOID *)(UINTN)Map->HostAddress, Map->BufferAddress, + Map->NumberOfBytes); + } + FreePages (Map->BufferAddress, EFI_SIZE_TO_PAGES (AllocSize)); + } else if (Map->DoubleBuffer) { + ASSERT (Map->Operation == MapOperationBusMasterWrite); if (Map->Operation != MapOperationBusMasterWrite) { @@ -335,10 +468,9 @@ DmaAllocateAlignedBuffer ( return EFI_INVALID_PARAMETER; } - if (MemoryType == EfiBootServicesData) { - Allocation = AllocateAlignedPages (Pages, Alignment); - } else if (MemoryType == EfiRuntimeServicesData) { - Allocation = AllocateAlignedRuntimePages (Pages, Alignment); + if (MemoryType == EfiBootServicesData || + MemoryType == EfiRuntimeServicesData) { + Allocation = InternalAllocateAlignedPages (MemoryType, Pages, Alignment); } else { return EFI_INVALID_PARAMETER; } @@ -479,6 +611,15 @@ NonCoherentDmaLibConstructor ( { InitializeListHead (&UncachedAllocationList); + // + // Ensure that the combination of DMA addressing offset and limit produces + // a sane value. + // + ASSERT (PcdGet64 (PcdDmaDeviceLimit) > PcdGet64 (PcdDmaDeviceOffset)); + + mDmaHostAddressLimit = PcdGet64 (PcdDmaDeviceLimit) - + PcdGet64 (PcdDmaDeviceOffset); + // Get the Cpu protocol for later use return gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu); } diff --git a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf b/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf index 2db751afee9..1a21cfe4ff2 100644 --- a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf +++ b/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf @@ -38,6 +38,7 @@ [Pcd] gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset + gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit [Depex] gEfiCpuArchProtocolGuid diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc index 109685b0627..1fc924ae5a1 100644 --- a/EmulatorPkg/EmulatorPkg.dsc +++ b/EmulatorPkg/EmulatorPkg.dsc @@ -240,7 +240,7 @@ !if "MSFT" in $(FAMILY) || $(WIN_HOST_BUILD) == TRUE ## # Emulator, OS WIN application - # CLANG9 is cross OS tool chain. It depends on WIN_HOST_BUILD flag + # CLANGPDB is cross OS tool chain. It depends on WIN_HOST_BUILD flag # to build WinHost application. ## EmulatorPkg/Win/Host/WinHost.inf @@ -421,7 +421,7 @@ MSFT:DEBUG_*_*_CC_FLAGS = /Od /Oy- MSFT:NOOPT_*_*_CC_FLAGS = /Od /Oy- - GCC:DEBUG_CLANG9_*_CC_FLAGS =-O0 -Wno-unused-command-line-argument -Wno-incompatible-pointer-types -Wno-enum-conversion -Wno-incompatible-pointer-types -Wno-sometimes-uninitialized -Wno-constant-conversion -Wno-main-return-type + GCC:DEBUG_CLANGPDB_*_CC_FLAGS =-O0 -Wno-unused-command-line-argument -Wno-incompatible-pointer-types -Wno-enum-conversion -Wno-incompatible-pointer-types -Wno-sometimes-uninitialized -Wno-constant-conversion -Wno-main-return-type MSFT:*_*_*_DLINK_FLAGS = /ALIGN:4096 /FILEALIGN:4096 /SUBSYSTEM:CONSOLE MSFT:DEBUG_*_*_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /BASE:0x10000 @@ -429,9 +429,9 @@ !if $(WIN_HOST_BUILD) == TRUE # - # CLANG9 tool chain depends on WIN_HOST_BUILD flag to generate the windows application. + # CLANGPDB tool chain depends on WIN_HOST_BUILD flag to generate the windows application. # - GCC:*_CLANG9_*_DLINK_FLAGS = /ALIGN:4096 /FILEALIGN:4096 /SUBSYSTEM:CONSOLE - GCC:DEBUG_CLANG9_*_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /BASE:0x10000 - GCC:NOOPT_CLANG9_*_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /BASE:0x10000 + GCC:*_CLANGPDB_*_DLINK_FLAGS = /ALIGN:4096 /FILEALIGN:4096 /SUBSYSTEM:CONSOLE + GCC:DEBUG_CLANGPDB_*_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /BASE:0x10000 + GCC:NOOPT_CLANGPDB_*_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /BASE:0x10000 !endif diff --git a/EmulatorPkg/PlatformSmbiosDxe/PlatformSmbiosDxe.c b/EmulatorPkg/PlatformSmbiosDxe/PlatformSmbiosDxe.c index e6f87346002..48a3bfb5e97 100644 --- a/EmulatorPkg/PlatformSmbiosDxe/PlatformSmbiosDxe.c +++ b/EmulatorPkg/PlatformSmbiosDxe/PlatformSmbiosDxe.c @@ -82,7 +82,7 @@ CreatePlatformSmbiosMemoryRecords ( **/ EFI_STATUS EFIAPI -PlatfomrSmbiosDriverEntryPoint ( +PlatformSmbiosDriverEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) diff --git a/EmulatorPkg/PlatformSmbiosDxe/PlatformSmbiosDxe.inf b/EmulatorPkg/PlatformSmbiosDxe/PlatformSmbiosDxe.inf index 95b119e9530..756f643c740 100644 --- a/EmulatorPkg/PlatformSmbiosDxe/PlatformSmbiosDxe.inf +++ b/EmulatorPkg/PlatformSmbiosDxe/PlatformSmbiosDxe.inf @@ -15,7 +15,7 @@ FILE_GUID = 67FA951E-4FA2-9F4E-A658-4DBD954AC22E MODULE_TYPE = DXE_DRIVER VERSION_STRING = 1.0 - ENTRY_POINT = PlatfomrSmbiosDriverEntryPoint + ENTRY_POINT = PlatformSmbiosDriverEntryPoint [Sources] diff --git a/EmulatorPkg/Win/Host/WinHost.inf b/EmulatorPkg/Win/Host/WinHost.inf index 1adca10d79d..e0b3ecb15bf 100644 --- a/EmulatorPkg/Win/Host/WinHost.inf +++ b/EmulatorPkg/Win/Host/WinHost.inf @@ -96,8 +96,8 @@ MSFT:*_*_X64_ASM_FLAGS == /nologo /W3 /WX /c /Cx /Zd /W0 /Zi MSFT:*_*_X64_ASMLINK_FLAGS == /link /nologo - GCC:*_CLANG9_X64_DLINK_FLAGS == /out:"$(BIN_DIR)\$(BASE_NAME).exe" /base:0x10000000 /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" /LIBPATH:"%VCToolsInstallDir%lib\x64" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /OPT:REF /DEBUG /MACHINE:AMD64 Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib /lldmap /EXPORT:InitializeDriver=_ModuleEntryPoint - GCC:*_CLANG9_X64_CC_FLAGS == -m64 -g -fshort-wchar -fno-strict-aliasing -Wall -c -include AutoGen.h -D _CRT_SECURE_NO_WARNINGS -Wnonportable-include-path -D UNICODE -D _CRT_SECURE_NO_DEPRECATE + GCC:*_CLANGPDB_X64_DLINK_FLAGS == /out:"$(BIN_DIR)\$(BASE_NAME).exe" /base:0x10000000 /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" /LIBPATH:"%VCToolsInstallDir%lib\x64" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /OPT:REF /DEBUG /MACHINE:AMD64 Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib /lldmap /EXPORT:InitializeDriver=_ModuleEntryPoint + GCC:*_CLANGPDB_X64_CC_FLAGS == -m64 -g -fshort-wchar -fno-strict-aliasing -Wall -c -include AutoGen.h -D _CRT_SECURE_NO_WARNINGS -Wnonportable-include-path -D UNICODE -D _CRT_SECURE_NO_DEPRECATE - GCC:*_CLANG9_IA32_DLINK_FLAGS == /out:"$(BIN_DIR)\$(BASE_NAME).exe" /base:0x10000000 /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" /LIBPATH:"%VCToolsInstallDir%ib\x86" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /OPT:REF /DEBUG /MACHINE:I386 Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib /lldmap /EXPORT:InitializeDriver=_ModuleEntryPoint - GCC:*_CLANG9_IA32_CC_FLAGS == -m32 -g -fshort-wchar -fno-strict-aliasing -Wall -c -include AutoGen.h -D _CRT_SECURE_NO_WARNINGS -Wnonportable-include-path -D UNICODE -D _CRT_SECURE_NO_DEPRECATE + GCC:*_CLANGPDB_IA32_DLINK_FLAGS == /out:"$(BIN_DIR)\$(BASE_NAME).exe" /base:0x10000000 /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" /LIBPATH:"%VCToolsInstallDir%ib\x86" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /OPT:REF /DEBUG /MACHINE:I386 Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib /lldmap /EXPORT:InitializeDriver=_ModuleEntryPoint + GCC:*_CLANGPDB_IA32_CC_FLAGS == -m32 -g -fshort-wchar -fno-strict-aliasing -Wall -c -include AutoGen.h -D _CRT_SECURE_NO_WARNINGS -Wnonportable-include-path -D UNICODE -D _CRT_SECURE_NO_DEPRECATE diff --git a/FatPkg/FatPkg.ci.yaml b/FatPkg/FatPkg.ci.yaml new file mode 100644 index 00000000000..8b0fb1d4fcd --- /dev/null +++ b/FatPkg/FatPkg.ci.yaml @@ -0,0 +1,50 @@ +## @file +# CI configuration for FatPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "CompilerPlugin": { + "DscPath": "FatPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "IgnoreInf": [], + "DscPath": "FatPkg.dsc" + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + "SpellCheck": { + "ExtendWords": [ + "ELTORITO", + "FHAND", + "IFILE", + "OFILE", + "FDISKed", + "Lfnbuffer", + "FFFFFFFFL", + "CDVOL", + "DMDEPKG" + ] + } +} diff --git a/FmpDevicePkg/FmpDevicePkg.ci.yaml b/FmpDevicePkg/FmpDevicePkg.ci.yaml new file mode 100644 index 00000000000..c17b355d428 --- /dev/null +++ b/FmpDevicePkg/FmpDevicePkg.ci.yaml @@ -0,0 +1,43 @@ +## @file +# CI configuration for FmpDevicePkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "CompilerPlugin": { + "DscPath": "FmpDevicePkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "FmpDevicePkg/FmpDevicePkg.dec", + "CryptoPkg/CryptoPkg.dec" + ], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "FmpDevicePkg.dsc", + "IgnoreInf": [] + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + "SpellCheck": { + "ExtendWords": [ + "FMPSTATE", + ] + }, + "Defines": { + "BLD_*_CONTINUOUS_INTEGRATION": "TRUE", + } +} diff --git a/FmpDevicePkg/FmpDevicePkg.dsc b/FmpDevicePkg/FmpDevicePkg.dsc index 67b5aa7a327..f4093d3837c 100644 --- a/FmpDevicePkg/FmpDevicePkg.dsc +++ b/FmpDevicePkg/FmpDevicePkg.dsc @@ -48,9 +48,13 @@ DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf - OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf +!endif FmpAuthenticationLib|SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf CapsuleUpdatePolicyLib|FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf FmpPayloadHeaderLib|FmpDevicePkg/Library/FmpPayloadHeaderLibV1/FmpPayloadHeaderLibV1.inf diff --git a/IntelFsp2Pkg/Tools/SplitFspBin.py b/IntelFsp2Pkg/Tools/SplitFspBin.py index b326241fa9d..39a7ea7460b 100644 --- a/IntelFsp2Pkg/Tools/SplitFspBin.py +++ b/IntelFsp2Pkg/Tools/SplitFspBin.py @@ -428,7 +428,7 @@ def ParseFfs(self): ffssize = len(self.FfsData) offset = sizeof(self.FfsHdr) if self.FfsHdr.Name != '\xff' * 16: - while offset < ffssize: + while offset < (ffssize - sizeof (EFI_COMMON_SECTION_HEADER)): sechdr = EFI_COMMON_SECTION_HEADER.from_buffer (self.FfsData, offset) sec = Section (offset, self.FfsData[offset:offset + int(sechdr.Size)]) self.SecList.append(sec) @@ -453,7 +453,7 @@ def ParseFv(self): else: offset = self.FvHdr.HeaderLength offset = AlignPtr(offset) - while offset < fvsize: + while offset < (fvsize - sizeof (EFI_FFS_FILE_HEADER)): ffshdr = EFI_FFS_FILE_HEADER.from_buffer (self.FvData, offset) if (ffshdr.Name == '\xff' * 16) and (int(ffshdr.Size) == 0xFFFFFF): offset = fvsize @@ -515,7 +515,7 @@ def ParseFd(self): offset = 0 fdsize = len(self.FdData) self.FvList = [] - while offset < fdsize: + while offset < (fdsize - sizeof (EFI_FIRMWARE_VOLUME_HEADER)): fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset) if b'_FVH' != fvh.Signature: raise Exception("ERROR: Invalid FV header !") @@ -838,7 +838,7 @@ def RebaseFspBin (FspBinary, FspComponent, FspBase, OutputDir, OutputFile): def main (): parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(title='commands') + subparsers = parser.add_subparsers(title='commands', dest="which") parser_rebase = subparsers.add_parser('rebase', help='rebase a FSP into a new base address') parser_rebase.set_defaults(which='rebase') @@ -880,7 +880,7 @@ def main (): elif args.which == 'info': ShowFspInfo (args.FspBinary) else: - pass + parser.print_help() return 0 diff --git a/IntelFsp2WrapperPkg/FspsWrapperPeim/FspsWrapperPeim.c b/IntelFsp2WrapperPkg/FspsWrapperPeim/FspsWrapperPeim.c index 0f8cd69a0e6..b20f0805a02 100644 --- a/IntelFsp2WrapperPkg/FspsWrapperPeim/FspsWrapperPeim.c +++ b/IntelFsp2WrapperPkg/FspsWrapperPeim/FspsWrapperPeim.c @@ -352,7 +352,7 @@ FspsWrapperInitApiMode ( EFI_BOOT_MODE BootMode; // - // Register MemoryDiscovered Nofity to run FspSiliconInit + // Register MemoryDiscovered Notify to run FspSiliconInit // Status = PeiServicesNotifyPpi (&mPeiMemoryDiscoveredNotifyDesc); ASSERT_EFI_ERROR (Status); diff --git a/IntelFsp2WrapperPkg/Include/Library/FspWrapperApiLib.h b/IntelFsp2WrapperPkg/Include/Library/FspWrapperApiLib.h index e39054c30d3..11a3faaad87 100644 --- a/IntelFsp2WrapperPkg/Include/Library/FspWrapperApiLib.h +++ b/IntelFsp2WrapperPkg/Include/Library/FspWrapperApiLib.h @@ -40,7 +40,7 @@ CallFspNotifyPhase ( /** Call FSP API - FspMemoryInit. - @param[in] FspmUpdDataPtr Pointer to the FSPM_UPD data sructure. + @param[in] FspmUpdDataPtr Pointer to the FSPM_UPD data structure. @param[out] HobListPtr Pointer to receive the address of the HOB list. @return EFI status returned by FspMemoryInit API. diff --git a/IntelFsp2WrapperPkg/Include/Library/FspWrapperPlatformLib.h b/IntelFsp2WrapperPkg/Include/Library/FspWrapperPlatformLib.h index b90f0eb7830..2aa14c92fd6 100644 --- a/IntelFsp2WrapperPkg/Include/Library/FspWrapperPlatformLib.h +++ b/IntelFsp2WrapperPkg/Include/Library/FspWrapperPlatformLib.h @@ -12,7 +12,7 @@ /** This function overrides the default configurations in the FSP-M UPD data region. - @param[in,out] FspUpdRgnPtr A pointer to the UPD data region data strcture. + @param[in,out] FspUpdRgnPtr A pointer to the UPD data region data structure. **/ VOID @@ -24,7 +24,7 @@ UpdateFspmUpdData ( /** This function overrides the default configurations in the FSP-S UPD data region. - @param[in,out] FspUpdRgnPtr A pointer to the UPD data region data strcture. + @param[in,out] FspUpdRgnPtr A pointer to the UPD data region data structure. **/ VOID diff --git a/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.nasm b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.nasm index 45c8f21255e..db8e62ebc5a 100644 --- a/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.nasm +++ b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.nasm @@ -43,7 +43,7 @@ ASM_PFX(AsmExecute32BitCode): cli ; - ; save orignal GDTR and CS + ; save original GDTR and CS ; mov rax, ds push rax @@ -190,7 +190,7 @@ ReloadCS: pop rdi popfq ; - ; Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor. + ; Switch to original GDT and CS. here rsp is pointer to the original GDT descriptor. ; lgdt [rsp] ; @@ -198,7 +198,7 @@ ReloadCS: ; add rsp, 0x10 ; - ; switch to orignal CS and GDTR + ; switch to original CS and GDTR ; pop r9 ; get CS shl r9, 32 ; rcx[32..47] <- Cs diff --git a/IntelFsp2WrapperPkg/Library/BaseFspWrapperPlatformLibSample/FspWrapperPlatformLibSample.c b/IntelFsp2WrapperPkg/Library/BaseFspWrapperPlatformLibSample/FspWrapperPlatformLibSample.c index def04b17665..dddf80b76c2 100644 --- a/IntelFsp2WrapperPkg/Library/BaseFspWrapperPlatformLibSample/FspWrapperPlatformLibSample.c +++ b/IntelFsp2WrapperPkg/Library/BaseFspWrapperPlatformLibSample/FspWrapperPlatformLibSample.c @@ -14,7 +14,7 @@ @note At this point, memory is NOT ready, PeiServices are available to use. - @param[in,out] FspUpdRgnPtr A pointer to the UPD data region data strcture. + @param[in,out] FspUpdRgnPtr A pointer to the UPD data region data structure. **/ VOID @@ -28,7 +28,7 @@ UpdateFspmUpdData ( /** This function overrides the default configurations in the FSP-S UPD data region. - @param[in,out] FspUpdRgnPtr A pointer to the UPD data region data strcture. + @param[in,out] FspUpdRgnPtr A pointer to the UPD data region data structure. **/ VOID diff --git a/IntelFsp2WrapperPkg/Library/PeiFspWrapperHobProcessLibSample/FspWrapperHobProcessLibSample.c b/IntelFsp2WrapperPkg/Library/PeiFspWrapperHobProcessLibSample/FspWrapperHobProcessLibSample.c index 54cebe127c8..48f4b0295a3 100644 --- a/IntelFsp2WrapperPkg/Library/PeiFspWrapperHobProcessLibSample/FspWrapperHobProcessLibSample.c +++ b/IntelFsp2WrapperPkg/Library/PeiFspWrapperHobProcessLibSample/FspWrapperHobProcessLibSample.c @@ -29,11 +29,11 @@ #define PEI_ADDITIONAL_MEMORY_SIZE (16 * EFI_PAGE_SIZE) /** - Get the mem size in memory type infromation table. + Get the mem size in memory type information table. @param[in] PeiServices PEI Services table. - @return the mem size in memory type infromation table. + @return the mem size in memory type information table. **/ UINT64 GetMemorySizeInMemoryTypeInformation ( diff --git a/IntelFsp2WrapperPkg/Library/SecFspWrapperPlatformSecLibSample/Ia32/SecEntry.nasm b/IntelFsp2WrapperPkg/Library/SecFspWrapperPlatformSecLibSample/Ia32/SecEntry.nasm index d8d0582cb4f..9f190bb25b0 100644 --- a/IntelFsp2WrapperPkg/Library/SecFspWrapperPlatformSecLibSample/Ia32/SecEntry.nasm +++ b/IntelFsp2WrapperPkg/Library/SecFspWrapperPlatformSecLibSample/Ia32/SecEntry.nasm @@ -207,7 +207,7 @@ TempRamInitDone: cmp eax, 8000000Eh ;Check if EFI_NOT_FOUND returned. Error code for Microcode Update not found. je CallSecFspInit ;If microcode not found, don't hang, but continue. - cmp eax, 0 ;Check if EFI_SUCCESS retuned. + cmp eax, 0 ;Check if EFI_SUCCESS returned. jnz FspApiFailed ; ECX: start of range diff --git a/IntelFsp2WrapperPkg/Library/SecFspWrapperPlatformSecLibSample/Ia32/Stack.nasm b/IntelFsp2WrapperPkg/Library/SecFspWrapperPlatformSecLibSample/Ia32/Stack.nasm index ba989bd4412..d7394cf286c 100644 --- a/IntelFsp2WrapperPkg/Library/SecFspWrapperPlatformSecLibSample/Ia32/Stack.nasm +++ b/IntelFsp2WrapperPkg/Library/SecFspWrapperPlatformSecLibSample/Ia32/Stack.nasm @@ -5,7 +5,7 @@ ; ; Abstract: ; -; Switch the stack from temporary memory to permenent memory. +; Switch the stack from temporary memory to permanent memory. ; ;------------------------------------------------------------------------------ diff --git a/Maintainers.txt b/Maintainers.txt index 6b89bec55e2..146d8aca93f 100644 --- a/Maintainers.txt +++ b/Maintainers.txt @@ -98,6 +98,29 @@ F: */Arm/ M: Leif Lindholm M: Ard Biesheuvel +EDK II Continuous Integration: +------------------------------ +.azurepipelines/ +F: .azurepipelines/ +M: Sean Brogan +M: Bret Barkelew +R: Michael D Kinney +R: Liming Gao + +.mergify/ +F: .mergify/ +M: Michael D Kinney +M: Liming Gao +R: Sean Brogan +R: Bret Barkelew + +.pytool/ +F: .pytool/ +M: Sean Brogan +M: Bret Barkelew +R: Michael D Kinney +R: Liming Gao + EDK II Packages: ---------------- ArmPkg @@ -127,7 +150,7 @@ F: ArmVirtPkg/PrePi/ F: ArmVirtPkg/XenAcpiPlatformDxe/ F: ArmVirtPkg/XenPlatformHasAcpiDtDxe/ F: ArmVirtPkg/XenioFdtDxe/ -R: Julien Grall +R: Julien Grall BaseTools F: BaseTools/ @@ -354,8 +377,9 @@ M: Liming Gao NetworkPkg F: NetworkPkg/ W: https://github.com/tianocore/tianocore.github.io/wiki/NetworkPkg -M: Siyuan Fu M: Jiaxin Wu +M: Maciej Rabeda +R: Siyuan Fu OvmfPkg F: OvmfPkg/ @@ -396,7 +420,7 @@ F: OvmfPkg/XenPvBlkDxe/ F: OvmfPkg/XenResetVector/ F: OvmfPkg/XenTimerDxe/ R: Anthony Perard -R: Julien Grall +R: Julien Grall OvmfPkg: TCG- and TPM2-related modules F: OvmfPkg/Include/IndustryStandard/QemuTpm.h @@ -457,6 +481,7 @@ S: Maintained StandaloneMmPkg F: StandaloneMmPkg/ -M: Achin Gupta +M: Ard Biesheuvel +M: Sami Mujawar M: Jiewen Yao R: Supreeth Venkatesh diff --git a/MdeModulePkg/Application/VariableInfo/VariableInfo.c b/MdeModulePkg/Application/VariableInfo/VariableInfo.c index f213471e9ab..c04ba182132 100644 --- a/MdeModulePkg/Application/VariableInfo/VariableInfo.c +++ b/MdeModulePkg/Application/VariableInfo/VariableInfo.c @@ -3,7 +3,7 @@ this utility will print out the statistics information. You can use console redirection to capture the data. - Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -126,7 +126,7 @@ PrintInfoFromSmm ( ASSERT (CommBuffer != NULL); ZeroMem (CommBuffer, RealCommSize); - Print (L"Non-Volatile SMM Variables:\n"); + Print (L"SMM Driver Non-Volatile Variables:\n"); do { CommSize = RealCommSize; Status = GetVariableStatisticsData (CommBuffer, &CommSize); @@ -155,7 +155,7 @@ PrintInfoFromSmm ( } } while (TRUE); - Print (L"Volatile SMM Variables:\n"); + Print (L"SMM Driver Volatile Variables:\n"); ZeroMem (CommBuffer, RealCommSize); do { CommSize = RealCommSize; @@ -207,24 +207,18 @@ UefiMain ( IN EFI_SYSTEM_TABLE *SystemTable ) { - EFI_STATUS Status; + EFI_STATUS RuntimeDxeStatus; + EFI_STATUS SmmStatus; VARIABLE_INFO_ENTRY *VariableInfo; VARIABLE_INFO_ENTRY *Entry; - Status = EfiGetSystemConfigurationTable (&gEfiVariableGuid, (VOID **)&Entry); - if (EFI_ERROR (Status) || (Entry == NULL)) { - Status = EfiGetSystemConfigurationTable (&gEfiAuthenticatedVariableGuid, (VOID **)&Entry); + RuntimeDxeStatus = EfiGetSystemConfigurationTable (&gEfiVariableGuid, (VOID **) &Entry); + if (EFI_ERROR (RuntimeDxeStatus) || (Entry == NULL)) { + RuntimeDxeStatus = EfiGetSystemConfigurationTable (&gEfiAuthenticatedVariableGuid, (VOID **) &Entry); } - if (EFI_ERROR (Status) || (Entry == NULL)) { - Status = PrintInfoFromSmm (); - if (!EFI_ERROR (Status)) { - return Status; - } - } - - if (!EFI_ERROR (Status) && (Entry != NULL)) { - Print (L"Non-Volatile EFI Variables:\n"); + if (!EFI_ERROR (RuntimeDxeStatus) && (Entry != NULL)) { + Print (L"Runtime DXE Driver Non-Volatile EFI Variables:\n"); VariableInfo = Entry; do { if (!VariableInfo->Volatile) { @@ -242,7 +236,7 @@ UefiMain ( VariableInfo = VariableInfo->Next; } while (VariableInfo != NULL); - Print (L"Volatile EFI Variables:\n"); + Print (L"Runtime DXE Driver Volatile EFI Variables:\n"); VariableInfo = Entry; do { if (VariableInfo->Volatile) { @@ -258,14 +252,19 @@ UefiMain ( } VariableInfo = VariableInfo->Next; } while (VariableInfo != NULL); + } + + SmmStatus = PrintInfoFromSmm (); - } else { + if (EFI_ERROR (RuntimeDxeStatus) && EFI_ERROR (SmmStatus)) { Print (L"Warning: Variable Dxe/Smm driver doesn't enable the feature of statistical information!\n"); Print (L"If you want to see this info, please:\n"); Print (L" 1. Set PcdVariableCollectStatistics as TRUE\n"); Print (L" 2. Rebuild Variable Dxe/Smm driver\n"); Print (L" 3. Run \"VariableInfo\" cmd again\n"); + + return EFI_NOT_FOUND; } - return Status; + return EFI_SUCCESS; } diff --git a/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c b/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c index 7c6a6a5f971..995ccd2463d 100644 --- a/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c +++ b/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c @@ -534,6 +534,8 @@ EhcCreateUrb ( PEI_URB *Urb; VOID *Map; + Map = NULL; + Urb = Ehc->Urb; Urb->Signature = EHC_URB_SIG; InitializeListHead (&Urb->UrbList); diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c index 3bde96bc957..62886d5c91f 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c @@ -672,7 +672,7 @@ ProcessAsyncTaskList ( } Private->CqHdbl[QueueId].Cqh++; - if (Private->CqHdbl[QueueId].Cqh > NVME_ASYNC_CCQ_SIZE) { + if (Private->CqHdbl[QueueId].Cqh > MIN (NVME_ASYNC_CCQ_SIZE, Private->Cap.Mqes)) { Private->CqHdbl[QueueId].Cqh = 0; Private->Pt[QueueId] ^= 1; } diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c index 8e721379466..e9357b1239c 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c @@ -452,6 +452,7 @@ NvmExpressPassThru ( NVME_SQ *Sq; NVME_CQ *Cq; UINT16 QueueId; + UINT16 QueueSize; UINT32 Bytes; UINT16 Offset; EFI_EVENT TimerEvent; @@ -540,6 +541,7 @@ NvmExpressPassThru ( Prp = NULL; TimerEvent = NULL; Status = EFI_SUCCESS; + QueueSize = MIN (NVME_ASYNC_CSQ_SIZE, Private->Cap.Mqes) + 1; if (Packet->QueueType == NVME_ADMIN_QUEUE) { QueueId = 0; @@ -552,7 +554,7 @@ NvmExpressPassThru ( // // Submission queue full check. // - if ((Private->SqTdbl[QueueId].Sqt + 1) % (NVME_ASYNC_CSQ_SIZE + 1) == + if ((Private->SqTdbl[QueueId].Sqt + 1) % QueueSize == Private->AsyncSqHead) { return EFI_NOT_READY; } @@ -701,7 +703,7 @@ NvmExpressPassThru ( // if ((Event != NULL) && (QueueId != 0)) { Private->SqTdbl[QueueId].Sqt = - (Private->SqTdbl[QueueId].Sqt + 1) % (NVME_ASYNC_CSQ_SIZE + 1); + (Private->SqTdbl[QueueId].Sqt + 1) % QueueSize; } else { Private->SqTdbl[QueueId].Sqt ^= 1; } diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c index 987eed420e2..a8cb7f3a675 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c +++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c @@ -376,6 +376,29 @@ NvmExpressPeimEntry ( continue; } + // + // Nvm Express Pass Thru PPI + // + Private->PassThruMode.Attributes = EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL | + EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL | + EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM; + Private->PassThruMode.IoAlign = sizeof (UINTN); + Private->PassThruMode.NvmeVersion = EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION; + Private->NvmePassThruPpi.Mode = &Private->PassThruMode; + Private->NvmePassThruPpi.GetDevicePath = NvmePassThruGetDevicePath; + Private->NvmePassThruPpi.GetNextNameSpace = NvmePassThruGetNextNameSpace; + Private->NvmePassThruPpi.PassThru = NvmePassThru; + CopyMem ( + &Private->NvmePassThruPpiList, + &mNvmePassThruPpiListTemplate, + sizeof (EFI_PEI_PPI_DESCRIPTOR) + ); + Private->NvmePassThruPpiList.Ppi = &Private->NvmePassThruPpi; + PeiServicesInstallPpi (&Private->NvmePassThruPpiList); + + // + // Block Io PPI + // Private->BlkIoPpi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo; Private->BlkIoPpi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo; Private->BlkIoPpi.ReadBlocks = NvmeBlockIoPeimReadBlocks; @@ -398,26 +421,6 @@ NvmExpressPeimEntry ( Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi; PeiServicesInstallPpi (&Private->BlkIoPpiList); - // - // Nvm Express Pass Thru PPI - // - Private->PassThruMode.Attributes = EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL | - EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL | - EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM; - Private->PassThruMode.IoAlign = sizeof (UINTN); - Private->PassThruMode.NvmeVersion = EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION; - Private->NvmePassThruPpi.Mode = &Private->PassThruMode; - Private->NvmePassThruPpi.GetDevicePath = NvmePassThruGetDevicePath; - Private->NvmePassThruPpi.GetNextNameSpace = NvmePassThruGetNextNameSpace; - Private->NvmePassThruPpi.PassThru = NvmePassThru; - CopyMem ( - &Private->NvmePassThruPpiList, - &mNvmePassThruPpiListTemplate, - sizeof (EFI_PEI_PPI_DESCRIPTOR) - ); - Private->NvmePassThruPpiList.Ppi = &Private->NvmePassThruPpi; - PeiServicesInstallPpi (&Private->NvmePassThruPpiList); - // // Check if the NVME controller supports the Security Receive/Send commands // diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c index b020ce50ce3..64284ac8251 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c @@ -8,7 +8,7 @@ PCI Root Bridges. So it means platform needs install PCI Root Bridge IO protocol for each PCI Root Bus and install PCI Host Bridge Resource Allocation Protocol. -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -37,7 +37,7 @@ UINT64 gAllZero = 0; EFI_PCI_PLATFORM_PROTOCOL *gPciPlatformProtocol; EFI_PCI_OVERRIDE_PROTOCOL *gPciOverrideProtocol; EDKII_IOMMU_PROTOCOL *mIoMmuProtocol; - +EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol; GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL mPciHotPlugRequest = { PciHotPlugRequestNotify @@ -293,6 +293,14 @@ PciBusDriverBindingStart ( ); } + if (mDeviceSecurityProtocol == NULL) { + gBS->LocateProtocol ( + &gEdkiiDeviceSecurityProtocolGuid, + NULL, + (VOID **) &mDeviceSecurityProtocol + ); + } + if (PcdGetBool (PcdPciDisableBusEnumeration)) { gFullEnumeration = FALSE; } else { diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h index 504a1b1c129..d4113993c8a 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h @@ -27,6 +27,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #include diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf index 05c22025b86..9284998f361 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf @@ -2,7 +2,7 @@ # The PCI bus driver will probe all PCI devices and allocate MMIO and IO space for these devices. # Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable hot plug supporting. # -# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -90,6 +90,8 @@ gEfiIncompatiblePciDeviceSupportProtocolGuid ## SOMETIMES_CONSUMES gEfiLoadFile2ProtocolGuid ## SOMETIMES_PRODUCES gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES + gEdkiiDeviceSecurityProtocolGuid ## SOMETIMES_CONSUMES + gEdkiiDeviceIdentifierTypePciGuid ## SOMETIMES_CONSUMES gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES [FeaturePcd] diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c index c7eafff5935..f8020f4e721 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c @@ -10,6 +10,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include "PciBus.h" extern CHAR16 *mBarTypeStr[]; +extern EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol; #define OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL #define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL @@ -2070,6 +2071,67 @@ InitializeP2C ( PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero); } +/* + Authenticate the PCI device by using DeviceSecurityProtocol. + + @param PciIoDevice PCI device. + + @retval EFI_SUCCESS The device passes the authentication. + @return not EFI_SUCCESS The device failes the authentication or + unexpected error happen during authentication. +*/ +EFI_STATUS +AuthenticatePciDevice ( + IN PCI_IO_DEVICE *PciIoDevice + ) +{ + EDKII_DEVICE_IDENTIFIER DeviceIdentifier; + EFI_STATUS Status; + + if (mDeviceSecurityProtocol != NULL) { + // + // Prepare the parameter + // + DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION; + CopyGuid (&DeviceIdentifier.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid); + DeviceIdentifier.DeviceHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &DeviceIdentifier.DeviceHandle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEdkiiDeviceIdentifierTypePciGuid, + &PciIoDevice->PciIo, + NULL + ); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Do DeviceAuthentication + // + Status = mDeviceSecurityProtocol->DeviceAuthenticate (mDeviceSecurityProtocol, &DeviceIdentifier); + // + // Always uninstall, because they are only for Authentication. + // No need to check return Status. + // + gBS->UninstallMultipleProtocolInterfaces ( + DeviceIdentifier.DeviceHandle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEdkiiDeviceIdentifierTypePciGuid, + &PciIoDevice->PciIo, + NULL + ); + return Status; + } + + // + // Device Security Protocol is not found, just return success + // + return EFI_SUCCESS; +} + /** Create and initialize general PCI I/O device instance for PCI device/bridge device/hotplug bridge device. @@ -2156,6 +2218,21 @@ CreatePciIoDevice ( PciIoDevice->IsPciExp = TRUE; } + // + // Now we can do the authentication check for the device. + // + Status = AuthenticatePciDevice (PciIoDevice); + // + // If authentication fails, skip this device. + // + if (EFI_ERROR(Status)) { + if (PciIoDevice->DevicePath != NULL) { + FreePool (PciIoDevice->DevicePath); + } + FreePool (PciIoDevice); + return NULL; + } + if (PcdGetBool (PcdAriSupport)) { // // Check if the device is an ARI device. diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c index 5b55fb5d3be..72690ab6476 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c @@ -1054,7 +1054,9 @@ PciScanBus ( &PciDevice ); - ASSERT (!EFI_ERROR (Status)); + if (EFI_ERROR (Status)) { + continue; + } PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0); diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c index 082904ccc5d..776c0e796c5 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c @@ -727,7 +727,7 @@ EmmcSwitchBusTiming ( // // Convert the clock freq unit from MHz to KHz. // - Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]); + Status = SdMmcHcClockSupply (Private, Slot, BusTiming, FALSE, ClockFreq * 1000); if (EFI_ERROR (Status)) { return Status; } @@ -745,24 +745,6 @@ EmmcSwitchBusTiming ( return EFI_DEVICE_ERROR; } - if (mOverride != NULL && mOverride->NotifyPhase != NULL) { - Status = mOverride->NotifyPhase ( - Private->ControllerHandle, - Slot, - EdkiiSdMmcSwitchClockFreqPost, - &BusTiming - ); - if (EFI_ERROR (Status)) { - DEBUG (( - DEBUG_ERROR, - "%a: SD/MMC switch clock freq post notifier callback failed - %r\n", - __FUNCTION__, - Status - )); - return Status; - } - } - return Status; } diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c index 336baade9e5..b630daab763 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c @@ -1145,29 +1145,11 @@ SdCardSetBusMode ( return Status; } - Status = SdMmcHcClockSupply (PciIo, Slot, BusMode.ClockFreq * 1000, Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]); + Status = SdMmcHcClockSupply (Private, Slot, BusMode.BusTiming, FALSE, BusMode.ClockFreq * 1000); if (EFI_ERROR (Status)) { return Status; } - if (mOverride != NULL && mOverride->NotifyPhase != NULL) { - Status = mOverride->NotifyPhase ( - Private->ControllerHandle, - Slot, - EdkiiSdMmcSwitchClockFreqPost, - &BusMode.BusTiming - ); - if (EFI_ERROR (Status)) { - DEBUG (( - DEBUG_ERROR, - "%a: SD/MMC switch clock freq post notifier callback failed - %r\n", - __FUNCTION__, - Status - )); - return Status; - } - } - if ((BusMode.BusTiming == SdMmcUhsSdr104) || ((BusMode.BusTiming == SdMmcUhsSdr50) && (Capability->TuningSDR50 != 0))) { Status = SdCardTuningClock (PciIo, PassThru, Slot); if (EFI_ERROR (Status)) { @@ -1345,7 +1327,10 @@ SdCardIdentification ( goto Error; } - SdMmcHcInitClockFreq (PciIo, Slot, Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]); + Status = SdMmcHcStartSdClock (PciIo, Slot); + if (EFI_ERROR (Status)) { + goto Error; + } gBS->Stall (1000); diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h index c29e48767ec..03049601324 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h @@ -796,6 +796,30 @@ SdCardIdentification ( IN UINT8 Slot ); +/** + SD/MMC card clock supply. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] BusTiming BusTiming at which the frequency change is done. + @param[in] FirstTimeSetup Flag to indicate whether the clock is being setup for the first time. + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +SdMmcHcClockSupply ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN SD_MMC_BUS_MODE BusTiming, + IN BOOLEAN FirstTimeSetup, + IN UINT64 ClockFreq + ); + /** Software reset the specified SD/MMC host controller. diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c index b9d04e0f17a..d1e60938f96 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c @@ -758,16 +758,40 @@ SdMmcHcStopClock ( return Status; } +/** + Start the SD clock. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number. + + @retval EFI_SUCCESS Succeeded to start the SD clock. + @retval Others Failed to start the SD clock. +**/ +EFI_STATUS +SdMmcHcStartSdClock ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ) +{ + UINT16 ClockCtrl; + + // + // Set SD Clock Enable in the Clock Control register to 1 + // + ClockCtrl = BIT2; + return SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); +} + /** SD/MMC card clock supply. Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details. - @param[in] PciIo The PCI IO protocol instance. - @param[in] Slot The slot number of the SD card to send the command to. - @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. - @param[in] BaseClkFreq The base clock frequency of host controller in MHz. - @param[in] ControllerVer The version of host controller. + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] BusTiming BusTiming at which the frequency change is done. + @param[in] FirstTimeSetup Flag to indicate whether the clock is being setup for the first time. + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. @retval EFI_SUCCESS The clock is supplied successfully. @retval Others The clock isn't supplied successfully. @@ -775,11 +799,11 @@ SdMmcHcStopClock ( **/ EFI_STATUS SdMmcHcClockSupply ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN UINT8 Slot, - IN UINT64 ClockFreq, - IN UINT32 BaseClkFreq, - IN UINT16 ControllerVer + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN SD_MMC_BUS_MODE BusTiming, + IN BOOLEAN FirstTimeSetup, + IN UINT64 ClockFreq ) { EFI_STATUS Status; @@ -787,13 +811,15 @@ SdMmcHcClockSupply ( UINT32 Divisor; UINT32 Remainder; UINT16 ClockCtrl; + UINT32 BaseClkFreq; + UINT16 ControllerVer; + EFI_PCI_IO_PROTOCOL *PciIo; - // - // Calculate a divisor for SD clock frequency - // - ASSERT (BaseClkFreq != 0); + PciIo = Private->PciIo; + BaseClkFreq = Private->BaseClkFreq[Slot]; + ControllerVer = Private->ControllerVersion[Slot]; - if (ClockFreq == 0) { + if (BaseClkFreq == 0 || ClockFreq == 0) { return EFI_INVALID_PARAMETER; } @@ -877,11 +903,33 @@ SdMmcHcClockSupply ( return Status; } + Status = SdMmcHcStartSdClock (PciIo, Slot); + if (EFI_ERROR (Status)) { + return Status; + } + // - // Set SD Clock Enable in the Clock Control register to 1 + // We don't notify the platform on first time setup to avoid changing + // legacy behavior. During first time setup we also don't know what type + // of the card slot it is and which enum value of BusTiming applies. // - ClockCtrl = BIT2; - Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); + if (!FirstTimeSetup && mOverride != NULL && mOverride->NotifyPhase != NULL) { + Status = mOverride->NotifyPhase ( + Private->ControllerHandle, + Slot, + EdkiiSdMmcSwitchClockFreqPost, + &BusTiming + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: SD/MMC switch clock freq post notifier callback failed - %r\n", + __FUNCTION__, + Status + )); + return Status; + } + } return Status; } @@ -1038,49 +1086,6 @@ SdMmcHcInitV4Enhancements ( return EFI_SUCCESS; } -/** - Supply SD/MMC card with lowest clock frequency at initialization. - - @param[in] PciIo The PCI IO protocol instance. - @param[in] Slot The slot number of the SD card to send the command to. - @param[in] BaseClkFreq The base clock frequency of host controller in MHz. - @param[in] ControllerVer The version of host controller. - - @retval EFI_SUCCESS The clock is supplied successfully. - @retval Others The clock isn't supplied successfully. - -**/ -EFI_STATUS -SdMmcHcInitClockFreq ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN UINT8 Slot, - IN UINT32 BaseClkFreq, - IN UINT16 ControllerVer - ) -{ - EFI_STATUS Status; - UINT32 InitFreq; - - // - // According to SDHCI specification ver. 4.2, BaseClkFreq field value of - // the Capability Register 1 can be zero, which means a need for obtaining - // the clock frequency via another method. Fail in case it is not updated - // by SW at this point. - // - if (BaseClkFreq == 0) { - // - // Don't support get Base Clock Frequency information via another method - // - return EFI_UNSUPPORTED; - } - // - // Supply 400KHz clock frequency at initialization phase. - // - InitFreq = 400; - Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, BaseClkFreq, ControllerVer); - return Status; -} - /** Supply SD/MMC card with maximum voltage at initialization. @@ -1216,7 +1221,14 @@ SdMmcHcInitHost ( return Status; } - Status = SdMmcHcInitClockFreq (PciIo, Slot, Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]); + // + // Perform first time clock setup with 400 KHz frequency. + // We send the 0 as the BusTiming value because at this time + // we still do not know the slot type and which enum value will apply. + // Since it is a first time setup SdMmcHcClockSupply won't notify + // the platofrm driver anyway so it doesn't matter. + // + Status = SdMmcHcClockSupply (Private, Slot, 0, TRUE, 400); if (EFI_ERROR (Status)) { return Status; } diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h index 088c70451cd..16229a846cc 100644 --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h @@ -479,27 +479,18 @@ SdMmcHcStopClock ( ); /** - SD/MMC card clock supply. + Start the SD clock. - Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details. - - @param[in] PciIo The PCI IO protocol instance. - @param[in] Slot The slot number of the SD card to send the command to. - @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. - @param[in] BaseClkFreq The base clock frequency of host controller in MHz. - @param[in] ControllerVer The version of host controller. - - @retval EFI_SUCCESS The clock is supplied successfully. - @retval Others The clock isn't supplied successfully. + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number. + @retval EFI_SUCCESS Succeeded to start the SD clock. + @retval Others Failed to start the SD clock. **/ EFI_STATUS -SdMmcHcClockSupply ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN UINT8 Slot, - IN UINT64 ClockFreq, - IN UINT32 BaseClkFreq, - IN UINT16 ControllerVer +SdMmcHcStartSdClock ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot ); /** @@ -542,26 +533,6 @@ SdMmcHcSetBusWidth ( IN UINT16 BusWidth ); -/** - Supply SD/MMC card with lowest clock frequency at initialization. - - @param[in] PciIo The PCI IO protocol instance. - @param[in] Slot The slot number of the SD card to send the command to. - @param[in] BaseClkFreq The base clock frequency of host controller in MHz. - @param[in] ControllerVer The version of host controller. - - @retval EFI_SUCCESS The clock is supplied successfully. - @retval Others The clock isn't supplied successfully. - -**/ -EFI_STATUS -SdMmcHcInitClockFreq ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN UINT8 Slot, - IN UINT32 BaseClkFreq, - IN UINT16 ControllerVer - ); - /** Supply SD/MMC card with maximum voltage at initialization. diff --git a/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c b/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c index b897c3f82ce..a05834da3c4 100644 --- a/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c +++ b/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c @@ -274,6 +274,8 @@ UhcControlTransfer ( PktID = INPUT_PACKET_ID; + RequestMap = NULL; + if (Request == NULL || TransferResult == NULL) { return EFI_INVALID_PARAMETER; } diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c index 8fa58d65b22..1d53fcd23e9 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c @@ -174,7 +174,7 @@ SdBlockIoPeimGetMediaInfo ( Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); - if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) { + if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices) || (DeviceIndex > SD_PEIM_MAX_SLOTS)) { return EFI_INVALID_PARAMETER; } @@ -252,7 +252,7 @@ SdBlockIoPeimReadBlocks ( return EFI_SUCCESS; } - if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) { + if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices) || (DeviceIndex > SD_PEIM_MAX_SLOTS)) { return EFI_INVALID_PARAMETER; } diff --git a/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c b/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c index 27685995c23..ccb389067a6 100644 --- a/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c +++ b/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c @@ -215,7 +215,7 @@ USBKeyboardDriverBindingStart ( EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints; // - // Traverse endpoints to find interrupt endpoint + // Traverse endpoints to find interrupt endpoint IN // Found = FALSE; for (Index = 0; Index < EndpointNumber; Index++) { @@ -226,7 +226,8 @@ USBKeyboardDriverBindingStart ( &EndpointDescriptor ); - if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) { + if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) && + ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) { // // We only care interrupt endpoint here // diff --git a/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c b/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c index 8953e7031cf..9cd0e4cd535 100644 --- a/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c +++ b/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c @@ -203,7 +203,7 @@ USBMouseAbsolutePointerDriverBindingStart ( EndpointNumber = UsbMouseAbsolutePointerDevice->InterfaceDescriptor.NumEndpoints; // - // Traverse endpoints to find interrupt endpoint + // Traverse endpoints to find interrupt endpoint IN // Found = FALSE; for (Index = 0; Index < EndpointNumber; Index++) { @@ -213,7 +213,8 @@ USBMouseAbsolutePointerDriverBindingStart ( &EndpointDescriptor ); - if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) { + if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) && + ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) { // // We only care interrupt endpoint here // diff --git a/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c b/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c index 677815a8ade..143ff15eb03 100644 --- a/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c +++ b/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c @@ -203,7 +203,7 @@ USBMouseDriverBindingStart ( EndpointNumber = UsbMouseDevice->InterfaceDescriptor.NumEndpoints; // - // Traverse endpoints to find interrupt endpoint + // Traverse endpoints to find interrupt endpoint IN // Found = FALSE; for (Index = 0; Index < EndpointNumber; Index++) { @@ -213,7 +213,8 @@ USBMouseDriverBindingStart ( &EndpointDescriptor ); - if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) { + if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) && + ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) { // // We only care interrupt endpoint here // diff --git a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c index 9477b94044b..b4cb48843fb 100644 --- a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c +++ b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c @@ -225,6 +225,8 @@ FindGuardedMemoryMap ( UINTN BitsToUnitEnd; EFI_STATUS Status; + MapMemory = 0; + // // Adjust current map table depth according to the address to access // diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c index 7a24bd07815..47edf86dfbf 100644 --- a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c +++ b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c @@ -1094,6 +1094,11 @@ DisableNullDetectionAtTheEndOfDxe ( ); ASSERT_EFI_ERROR (Status); + // + // Page 0 might have be allocated to avoid misuses. Free it here anyway. + // + CoreFreePages (0, 1); + CoreCloseEvent (Event); DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n")); diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c index 172d7cd1c60..6e8ca824d46 100644 --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c @@ -246,8 +246,12 @@ HandOffToDxeCore ( EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi; BOOLEAN BuildPageTablesIa32Pae; + // + // Clear page 0 and mark it as allocated if NULL pointer detection is enabled. + // if (IsNullDetectionEnabled ()) { ClearFirst4KPage (HobList.Raw); + BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData); } Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack); diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c index 2867610bff4..f465eb1d8ac 100644 --- a/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c +++ b/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c @@ -36,8 +36,12 @@ HandOffToDxeCore ( EFI_VECTOR_HANDOFF_INFO *VectorInfo; EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi; + // + // Clear page 0 and mark it as allocated if NULL pointer detection is enabled. + // if (IsNullDetectionEnabled ()) { ClearFirst4KPage (HobList.Raw); + BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData); } // diff --git a/MdeModulePkg/Core/Pei/Dependency/Dependency.c b/MdeModulePkg/Core/Pei/Dependency/Dependency.c index 6ce610a0283..b53e5f2686e 100644 --- a/MdeModulePkg/Core/Pei/Dependency/Dependency.c +++ b/MdeModulePkg/Core/Pei/Dependency/Dependency.c @@ -2,10 +2,10 @@ PEI Dispatcher Dependency Evaluator This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine - if a driver can be scheduled for execution. The criteria for - schedulability is that the dependency expression is satisfied. + if a driver can be scheduled for execution. The criteria to be scheduled is + that the dependency expression is satisfied. -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -45,7 +45,7 @@ IsPpiInstalled ( } // - // Copy the Guid into a locale variable so that there are no + // Copy the GUID into a local variable so that there are no // possibilities of alignment faults for cross-compilation // environments such as Intel?Itanium(TM). // @@ -72,7 +72,7 @@ IsPpiInstalled ( This is the POSTFIX version of the dependency evaluator. When a PUSH [PPI GUID] is encountered, a pointer to the GUID is stored on - the evaluation stack. When that entry is poped from the evaluation + the evaluation stack. When that entry is popped from the evaluation stack, the PPI is checked if it is installed. This method allows some time savings as not all PPIs must be checked for certain operation types (AND, OR). @@ -123,7 +123,7 @@ PeimDispatchReadiness ( // // Push the pointer to the PUSH opcode operator (pointer to PPI GUID) - // We will evaluate if the PPI is insalled on the POP operation. + // We will evaluate if the PPI is installed on the POP operation. // StackPtr->Operator = (VOID *) Iterator; Iterator = Iterator + sizeof (EFI_GUID); diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c index ba2fd0cae14..a18ac47f617 100644 --- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c +++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c @@ -1,7 +1,7 @@ /** @file EFI PEI Core dispatch services -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
(C) Copyright 2016 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -11,7 +11,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent /** - Discover all Peims and optional Apriori file in one FV. There is at most one + Discover all PEIMs and optional Apriori file in one FV. There is at most one Apriori file in one FV. @@ -49,7 +49,7 @@ DiscoverPeimsAndOrderWithApriori ( Guid = NULL; // - // If the current Fv has been scanned, directly get its cached records. + // If the current FV has been scanned, directly get its cached records. // if (CoreFileHandle->ScanFv) { Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles; @@ -60,7 +60,7 @@ DiscoverPeimsAndOrderWithApriori ( TempFileGuid = Private->TempFileGuid; // - // Go ahead to scan this Fv, get PeimCount and cache FileHandles within it to TempFileHandles. + // Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles. // PeimCount = 0; FileHandle = NULL; @@ -147,7 +147,7 @@ DiscoverPeimsAndOrderWithApriori ( for (Index = 0; Index < PeimCount; Index++) { // - // Make an array of file name guids that matches the FileHandle array so we can convert + // Make an array of file name GUIDs that matches the FileHandle array so we can convert // quickly from file name to file handle // Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo); @@ -156,7 +156,7 @@ DiscoverPeimsAndOrderWithApriori ( } // - // Walk through TempFileGuid array to find out who is invalid PEIM guid in Apriori file. + // Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file. // Add available PEIMs in Apriori file into FvFileHandles array. // Index = 0; @@ -194,8 +194,8 @@ DiscoverPeimsAndOrderWithApriori ( } // - // The current Fv File Handles have been cached. So that we don't have to scan the Fv again. - // Instead, we can retrieve the file handles within this Fv from cached records. + // The current FV File Handles have been cached. So that we don't have to scan the FV again. + // Instead, we can retrieve the file handles within this FV from cached records. // CoreFileHandle->ScanFv = TRUE; Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles; @@ -307,7 +307,7 @@ PeiLoadFixAddressHook( DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressPeiCodePageNumber))); DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize)); // - // Loop through the system memory typed hob to merge the adjacent memory range + // Loop through the system memory typed HOB to merge the adjacent memory range // for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { // @@ -317,7 +317,7 @@ PeiLoadFixAddressHook( ResourceHob = Hob.ResourceDescriptor; // - // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored. + // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored. // if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY || ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS) { @@ -387,18 +387,18 @@ PeiLoadFixAddressHook( if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { NextResourceHob = NextHob.ResourceDescriptor; // - // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored. + // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored. // if (NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY || NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS) { continue; } // - // If the range describe in memory allocation HOB belongs to the memroy range described by the resource hob + // If the range describe in memory allocation HOB belongs to the memory range described by the resource HOB // if (MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart && MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) { // - // Build seperate resource hob for this allocated range + // Build separate resource HOB for this allocated range // if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) { BuildResourceDescriptorHob ( @@ -452,7 +452,7 @@ PeiLoadFixAddressHook( ResourceHob = Hob.ResourceDescriptor; // - // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS + // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS // if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) { @@ -476,7 +476,7 @@ PeiLoadFixAddressHook( DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress)); DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n")); // - // Print the recomended Top address range. + // Print the recommended Top address range. // for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { // @@ -486,7 +486,7 @@ PeiLoadFixAddressHook( ResourceHob = Hob.ResourceDescriptor; // - // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS + // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS // if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) { @@ -524,7 +524,7 @@ PeiLoadFixAddressHook( ResourceHob = Hob.ResourceDescriptor; // - // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS + // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS // if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS && @@ -554,7 +554,7 @@ PeiLoadFixAddressHook( if (CurrentResourceHob != NULL) { // - // rebuild resource HOB for PEI memmory and reserved memory + // rebuild resource HOB for PEI memory and reserved memory // BuildResourceDescriptorHob ( EFI_RESOURCE_SYSTEM_MEMORY, @@ -750,7 +750,7 @@ PeiCheckAndSwitchStack ( ASSERT (NewStackSize >= SecCoreData->StackSize); // - // Calculate stack offset and heap offset between temporary memory and new permement + // Calculate stack offset and heap offset between temporary memory and new permanent // memory seperately. // TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize; @@ -1042,10 +1042,10 @@ PeiDispatcher ( // // This is the main dispatch loop. It will search known FVs for PEIMs and // attempt to dispatch them. If any PEIM gets dispatched through a single - // pass of the dispatcher, it will start over from the Bfv again to see + // pass of the dispatcher, it will start over from the BFV again to see // if any new PEIMs dependencies got satisfied. With a well ordered // FV where PEIMs are found in the order their dependencies are also - // satisfied, this dipatcher should run only once. + // satisfied, this dispatcher should run only once. // do { // @@ -1081,7 +1081,7 @@ PeiDispatcher ( } // - // Start to dispatch all modules within the current Fv. + // Start to dispatch all modules within the current FV. // for (PeimCount = Private->CurrentPeimCount; PeimCount < Private->Fv[FvCount].PeimCount; @@ -1097,7 +1097,7 @@ PeiDispatcher ( ASSERT_EFI_ERROR (Status); if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { // - // For Fv type file, Produce new FvInfo PPI and FV hob + // For FV type file, Produce new FvInfo PPI and FV HOB // Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle); if (Status == EFI_SUCCESS) { @@ -1317,7 +1317,7 @@ DepexSatisfied ( if (PeimCount < Private->AprioriCount) { // - // If it's in the Apriori file then we set Depex to TRUE + // If it's in the Apriori file then we set DEPEX to TRUE // DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n")); return TRUE; @@ -1347,8 +1347,8 @@ DepexSatisfied ( } /** - This routine enable a PEIM to register itself to shadow when PEI Foundation - discovery permanent memory. + This routine enables a PEIM to register itself for shadow when the PEI Foundation + discovers permanent memory. @param FileHandle File handle of a PEIM. diff --git a/MdeModulePkg/Core/Pei/FwVol/FwVol.c b/MdeModulePkg/Core/Pei/FwVol/FwVol.c index f4642c47c13..b3661146f29 100644 --- a/MdeModulePkg/Core/Pei/FwVol/FwVol.c +++ b/MdeModulePkg/Core/Pei/FwVol/FwVol.c @@ -13,12 +13,12 @@ EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnFvInfoList[] = { { EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, &gEfiPeiFirmwareVolumeInfoPpiGuid, - FirmwareVolmeInfoPpiNotifyCallback + FirmwareVolumeInfoPpiNotifyCallback }, { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiFirmwareVolumeInfo2PpiGuid, - FirmwareVolmeInfoPpiNotifyCallback + FirmwareVolumeInfoPpiNotifyCallback } }; @@ -447,7 +447,7 @@ FindFileEx ( } /** - Initialize PeiCore Fv List. + Initialize PeiCore FV List. @param PrivateData - Pointer to PEI_CORE_INSTANCE. @param SecCoreData - Pointer to EFI_SEC_PEI_HAND_OFF. @@ -520,7 +520,7 @@ PeiInitializeFv ( // // Post a call-back for the FvInfoPPI and FvInfo2PPI services to expose - // additional Fvs to PeiCore. + // additional FVs to PeiCore. // Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList); ASSERT_EFI_ERROR (Status); @@ -528,7 +528,7 @@ PeiInitializeFv ( } /** - Process Firmware Volum Information once FvInfoPPI or FvInfo2PPI install. + Process Firmware Volume Information once FvInfoPPI or FvInfo2PPI install. The FV Info will be registered into PeiCore private data structure. And search the inside FV image, if found, the new FV INFO(2) PPI will be installed. @@ -537,12 +537,12 @@ PeiInitializeFv ( @param Ppi Address of the PPI that was installed. @retval EFI_SUCCESS The FV Info is registered into PeiCore private data structure. - @return if not EFI_SUCESS, fail to verify FV. + @return if not EFI_SUCCESS, fail to verify FV. **/ EFI_STATUS EFIAPI -FirmwareVolmeInfoPpiNotifyCallback ( +FirmwareVolumeInfoPpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi @@ -593,7 +593,7 @@ FirmwareVolmeInfoPpiNotifyCallback ( } // - // Locate the corresponding FV_PPI according to founded FV's format guid + // Locate the corresponding FV_PPI according to the format GUID of the FV found // Status = PeiServicesLocatePpi ( &FvInfo2Ppi.FvFormat, @@ -620,7 +620,7 @@ FirmwareVolmeInfoPpiNotifyCallback ( PrivateData->Fv[FvIndex].AuthenticationStatus = FvInfo2Ppi.AuthenticationStatus; DEBUG ((EFI_D_INFO, "Update AuthenticationStatus of the %dth FV to 0x%x!\n", FvIndex, FvInfo2Ppi.AuthenticationStatus)); } - DEBUG ((EFI_D_INFO, "The Fv %p has already been processed!\n", FvInfo2Ppi.FvInfo)); + DEBUG ((DEBUG_INFO, "The FV %p has already been processed!\n", FvInfo2Ppi.FvInfo)); return EFI_SUCCESS; } } @@ -661,7 +661,7 @@ FirmwareVolmeInfoPpiNotifyCallback ( PrivateData->FvCount ++; // - // Scan and process the new discoveried FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE + // Scan and process the new discovered FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE // FileHandle = NULL; do { @@ -1359,11 +1359,11 @@ GetFvUsedSize ( } /** - Get Fv image(s) from the FV type file, then install FV INFO(2) ppi, Build FV(2, 3) hob. + Get FV image(s) from the FV type file, then install FV INFO(2) PPI, Build FV(2, 3) HOB. @param PrivateData PeiCore's private data structure - @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent Fv image that contain this Fv image. - @param ParentFvFileHandle File handle of a Fv type file that contain this Fv image. + @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent FV image that contain this FV image. + @param ParentFvFileHandle File handle of a FV type file that contain this FV image. @retval EFI_NOT_FOUND FV image can't be found. @retval EFI_SUCCESS Successfully to process it. @@ -1533,7 +1533,7 @@ ProcessFvFile ( ); // - // Inform the extracted FvImage to Fv HOB consumer phase, i.e. DXE phase + // Expose the extracted FvImage to the FV HOB consumer phase, i.e. DXE phase // BuildFvHob ( (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, @@ -1619,7 +1619,7 @@ PeiFfsFvPpiProcessVolume ( // // The build-in EFI_PEI_FIRMWARE_VOLUME_PPI for FFS2/FFS3 support memory-mapped - // FV image and the handle is pointed to Fv image's buffer. + // FV image and the handle is pointed to FV image's buffer. // *FvHandle = (EFI_PEI_FV_HANDLE) Buffer; @@ -1915,7 +1915,7 @@ PeiFfsFvPpiGetVolumeInfo ( CopyMem (&FwVolHeader, FvHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); // - // Check Fv Image Signature + // Check FV Image Signature // if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) { return EFI_INVALID_PARAMETER; @@ -2087,12 +2087,13 @@ FvHandleToCoreHandle ( } /** - Get instance of PEI_CORE_FV_HANDLE for next volume according to given index. + Gets a PEI_CORE_FV_HANDLE instance for the next volume according to the given index. - This routine also will install FvInfo ppi for FV hob in PI ways. + This routine also will install an instance of the FvInfo PPI for the FV HOB + as defined in the PI specification. @param Private Pointer of PEI_CORE_INSTANCE - @param Instance The index of FV want to be searched. + @param Instance Index of the FV to search @return Instance of PEI_CORE_FV_HANDLE. **/ @@ -2185,13 +2186,14 @@ PeiReinitializeFv ( } /** - Report the information for a new discoveried FV in unknown third-party format. + Report the information for a newly discovered FV in an unknown format. - If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for third-party FV format, but - the FV in this format has been discoveried, then this FV's information will be cached into - PEI_CORE_INSTANCE's UnknownFvInfo array. - Also a notification would be installed for unknown third-party FV format guid, if EFI_PEI_FIRMWARE_VOLUME_PPI - is installed later by platform's PEIM, the original unknown third-party FV will be processed by + If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for a third-party FV format, but + the FV has been discovered, then the information of this FV will be cached into PEI_CORE_INSTANCE's + UnknownFvInfo array. + + Also a notification would be installed for unknown FV format GUID, if EFI_PEI_FIRMWARE_VOLUME_PPI + is installed later by platform's PEIM, the original unknown FV will be processed by using new installed EFI_PEI_FIRMWARE_VOLUME_PPI. @param PrivateData Point to instance of PEI_CORE_INSTANCE @@ -2242,13 +2244,13 @@ AddUnknownFormatFvInfo ( } /** - Find the FV information according to third-party FV format guid. + Find the FV information according to third-party FV format GUID. - This routine also will remove the FV information found by given FV format guid from + This routine also will remove the FV information found by given FV format GUID from PrivateData->UnknownFvInfo[]. @param PrivateData Point to instance of PEI_CORE_INSTANCE - @param Format Point to given FV format guid + @param Format Point to given FV format GUID @param FvInfo On return, the pointer of FV information buffer @param FvInfoSize On return, the size of FV information buffer. @param AuthenticationStatus On return, the authentication status of FV information buffer. @@ -2298,7 +2300,7 @@ FindUnknownFormatFvInfo ( Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI. When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this - routine is called to process all discoveried FVs in this format. + routine is called to process all discovered FVs in this format. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @param NotifyDescriptor Address of the notification descriptor data structure. @@ -2352,7 +2354,7 @@ ThirdPartyFvPpiNotifyCallback ( IsProcessed = FALSE; for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) { if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) { - DEBUG ((EFI_D_INFO, "The Fv %p has already been processed!\n", FvInfo)); + DEBUG ((DEBUG_INFO, "The FV %p has already been processed!\n", FvInfo)); IsProcessed = TRUE; break; } @@ -2398,7 +2400,7 @@ ThirdPartyFvPpiNotifyCallback ( PrivateData->FvCount ++; // - // Scan and process the new discoveried FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE + // Scan and process the new discovered FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE // FileHandle = NULL; do { diff --git a/MdeModulePkg/Core/Pei/FwVol/FwVol.h b/MdeModulePkg/Core/Pei/FwVol/FwVol.h index ca80e84e0fc..7241c01b8cb 100644 --- a/MdeModulePkg/Core/Pei/FwVol/FwVol.h +++ b/MdeModulePkg/Core/Pei/FwVol/FwVol.h @@ -1,7 +1,7 @@ /** @file The internal header file for firmware volume related definitions. -Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -303,12 +303,13 @@ FindFileEx ( ); /** - Report the information for a new discoveried FV in unknown format. + Report the information for a newly discovered FV in an unknown format. - If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for specifical FV format, but - the FV in this FV format has been discoveried, then the information of this FV - will be cached into PEI_CORE_INSTANCE's UnknownFvInfo array. - Also a notification would be installed for unknown FV format guid, if EFI_PEI_FIRMWARE_VOLUME_PPI + If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for a third-party FV format, but + the FV has been discovered, then the information of this FV will be cached into PEI_CORE_INSTANCE's + UnknownFvInfo array. + + Also a notification would be installed for unknown FV format GUID, if EFI_PEI_FIRMWARE_VOLUME_PPI is installed later by platform's PEIM, the original unknown FV will be processed by using new installed EFI_PEI_FIRMWARE_VOLUME_PPI. @@ -325,14 +326,14 @@ AddUnknownFormatFvInfo ( ); /** - Find the FV information according to FV format guid. + Find the FV information according to FV format GUID. - This routine also will remove the FV information found by given FV format guid from + This routine also will remove the FV information found by given FV format GUID from PrivateData->UnknownFvInfo[]. @param PrivateData Point to instance of PEI_CORE_INSTANCE - @param Format Point to given FV format guid - @param FvInfo On return, the pointer of FV information buffer in given FV format guid + @param Format Point to given FV format GUID + @param FvInfo On return, the pointer of FV information buffer in given FV format GUID @param FvInfoSize On return, the size of FV information buffer. @param AuthenticationStatus On return, the authentication status of FV information buffer. @@ -352,7 +353,7 @@ FindUnknownFormatFvInfo ( Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI. When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this - routine is called to process all discoveried FVs in this format. + routine is called to process all discovered FVs in this format. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @param NotifyDescriptor Address of the notification descriptor data structure. diff --git a/MdeModulePkg/Core/Pei/Hob/Hob.c b/MdeModulePkg/Core/Pei/Hob/Hob.c index 5900f6042b6..e0e47fad25b 100644 --- a/MdeModulePkg/Core/Pei/Hob/Hob.c +++ b/MdeModulePkg/Core/Pei/Hob/Hob.c @@ -1,7 +1,7 @@ /** @file This module provide Hand-Off Block manupulation. -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -55,7 +55,7 @@ PeiGetHobList ( @param Length Length of the new HOB to allocate. @param Hob Pointer to the new HOB. - @return EFI_SUCCESS Success to create hob. + @return EFI_SUCCESS Success to create HOB. @retval EFI_INVALID_PARAMETER if Hob is NULL @retval EFI_NOT_AVAILABLE_YET if HobList is still not available. @retval EFI_OUT_OF_RESOURCES if there is no more memory to grow the Hoblist. diff --git a/MdeModulePkg/Core/Pei/Image/Image.c b/MdeModulePkg/Core/Pei/Image/Image.c index d553d9128fd..e3ee3699337 100644 --- a/MdeModulePkg/Core/Pei/Image/Image.c +++ b/MdeModulePkg/Core/Pei/Image/Image.c @@ -1,7 +1,7 @@ /** @file Pei Core Load Image Support -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -99,7 +99,7 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( } // - // Test if the memory is avalaible or not. + // Test if the memory is available or not. // MemoryUsageBitMap = Private->PeiCodeMemoryRangeUsageBitMap; BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - PeiCodeBase)); @@ -290,7 +290,7 @@ LoadAndRelocatePeCoffImage ( } // - // Initilize local IsS3Boot and IsRegisterForShadow variable + // Initialize local IsS3Boot and IsRegisterForShadow variable // IsS3Boot = FALSE; if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) { @@ -363,7 +363,7 @@ LoadAndRelocatePeCoffImage ( if (EFI_ERROR (Status)){ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // - // The PEIM is not assiged valid address, try to allocate page to load it. + // The PEIM is not assigned valid address, try to allocate page to load it. // Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize), @@ -602,7 +602,7 @@ PeiLoadImageLoadImage ( // // Copy the PDB file name to our temporary string, and replace .pdb with .efi // The PDB file name is limited in the range of 0~511. - // If the length is bigger than 511, trim the redudant characters to avoid overflow in array boundary. + // If the length is bigger than 511, trim the redundant characters to avoid overflow in array boundary. // for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { EfiFileName[Index] = AsciiString[Index + StartIndex]; diff --git a/MdeModulePkg/Core/Pei/Memory/MemoryServices.c b/MdeModulePkg/Core/Pei/Memory/MemoryServices.c index 706837890fd..6b3a64a811c 100644 --- a/MdeModulePkg/Core/Pei/Memory/MemoryServices.c +++ b/MdeModulePkg/Core/Pei/Memory/MemoryServices.c @@ -1,7 +1,7 @@ /** @file EFI PEI Core memory services -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -17,7 +17,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent environment, such as the size and location of temporary RAM, the stack location and the BFV location. @param OldCoreData Pointer to the PEI Core data. - NULL if being run in non-permament memory mode. + NULL if being run in non-permanent memory mode. **/ VOID @@ -32,7 +32,7 @@ InitializeMemoryServices ( // // First entering PeiCore, following code will initialized some field - // in PeiCore's private data according to hand off data from sec core. + // in PeiCore's private data according to hand off data from SEC core. // if (OldCoreData == NULL) { @@ -61,7 +61,7 @@ InitializeMemoryServices ( The usage model is that the PEIM that discovers the permanent memory shall invoke this service. This routine will hold discoveried memory information into PeiCore's private data, and set SwitchStackSignal flag. After PEIM who discovery memory is dispatched, - PeiDispatcher will migrate temporary memory to permenement memory. + PeiDispatcher will migrate temporary memory to permanent memory. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. @param MemoryBegin Start of memory address. @@ -86,7 +86,7 @@ PeiInstallPeiMemory ( // // PEI_SERVICE.InstallPeiMemory should only be called one time during whole PEI phase. // If it is invoked more than one time, ASSERT information is given for developer debugging in debug tip and - // simply return EFI_SUCESS in release tip to ignore it. + // simply return EFI_SUCCESS in release tip to ignore it. // if (PrivateData->PeiMemoryInstalled) { DEBUG ((EFI_D_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n")); @@ -758,9 +758,9 @@ PeiFreePages ( /** - Pool allocation service. Before permanent memory is discoveried, the pool will - be allocated the heap in the temporary memory. Genenrally, the size of heap in temporary - memory does not exceed to 64K, so the biggest pool size could be allocated is + Pool allocation service. Before permanent memory is discovered, the pool will + be allocated in the heap in temporary memory. Generally, the size of the heap in temporary + memory does not exceed 64K, so the biggest pool size could be allocated is 64K. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. @@ -789,8 +789,8 @@ PeiAllocatePool ( // // - // Generally, the size of heap in temporary memory does not exceed to 64K, - // HobLength is multiples of 8 bytes, so the maxmium size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL) + // Generally, the size of heap in temporary memory does not exceed 64K, + // HobLength is multiples of 8 bytes, so the maximum size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL) // if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) { return EFI_OUT_OF_RESOURCES; diff --git a/MdeModulePkg/Core/Pei/PeiMain.h b/MdeModulePkg/Core/Pei/PeiMain.h index f2aa97c6640..6431bdaaacf 100644 --- a/MdeModulePkg/Core/Pei/PeiMain.h +++ b/MdeModulePkg/Core/Pei/PeiMain.h @@ -47,7 +47,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent /// /// It is an FFS type extension used for PeiFindFileEx. It indicates current -/// Ffs searching is for all PEIMs can be dispatched by PeiCore. +/// FFS searching is for all PEIMs can be dispatched by PeiCore. /// #define PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE 0xff @@ -116,7 +116,7 @@ typedef struct { } PEI_PPI_DATABASE; // -// PEI_CORE_FV_HANDE.PeimState +// PEI_CORE_FV_HANDLE.PeimState // Do not change these values as there is code doing math to change states. // Look for Private->Fv[FvCount].PeimState[PeimCount]++; // @@ -136,11 +136,11 @@ typedef struct { EFI_PEI_FV_HANDLE FvHandle; UINTN PeimCount; // - // Ponter to the buffer with the PeimCount number of Entries. + // Pointer to the buffer with the PeimCount number of Entries. // UINT8 *PeimState; // - // Ponter to the buffer with the PeimCount number of Entries. + // Pointer to the buffer with the PeimCount number of Entries. // EFI_PEI_FILE_HANDLE *FvFileHandles; BOOLEAN ScanFv; @@ -277,7 +277,7 @@ struct _PEI_CORE_INSTANCE { // // For Loading modules at fixed address feature to cache the top address below which the // Runtime code, boot time code and PEI memory will be placed. Please note that the offset between this field - // and Ps should not be changed since maybe user could get this top address by using the offet to Ps. + // and Ps should not be changed since maybe user could get this top address by using the offset to Ps. // EFI_PHYSICAL_ADDRESS LoadModuleAtFixAddressTopAddress; // @@ -372,7 +372,7 @@ PeiCore ( This is the POSTFIX version of the dependency evaluator. When a PUSH [PPI GUID] is encountered, a pointer to the GUID is stored on - the evaluation stack. When that entry is poped from the evaluation + the evaluation stack. When that entry is popped from the evaluation stack, the PPI is checked if it is installed. This method allows some time savings as not all PPIs must be checked for certain operation types (AND, OR). @@ -412,7 +412,7 @@ PeiDispatcher ( @param PrivateData PeiCore's private data structure @param OldCoreData Old data from SecCore - NULL if being run in non-permament memory mode. + NULL if being run in non-permanent memory mode. @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size and location of temporary RAM, the stack location and the BFV location. @@ -453,7 +453,7 @@ DepexSatisfied ( @param PrivateData Pointer to the PEI Core data. @param OldCoreData Pointer to old PEI Core data. - NULL if being run in non-permament memory mode. + NULL if being run in non-permanent memory mode. **/ VOID @@ -482,7 +482,7 @@ ConvertPpiPointers ( Install PPI services. It is implementation of EFI_PEI_SERVICE.InstallPpi. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. - @param PpiList Pointer to ppi array that want to be installed. + @param PpiList Pointer to PPI array that want to be installed. @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed. @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer @@ -659,7 +659,7 @@ PeiSetBootMode ( @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. @param OldCoreData Pointer to the old core data. - NULL if being run in non-permament memory mode. + NULL if being run in non-permanent memory mode. **/ VOID @@ -687,7 +687,7 @@ VerifyFv ( @param PrivateData PeiCore's private data structure @param VolumeHandle Handle of FV - @param FileHandle Handle of PEIM's ffs + @param FileHandle Handle of PEIM's FFS @param AuthenticationStatus Authentication status @retval EFI_SUCCESS Image is OK @@ -730,7 +730,7 @@ PeiGetHobList ( @param Length Length of the new HOB to allocate. @param Hob Pointer to the new HOB. - @return EFI_SUCCESS Success to create hob. + @return EFI_SUCCESS Success to create HOB. @retval EFI_INVALID_PARAMETER if Hob is NULL @retval EFI_NOT_AVAILABLE_YET if HobList is still not available. @retval EFI_OUT_OF_RESOURCES if there is no more memory to grow the Hoblist. @@ -887,7 +887,7 @@ PeiFfsFindNextVolume ( @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size and location of temporary RAM, the stack location and the BFV location. @param OldCoreData Pointer to the PEI Core data. - NULL if being run in non-permament memory mode. + NULL if being run in non-permanent memory mode. **/ VOID @@ -1111,7 +1111,7 @@ PeiResetSystem2 ( /** - Initialize PeiCore Fv List. + Initialize PeiCore FV List. @param PrivateData - Pointer to PEI_CORE_INSTANCE. @@ -1125,7 +1125,7 @@ PeiInitializeFv ( ); /** - Process Firmware Volum Information once FvInfoPPI install. + Process Firmware Volume Information once FvInfoPPI install. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. @param NotifyDescriptor Address of the notification descriptor data structure. @@ -1136,7 +1136,7 @@ PeiInitializeFv ( **/ EFI_STATUS EFIAPI -FirmwareVolmeInfoPpiNotifyCallback ( +FirmwareVolumeInfoPpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi @@ -1217,8 +1217,8 @@ PeiFfsGetVolumeInfo ( ); /** - This routine enable a PEIM to register itself to shadow when PEI Foundation - discovery permanent memory. + This routine enables a PEIM to register itself for shadow when the PEI Foundation + discovers permanent memory. @param FileHandle File handle of a PEIM. @@ -1293,11 +1293,11 @@ SecurityPpiNotifyCallback ( ); /** - Get Fv image(s) from the FV type file, then install FV INFO(2) ppi, Build FV(2, 3) hob. + Get FV image(s) from the FV type file, then install FV INFO(2) PPI, Build FV(2, 3) HOB. @param PrivateData PeiCore's private data structure - @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent Fv image that contain this Fv image. - @param ParentFvFileHandle File handle of a Fv type file that contain this Fv image. + @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent FV image that contain this FV image. + @param ParentFvFileHandle File handle of a FV type file that contain this FV image. @retval EFI_NOT_FOUND FV image can't be found. @retval EFI_SUCCESS Successfully to process it. @@ -1314,12 +1314,13 @@ ProcessFvFile ( ); /** - Get instance of PEI_CORE_FV_HANDLE for next volume according to given index. + Gets a PEI_CORE_FV_HANDLE instance for the next volume according to the given index. - This routine also will install FvInfo ppi for FV hob in PI ways. + This routine also will install an instance of the FvInfo PPI for the FV HOB + as defined in the PI specification. @param Private Pointer of PEI_CORE_INSTANCE - @param Instance The index of FV want to be searched. + @param Instance Index of the FV to search @return Instance of PEI_CORE_FV_HANDLE. **/ diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf b/MdeModulePkg/Core/Pei/PeiMain.inf index 7c482dacfc3..6e25cc40232 100644 --- a/MdeModulePkg/Core/Pei/PeiMain.inf +++ b/MdeModulePkg/Core/Pei/PeiMain.inf @@ -69,12 +69,12 @@ [Guids] gPeiAprioriFileNameGuid ## SOMETIMES_CONSUMES ## File - ## PRODUCES ## UNDEFINED # Install ppi - ## CONSUMES ## UNDEFINED # Locate ppi + ## PRODUCES ## UNDEFINED # Install PPI + ## CONSUMES ## UNDEFINED # Locate PPI gEfiFirmwareFileSystem2Guid - ## PRODUCES ## UNDEFINED # Install ppi - ## CONSUMES ## UNDEFINED # Locate ppi - ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format + ## PRODUCES ## UNDEFINED # Install PPI + ## CONSUMES ## UNDEFINED # Locate PPI + ## CONSUMES ## GUID # Used to compare with FV's file system GUID and get the FV's file system format gEfiFirmwareFileSystem3Guid [Ppis] diff --git a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c index 33f056ea8f5..025d7f98ec2 100644 --- a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c +++ b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c @@ -315,7 +315,7 @@ PeiCore ( } // - // Shadow PEI Core. When permanent memory is avaiable, shadow + // Shadow PEI Core. When permanent memory is available, shadow // PEI Core and PEIMs to get high performance. // OldCoreData->ShadowedPeiCore = (PEICORE_FUNCTION_POINTER) (UINTN) PeiCore; diff --git a/MdeModulePkg/Core/Pei/Ppi/Ppi.c b/MdeModulePkg/Core/Pei/Ppi/Ppi.c index 964aee690e2..1ffe718c470 100644 --- a/MdeModulePkg/Core/Pei/Ppi/Ppi.c +++ b/MdeModulePkg/Core/Pei/Ppi/Ppi.c @@ -1,7 +1,7 @@ /** @file EFI PEI Core PPI services -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -663,7 +663,7 @@ ProcessDispatchNotifyList ( // // Check if the PEIM that was just dispatched resulted in any // Notifies getting installed. If so, go process any dispatch - // level Notifies that match the previouly installed PPIs. + // level Notifies that match the previously installed PPIs. // Use "while" instead of "if" since ProcessNotify can modify // DispatchNotifyList.CurrentCount (with NotifyPpi) so we have // to iterate until the same. diff --git a/MdeModulePkg/Core/Pei/Security/Security.c b/MdeModulePkg/Core/Pei/Security/Security.c index 99da505538f..8c18ed6cc89 100644 --- a/MdeModulePkg/Core/Pei/Security/Security.c +++ b/MdeModulePkg/Core/Pei/Security/Security.c @@ -1,7 +1,7 @@ /** @file EFI PEI Core Security services -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -20,7 +20,7 @@ EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = { @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. @param OldCoreData Pointer to the old core data. - NULL if being run in non-permament memory mode. + NULL if being run in non-permanent memory mode. **/ VOID @@ -76,7 +76,7 @@ SecurityPpiNotifyCallback ( @param PrivateData PeiCore's private data structure @param VolumeHandle Handle of FV - @param FileHandle Handle of PEIM's ffs + @param FileHandle Handle of PEIM's FFS @param AuthenticationStatus Authentication status @retval EFI_SUCCESS Image is OK @@ -92,7 +92,7 @@ VerifyPeim ( ) { EFI_STATUS Status; - BOOLEAN DeferExection; + BOOLEAN DeferExecution; Status = EFI_NOT_FOUND; if (PrivateData->PrivateSecurityPpi == NULL) { @@ -114,9 +114,9 @@ VerifyPeim ( AuthenticationStatus, VolumeHandle, FileHandle, - &DeferExection + &DeferExecution ); - if (DeferExection) { + if (DeferExecution) { Status = EFI_SECURITY_VIOLATION; } } diff --git a/MdeModulePkg/Include/Guid/SmmVariableCommon.h b/MdeModulePkg/Include/Guid/SmmVariableCommon.h index c527a598913..ceef44dfd2d 100644 --- a/MdeModulePkg/Include/Guid/SmmVariableCommon.h +++ b/MdeModulePkg/Include/Guid/SmmVariableCommon.h @@ -1,7 +1,7 @@ /** @file The file defined some common structures used for communicating between SMM variable module and SMM variable wrapper module. -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -9,6 +9,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #ifndef _SMM_VARIABLE_COMMON_H_ #define _SMM_VARIABLE_COMMON_H_ +#include #include #define EFI_SMM_VARIABLE_WRITE_GUID \ @@ -66,6 +67,16 @@ typedef struct { #define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10 #define SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE 11 +// +// The payload for this function is SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT +// +#define SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT 12 + +#define SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE 13 +// +// The payload for this function is SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO +// +#define SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO 14 /// /// Size of SMM communicate header, without including the payload. @@ -120,4 +131,20 @@ typedef struct { UINTN VariablePayloadSize; } SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE; +typedef struct { + BOOLEAN *ReadLock; + BOOLEAN *PendingUpdate; + BOOLEAN *HobFlushComplete; + VARIABLE_STORE_HEADER *RuntimeHobCache; + VARIABLE_STORE_HEADER *RuntimeNvCache; + VARIABLE_STORE_HEADER *RuntimeVolatileCache; +} SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT; + +typedef struct { + UINTN TotalHobStorageSize; + UINTN TotalNvStorageSize; + UINTN TotalVolatileStorageSize; + BOOLEAN AuthenticatedVariableUsage; +} SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO; + #endif // _SMM_VARIABLE_COMMON_H_ diff --git a/MdeModulePkg/Include/Library/ResetSystemLib.h b/MdeModulePkg/Include/Library/ResetSystemLib.h index 3b2a098a608..09ee14540c4 100644 --- a/MdeModulePkg/Include/Library/ResetSystemLib.h +++ b/MdeModulePkg/Include/Library/ResetSystemLib.h @@ -51,17 +51,6 @@ ResetShutdown ( VOID ); -/** - This function causes the system to enter S3 and then wake up immediately. - - If this function returns, it means that the system does not support S3 feature. -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ); - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/MdeModulePkg/Include/Protocol/DeviceSecurity.h b/MdeModulePkg/Include/Protocol/DeviceSecurity.h new file mode 100644 index 00000000000..c3bf624cac3 --- /dev/null +++ b/MdeModulePkg/Include/Protocol/DeviceSecurity.h @@ -0,0 +1,162 @@ +/** @file + Device Security Protocol definition. + + It is used to authenticate a device based upon the platform policy. + It is similar to the EFI_SECURITY_ARCH_PROTOCOL, which is used to verify a image. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef __DEVICE_SECURITY_H__ +#define __DEVICE_SECURITY_H__ + +// +// Device Security Protocol GUID value +// +#define EDKII_DEVICE_SECURITY_PROTOCOL_GUID \ + { \ + 0x5d6b38c8, 0x5510, 0x4458, { 0xb4, 0x8d, 0x95, 0x81, 0xcf, 0xa7, 0xb0, 0xd } \ + } + +// +// Forward reference for pure ANSI compatability +// +typedef struct _EDKII_DEVICE_SECURITY_PROTOCOL EDKII_DEVICE_SECURITY_PROTOCOL; + +// +// Revision The revision to which the DEVICE_SECURITY interface adheres. +// All future revisions must be backwards compatible. +// If a future version is not back wards compatible it is not the same GUID. +// +#define EDKII_DEVICE_SECURITY_PROTOCOL_REVISION 0x00010000 + +// +// The device identifier. +// +typedef struct { + /// + /// Version of this data structure. + /// + UINT32 Version; + /// + /// Type of the device. + /// This field is also served as a device Access protocol GUID. + /// The device access protocol is installed on the DeviceHandle. + /// The device access protocol is device specific. + /// EDKII_DEVICE_IDENTIFIER_TYPE_PCI_GUID means the device access protocol is PciIo. + /// EDKII_DEVICE_IDENTIFIER_TYPE_USB_GUID means the device access protocol is UsbIo. + /// + EFI_GUID DeviceType; + /// + /// The handle created for this device. + /// NOTE: This might be a temporary handle. + /// If the device is not authenticated, this handle shall be uninstalled. + /// + /// As minimal requirement, there should be 2 protocols installed on the device handle. + /// 1) An EFI_DEVICE_PATH_PROTOCOL with EFI_DEVICE_PATH_PROTOCOL_GUID. + /// 2) A device access protocol with EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID. + /// If the device is PCI device, the EFI_PCI_IO_PROTOCOL is installed with + /// EDKII_DEVICE_IDENTIFIER_TYPE_PCI_GUID. + /// If the device is USB device, the EFI_USB_IO_PROTOCOL is installed with + /// EDKII_DEVICE_IDENTIFIER_TYPE_USB_GUID. + /// + /// The device access protocol is required, because the verifier need have a way + /// to communciate with the device hardware to get the measurement or do the + /// challenge/response for the device authentication. + /// + /// NOTE: We don't use EFI_PCI_IO_PROTOCOL_GUID or EFI_USB_IO_PROTOCOL_GUID here, + /// because we don't want to expose a real protocol. A platform may have driver + /// register a protocol notify function. Installing a real protocol may cause + /// the callback function being executed before the device is authenticated. + /// + EFI_HANDLE DeviceHandle; +} EDKII_DEVICE_IDENTIFIER; + +// +// Revision The revision to which the DEVICE_IDENTIFIER interface adheres. +// All future revisions must be backwards compatible. +// +#define EDKII_DEVICE_IDENTIFIER_REVISION 0x00010000 + +// +// Device Identifier GUID value +// +#define EDKII_DEVICE_IDENTIFIER_TYPE_PCI_GUID \ + { \ + 0x2509b2f1, 0xa022, 0x4cca, { 0xaf, 0x70, 0xf9, 0xd3, 0x21, 0xfb, 0x66, 0x49 } \ + } + +#define EDKII_DEVICE_IDENTIFIER_TYPE_USB_GUID \ + { \ + 0x7394f350, 0x394d, 0x488c, { 0xbb, 0x75, 0xc, 0xab, 0x7b, 0x12, 0xa, 0xc5 } \ + } + +/** + The device driver uses this service to measure and/or verify a device. + + The flow in device driver is: + 1) Device driver discovers a new device. + 2) Device driver creates an EFI_DEVICE_PATH_PROTOCOL. + 3) Device driver creates a device access protocol. e.g. + EFI_PCI_IO_PROTOCOL for PCI device. + EFI_USB_IO_PROTOCOL for USB device. + EFI_EXT_SCSI_PASS_THRU_PROTOCOL for SCSI device. + EFI_ATA_PASS_THRU_PROTOCOL for ATA device. + EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL for NVMe device. + EFI_SD_MMC_PASS_THRU_PROTOCOL for SD/MMC device. + 4) Device driver installs the EFI_DEVICE_PATH_PROTOCOL with EFI_DEVICE_PATH_PROTOCOL_GUID, + and the device access protocol with EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID. + Once it is done, a DeviceHandle is returned. + 5) Device driver creates EDKII_DEVICE_IDENTIFIER with EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID + and the DeviceHandle. + 6) Device driver calls DeviceAuthenticate(). + 7) If DeviceAuthenticate() returns EFI_SECURITY_VIOLATION, the device driver uninstalls + all protocols on this handle. + 8) If DeviceAuthenticate() returns EFI_SUCCESS, the device driver installs the device access + protocol with a real protocol GUID. e.g. + EFI_PCI_IO_PROTOCOL with EFI_PCI_IO_PROTOCOL_GUID. + EFI_USB_IO_PROTOCOL with EFI_USB_IO_PROTOCOL_GUID. + + @param[in] This The protocol instance pointer. + @param[in] DeviceId The Identifier for the device. + + @retval EFI_SUCCESS The device specified by the DeviceId passed the measurement + and/or authentication based upon the platform policy. + If TCG measurement is required, the measurement is extended to TPM PCR. + @retval EFI_SECURITY_VIOLATION The device fails to return the measurement data. + @retval EFI_SECURITY_VIOLATION The device fails to response the authentication request. + @retval EFI_SECURITY_VIOLATION The system fails to verify the device based upon the authentication response. + @retval EFI_SECURITY_VIOLATION The system fails to extend the measurement to TPM PCR. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_DEVICE_AUTHENTICATE)( + IN EDKII_DEVICE_SECURITY_PROTOCOL *This, + IN EDKII_DEVICE_IDENTIFIER *DeviceId + ); + +/// +/// Device Security Protocol structure. +/// It is similar to the EFI_SECURITY_ARCH_PROTOCOL, which is used to verify a image. +/// This protocol is used to authenticate a device based upon the platform policy. +/// +struct _EDKII_DEVICE_SECURITY_PROTOCOL { + UINT64 Revision; + EDKII_DEVICE_AUTHENTICATE DeviceAuthenticate; +}; + +/// +/// Device Security Protocol GUID variable. +/// +extern EFI_GUID gEdkiiDeviceSecurityProtocolGuid; + +/// +/// Device Identifier tpye GUID variable. +/// +extern EFI_GUID gEdkiiDeviceIdentifierTypePciGuid; +extern EFI_GUID gEdkiiDeviceIdentifierTypeUsbGuid; + +#endif diff --git a/MdeModulePkg/Include/Protocol/PlatformBootManager.h b/MdeModulePkg/Include/Protocol/PlatformBootManager.h new file mode 100644 index 00000000000..26b9ce48ad6 --- /dev/null +++ b/MdeModulePkg/Include/Protocol/PlatformBootManager.h @@ -0,0 +1,82 @@ +/** @file + + Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PLATFORM_BOOT_MANAGER_PROTOCOL_H__ +#define __PLATFORM_BOOT_MANAGER_PROTOCOL_H__ + +#include + +// +// Platform Boot Manager Protocol GUID value +// +#define EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL_GUID \ + { \ + 0xaa17add4, 0x756c, 0x460d, { 0x94, 0xb8, 0x43, 0x88, 0xd7, 0xfb, 0x3e, 0x59 } \ + } + +// +// Protocol interface structure +// +typedef struct _EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL; + +// +// Revision The revision to which the protocol interface adheres. +// All future revisions must be backwards compatible. +// If a future version is not back wards compatible it is not the same GUID. +// +#define EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL_REVISION 0x00000001 + +// +// Function Prototypes +// + +/* + This function allows platform to refresh all boot options specific to the platform. Within + this function, platform can make modifications to the auto enumerated platform boot options + as well as NV boot options. + + @param[in const] BootOptions An array of auto enumerated platform boot options. + This array will be freed by caller upon successful + exit of this function and output array would be used. + + @param[in const] BootOptionsCount The number of elements in BootOptions. + + @param[out] UpdatedBootOptions An array of boot options that have been customized + for the platform on top of input boot options. This + array would be allocated by REFRESH_ALL_BOOT_OPTIONS + and would be freed by caller after consuming it. + + @param[out] UpdatedBootOptionsCount The number of elements in UpdatedBootOptions. + + + @retval EFI_SUCCESS Platform refresh to input BootOptions and + BootCount have been done. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + + @retval EFI_INVALID_PARAMETER Input is not correct. + + @retval EFI_UNSUPPORTED Platform specific overrides are not supported. +*/ +typedef +EFI_STATUS +(EFIAPI *PLATFORM_BOOT_MANAGER_REFRESH_ALL_BOOT_OPTIONS) ( + IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions, + IN CONST UINTN BootOptionsCount, + OUT EFI_BOOT_MANAGER_LOAD_OPTION **UpdatedBootOptions, + OUT UINTN *UpdatedBootOptionsCount + ); + +struct _EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL { + UINT64 Revision; + PLATFORM_BOOT_MANAGER_REFRESH_ALL_BOOT_OPTIONS RefreshAllBootOptions; +}; + +extern EFI_GUID gEdkiiPlatformBootManagerProtocolGuid; + +#endif /* __PLATFORM_BOOT_MANAGER_PROTOCOL_H__ */ diff --git a/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c b/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c index 8d4c1028e60..33a896bee05 100644 --- a/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c +++ b/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c @@ -58,20 +58,6 @@ ResetShutdown ( ASSERT (FALSE); } -/** - This function causes the system to enter S3 and then wake up immediately. - - If this function returns, it means that the system does not support S3 feature. -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ) -{ - ASSERT (FALSE); -} - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/types.h b/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/types.h index 2867d206f78..35c95696423 100644 --- a/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/types.h +++ b/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/types.h @@ -13,11 +13,7 @@ #define BROTLI_COMMON_TYPES_H_ //#include /* for size_t */ -#ifndef _SIZE_T_DEFINED -#if !defined(_WIN64) || defined(__GNUC__) -typedef unsigned int size_t; -#endif -#endif +typedef UINTN size_t; #if defined(_MSC_VER) && (_MSC_VER < 1600) typedef __int8 int8_t; diff --git a/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.c b/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.c index a85b6cd9a61..47b814fe8de 100644 --- a/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.c +++ b/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.c @@ -57,19 +57,6 @@ ResetShutdown ( gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); } -/** - This function causes the system to enter S3 and then wake up immediately. - - If this function returns, it means that the system does not support S3 feature. -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ) -{ -} - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTest.c b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTest.c new file mode 100644 index 00000000000..5f7cedb61bd --- /dev/null +++ b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTest.c @@ -0,0 +1,312 @@ +/** @file + Unit tests of the DxeResetSystemLib instance of the ResetSystemLib class + + Copyright (C) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define UNIT_TEST_APP_NAME "DxeResetSystemLib Unit Tests" +#define UNIT_TEST_APP_VERSION "1.0" + +/** + Resets the entire platform. + + @param[in] ResetType The type of reset to perform. + @param[in] ResetStatus The status code for the reset. + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null-terminated + string, optionally followed by additional binary data. + The string is a description that the caller may use to further + indicate the reason for the system reset. + For a ResetType of EfiResetPlatformSpecific the data buffer + also starts with a Null-terminated string that is followed + by an EFI_GUID that describes the specific type of reset to perform. +**/ +STATIC +VOID +EFIAPI +MockResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + check_expected_ptr (ResetType); + check_expected_ptr (ResetStatus); + + // + // NOTE: Mocked functions can also return values, but that + // is for another demo. +} + +/// +/// Mock version of the UEFI Runtime Services Table +/// +EFI_RUNTIME_SERVICES MockRuntime = { + { + EFI_RUNTIME_SERVICES_SIGNATURE, // Signature + EFI_RUNTIME_SERVICES_REVISION, // Revision + sizeof (EFI_RUNTIME_SERVICES), // HeaderSize + 0, // CRC32 + 0 // Reserved + }, + NULL, // GetTime + NULL, // SetTime + NULL, // GetWakeupTime + NULL, // SetWakeupTime + NULL, // SetVirtualAddressMap + NULL, // ConvertPointer + NULL, // GetVariable + NULL, // GetNextVariableName + NULL, // SetVariable + NULL, // GetNextHighMonotonicCount + MockResetSystem, // ResetSystem + NULL, // UpdateCapsule + NULL, // QueryCapsuleCapabilities + NULL // QueryVariableInfo +}; + +/** + Unit test for ColdReset () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetColdShouldIssueAColdReset ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetCold); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetCold (); + + return UNIT_TEST_PASSED; +} + +/** + Unit test for WarmReset () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetWarmShouldIssueAWarmReset ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetWarm); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetWarm (); + + return UNIT_TEST_PASSED; +} + +/** + Unit test for ResetShutdown () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetShutdownShouldIssueAShutdown ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetShutdown); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetShutdown (); + + return UNIT_TEST_PASSED; +} + +/** + Unit test for ResetPlatformSpecific () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetPlatformSpecificShouldIssueAPlatformSpecificReset ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetPlatformSpecific); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetPlatformSpecific (0, NULL); + + return UNIT_TEST_PASSED; +} + +/** + Unit test for ResetSystem () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetSystemShouldPassTheParametersThrough ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetCold); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + + expect_value (MockResetSystem, ResetType, EfiResetShutdown); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); + + return UNIT_TEST_PASSED; +} + +/** + Initialze the unit test framework, suite, and unit tests for the + ResetSystemLib and run the ResetSystemLib unit test. + + @retval EFI_SUCCESS All test cases were dispached. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + initialize the unit tests. +**/ +STATIC +EFI_STATUS +EFIAPI +UnitTestingEntry ( + VOID + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework; + UNIT_TEST_SUITE_HANDLE ResetTests; + + Framework = NULL; + + DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION )); + + // + // Start setting up the test framework for running the tests. + // + Status = InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status)); + goto EXIT; + } + + // + // Populate the ResetSytemLib Unit Test Suite. + // + Status = CreateUnitTestSuite (&ResetTests, Framework, "DxeResetSystemLib Reset Tests", "ResetSystemLib.Reset", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ResetTests\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + // + // --------------Suite-----------Description--------------Name----------Function--------Pre---Post-------------------Context----------- + // + AddTestCase (ResetTests, "ResetCold should issue a cold reset", "Cold", ResetColdShouldIssueAColdReset, NULL, NULL, NULL); + AddTestCase (ResetTests, "ResetWarm should issue a warm reset", "Warm", ResetWarmShouldIssueAWarmReset, NULL, NULL, NULL); + AddTestCase (ResetTests, "ResetShutdown should issue a shutdown", "Shutdown", ResetShutdownShouldIssueAShutdown, NULL, NULL, NULL); + AddTestCase (ResetTests, "ResetPlatformSpecific should issue a platform-specific reset", "Platform", ResetPlatformSpecificShouldIssueAPlatformSpecificReset, NULL, NULL, NULL); + AddTestCase (ResetTests, "ResetSystem should pass all parameters through", "Parameters", ResetSystemShouldPassTheParametersThrough, NULL, NULL, NULL); + + // + // Execute the tests. + // + Status = RunAllTestSuites (Framework); + +EXIT: + if (Framework) { + FreeUnitTestFramework (Framework); + } + + return Status; +} + +/** + Standard POSIX C entry point for host based unit test execution. +**/ +int +main ( + int argc, + char *argv[] + ) +{ + return UnitTestingEntry (); +} diff --git a/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf new file mode 100644 index 00000000000..54f968e810f --- /dev/null +++ b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf @@ -0,0 +1,34 @@ +## @file +# Unit tests of the DxeResetSystemLib instance of the ResetSystemLib class +# +# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = DxeResetSystemLibUnitTestHost + FILE_GUID = 83E35653-B943-4C5F-BA08-9B2996AE9273 + MODULE_TYPE = HOST_APPLICATION + VERSION_STRING = 1.0 + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + DxeResetSystemLibUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + ResetSystemLib + BaseLib + BaseMemoryLib + DebugLib + UnitTestLib diff --git a/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.c b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.c new file mode 100644 index 00000000000..3540e1c039f --- /dev/null +++ b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.c @@ -0,0 +1,13 @@ +/** @file + Mock implementation of the UEFI Runtime Services Table Library. + + Copyright (C) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +extern EFI_RUNTIME_SERVICES MockRuntime; + +EFI_RUNTIME_SERVICES *gRT = &MockRuntime; diff --git a/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf new file mode 100644 index 00000000000..e716b855a31 --- /dev/null +++ b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf @@ -0,0 +1,25 @@ +## @file +# Mock implementation of the UEFI Runtime Services Table Library. +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MockUefiRuntimeServicesTableLib + FILE_GUID = 4EA215EE-85C1-4A0A-847F-D2A8DE20805F + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = UefiRuntimeServicesTableLib|HOST_APPLICATION + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + MockUefiRuntimeServicesTableLib.c + +[Packages] + MdePkg/MdePkg.dec diff --git a/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf b/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf index 42b741c64bc..4ed1d83a404 100644 --- a/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf +++ b/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf @@ -25,7 +25,7 @@ # # The following information is for reference only and not required by the build tools. # -# VALID_ARCHITECTURES = IA32 X64 EBC +# VALID_ARCHITECTURES = IA32 X64 AARCH64 ARM # [Sources] diff --git a/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h b/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h index cbdecd377bc..e1315b6ec33 100644 --- a/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h +++ b/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h @@ -18,11 +18,7 @@ #undef _WIN32 #endif -#ifndef _SIZE_T_DEFINED -#if !defined(_WIN64) || defined(__GNUC__) -typedef unsigned int size_t; -#endif -#endif +typedef UINTN size_t; #ifdef _WIN64 #undef _WIN64 diff --git a/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.c b/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.c index 50297129b7c..6c8c770ca37 100644 --- a/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.c +++ b/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.c @@ -57,19 +57,6 @@ ResetShutdown ( PeiServicesResetSystem2 (EfiResetShutdown, EFI_SUCCESS, 0, NULL); } -/** - This function causes the system to enter S3 and then wake up immediately. - - If this function returns, it means that the system does not support S3 feature. -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ) -{ -} - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c b/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c index 29b3f7ebd87..f4490180ccf 100644 --- a/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c +++ b/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c @@ -62,19 +62,6 @@ ResetShutdown ( mInternalRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); } -/** - This function causes the system to enter S3 and then wake up immediately. - - If this function returns, it means that the system does not support S3 feature. -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ) -{ -} - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c index 760d7647b8b..540d169ec1a 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c @@ -1,6 +1,7 @@ /** @file Library functions which relates with booting. +Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -1386,6 +1387,37 @@ BmExpandLoadFile ( // FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)); if (FileBuffer == NULL) { + DEBUG_CODE ( + EFI_DEVICE_PATH *LoadFilePath; + CHAR16 *LoadFileText; + CHAR16 *FileText; + + LoadFilePath = DevicePathFromHandle (LoadFileHandle); + if (LoadFilePath == NULL) { + LoadFileText = NULL; + } else { + LoadFileText = ConvertDevicePathToText (LoadFilePath, FALSE, FALSE); + } + FileText = ConvertDevicePathToText (FilePath, FALSE, FALSE); + + DEBUG (( + DEBUG_ERROR, + "%a:%a: failed to allocate reserved pages: " + "BufferSize=%Lu LoadFile=\"%s\" FilePath=\"%s\"\n", + gEfiCallerBaseName, + __FUNCTION__, + (UINT64)BufferSize, + LoadFileText, + FileText + )); + + if (FileText != NULL) { + FreePool (FileText); + } + if (LoadFileText != NULL) { + FreePool (LoadFileText); + } + ); return NULL; } @@ -2258,12 +2290,15 @@ EfiBootManagerRefreshAllBootOption ( VOID ) { - EFI_STATUS Status; - EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions; - UINTN NvBootOptionCount; - EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; - UINTN BootOptionCount; - UINTN Index; + EFI_STATUS Status; + EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions; + UINTN NvBootOptionCount; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN BootOptionCount; + EFI_BOOT_MANAGER_LOAD_OPTION *UpdatedBootOptions; + UINTN UpdatedBootOptionCount; + UINTN Index; + EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager; // // Optionally refresh the legacy boot option @@ -2273,7 +2308,6 @@ EfiBootManagerRefreshAllBootOption ( } BootOptions = BmEnumerateBootOptions (&BootOptionCount); - NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot); // // Mark the boot option as added by BDS by setting OptionalData to a special GUID @@ -2283,6 +2317,30 @@ EfiBootManagerRefreshAllBootOption ( BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID); } + // + // Locate Platform Boot Options Protocol + // + Status = gBS->LocateProtocol (&gEdkiiPlatformBootManagerProtocolGuid, + NULL, + (VOID **)&PlatformBootManager); + if (!EFI_ERROR (Status)) { + // + // If found, call platform specific refresh to all auto enumerated and NV + // boot options. + // + Status = PlatformBootManager->RefreshAllBootOptions ((CONST EFI_BOOT_MANAGER_LOAD_OPTION *)BootOptions, + (CONST UINTN)BootOptionCount, + &UpdatedBootOptions, + &UpdatedBootOptionCount); + if (!EFI_ERROR (Status)) { + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); + BootOptions = UpdatedBootOptions; + BootOptionCount = UpdatedBootOptionCount; + } + } + + NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot); + // // Remove invalid EFI boot options from NV // diff --git a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h index 027eb25ecf2..ac866ac25fd 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h +++ b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h @@ -1,6 +1,7 @@ /** @file BDS library definition, include the file and data structure +Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
(C) Copyright 2015 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -41,6 +42,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #include diff --git a/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf b/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf index ed6b4679eb7..cf5908692fa 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf +++ b/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf @@ -5,6 +5,7 @@ # manipulation, hotkey registration, UEFI boot, connect/disconnect, console # manipulation, driver health checking and etc. # +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
# SPDX-License-Identifier: BSD-2-Clause-Patent @@ -107,6 +108,7 @@ gEfiFormBrowser2ProtocolGuid ## SOMETIMES_CONSUMES gEfiRamDiskProtocolGuid ## SOMETIMES_CONSUMES gEfiDeferredImageLoadProtocolGuid ## SOMETIMES_CONSUMES + gEdkiiPlatformBootManagerProtocolGuid ## SOMETIMES_CONSUMES [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange ## SOMETIMES_CONSUMES diff --git a/MdeModulePkg/MdeModulePkg.ci.yaml b/MdeModulePkg/MdeModulePkg.ci.yaml new file mode 100644 index 00000000000..3b6e7470757 --- /dev/null +++ b/MdeModulePkg/MdeModulePkg.ci.yaml @@ -0,0 +1,91 @@ +## @file +# CI configuration for MdeModulePkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + ## options defined ci/Plugin/CompilerPlugin + "CompilerPlugin": { + "DscPath": "MdeModulePkg.dsc" + }, + ## options defined ci/Plugin/HostUnitTestCompilerPlugin + "HostUnitTestCompilerPlugin": { + "DscPath": "Test/MdeModulePkgHostTest.dsc" + }, + + ## options defined ci/Plugin/CharEncodingCheck + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + + ## options defined ci/Plugin/DependencyCheck + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "StandaloneMmPkg/StandaloneMmPkg.dec", + "ArmPkg/ArmPkg.dec" # this should be fixed by promoting an abstraction + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[ + "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec" + ], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + + ## options defined ci/Plugin/DscCompleteCheck + "DscCompleteCheck": { + "IgnoreInf": [], + "DscPath": "MdeModulePkg.dsc" + }, + ## options defined ci/Plugin/HostUnitTestDscCompleteCheck + "HostUnitTestDscCompleteCheck": { + "IgnoreInf": [""], + "DscPath": "Test/MdeModulePkgHostTest.dsc" + }, + + ## options defined ci/Plugin/GuidCheck + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": ["00000000-0000-0000-0000-000000000000"], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [ + "gEdkiiFormBrowserExProtocolGuid=gEfiFormBrowserExProtocolGuid", + "gEfiPeiMmAccessPpiGuid=gPeiSmmAccessPpiGuid", + "gPeiSmmControlPpiGuid=gEfiPeiMmControlPpiGuid", + ] + }, + + ## options defined ci/Plugin/LibraryClassCheck + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined ci/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log + "IgnoreStandardPaths": [ # Standard Plugin defined paths that should be ignore + "*.c", "*.asm", "*.h", "*.nasm", "*.s", "*.asl", "*.inf" + ], + "IgnoreFiles": [ # use gitignore syntax to ignore errors in matching files + "Library/LzmaCustomDecompressLib/Sdk/DOC/*" + ], + "ExtendWords": [ # words to extend to the dictionary for this package + "LIGHTGRAY", + "DARKGRAY", + "LIGHTBLUE", + "LIGHTGREEN", + "LIGHTCYAN", + "LIGHTRED", + "LIGHTMAGENTA", + "FVMAIN", + "VARCHECKPCD", + "Getxx", + "lzturbo" + ], + "AdditionalIncludePaths": [] # Additional paths to spell check relative to package root (wildcards supported) + } +} diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index d6bac974da9..e840cebe2ea 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -3,6 +3,7 @@ # It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes) # and libraries instances, which are used for those modules. # +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
# Copyright (c) 2016, Linaro Ltd. All rights reserved.
# (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP
@@ -584,6 +585,11 @@ ## Include/Protocol/IoMmu.h gEdkiiIoMmuProtocolGuid = { 0x4e939de9, 0xd948, 0x4b0f, { 0x88, 0xed, 0xe6, 0xe1, 0xce, 0x51, 0x7c, 0x1e } } + ## Include/Protocol/DeviceSecurity.h + gEdkiiDeviceSecurityProtocolGuid = { 0x5d6b38c8, 0x5510, 0x4458, { 0xb4, 0x8d, 0x95, 0x81, 0xcf, 0xa7, 0xb0, 0xd } } + gEdkiiDeviceIdentifierTypePciGuid = { 0x2509b2f1, 0xa022, 0x4cca, { 0xaf, 0x70, 0xf9, 0xd3, 0x21, 0xfb, 0x66, 0x49 } } + gEdkiiDeviceIdentifierTypeUsbGuid = { 0x7394f350, 0x394d, 0x488c, { 0xbb, 0x75, 0xc, 0xab, 0x7b, 0x12, 0xa, 0xc5 } } + ## Include/Protocol/SmmMemoryAttribute.h gEdkiiSmmMemoryAttributeProtocolGuid = { 0x69b792ea, 0x39ce, 0x402d, { 0xa2, 0xa6, 0xf7, 0x21, 0xde, 0x35, 0x1d, 0xfe } } @@ -604,6 +610,9 @@ ## Include/Protocol/PeCoffImageEmulator.h gEdkiiPeCoffImageEmulatorProtocolGuid = { 0x96f46153, 0x97a7, 0x4793, { 0xac, 0xc1, 0xfa, 0x19, 0xbf, 0x78, 0xea, 0x97 } } + ## Include/Protocol/PlatformBootManager.h + gEdkiiPlatformBootManagerProtocolGuid = { 0xaa17add4, 0x756c, 0x460d, { 0x94, 0xb8, 0x43, 0x88, 0xd7, 0xfb, 0x3e, 0x59 } } + # # [Error.gEfiMdeModulePkgTokenSpaceGuid] # 0x80000001 | Invalid value provided. @@ -641,6 +650,18 @@ # @Prompt Enable Device Path From Text support. gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFromText|TRUE|BOOLEAN|0x00010038 + ## Indicates if the UEFI variable runtime cache should be enabled. + # This setting only applies if SMM variables are enabled. When enabled, all variable + # data for Runtime Service GetVariable () and GetNextVariableName () calls is retrieved + # from a runtime data buffer referred to as the "runtime cache". An SMI is not triggered + # at all for these requests. Variables writes still trigger an SMI. This can greatly + # reduce overall system SMM usage as most boots tend to issue far more variable reads + # than writes.

+ # TRUE - The UEFI variable runtime cache is enabled.
+ # FALSE - The UEFI variable runtime cache is disabled.
+ # @Prompt Enable the UEFI variable runtime cache. + gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|TRUE|BOOLEAN|0x00010039 + ## Indicates if the statistics about variable usage will be collected. This information is # stored as a vendor configuration table into the EFI system table. # Set this PCD to TRUE to use VariableInfo application in MdeModulePkg\Application directory to get @@ -1986,6 +2007,14 @@ # @Prompt Capsule On Disk relocation device path. gEfiMdeModulePkgTokenSpaceGuid.PcdCodRelocationDevPath|{0xFF}|VOID*|0x0000002f + ## Indicates which TCG Platform Firmware Profile revision the EDKII firmware follows. + # The revision number is defined in MdePkg/Include/IndustryStandard/UefiTcgPlatform.h + # 0: This is for compatiblity support. + # 105: This is the first revision to support 800-155 is related event, such as + # EV_EFI_PLATFORM_FIRMWARE_BLOB2 and EV_EFI_HANDOFF_TABLES2. + # @Prompt TCG Platform Firmware Profile revision. + gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision|0|UINT32|0x00010077 + [PcdsPatchableInModule] ## Specify memory size with page number for PEI code when # Loading Module at Fixed Address feature is enabled. diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 4320839abfb..f7dbb27ce25 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -299,7 +299,6 @@ MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf - MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf MdeModulePkg/Library/PeiDebugLibDebugPpi/PeiDebugLibDebugPpi.inf MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf @@ -433,6 +432,7 @@ [Components.IA32, Components.X64, Components.ARM, Components.AARCH64] MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliCustomDecompressLib.inf + MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf MdeModulePkg/Core/Dxe/DxeMain.inf { diff --git a/MdeModulePkg/MdeModulePkg.uni b/MdeModulePkg/MdeModulePkg.uni index a2c7a7ded3e..d9c7b1ac6cf 100644 --- a/MdeModulePkg/MdeModulePkg.uni +++ b/MdeModulePkg/MdeModulePkg.uni @@ -660,6 +660,18 @@ "TRUE - Device Path From Text Protocol will be produced.
\n" "FALSE - Device Path From Text Protocol will not be produced.
" +#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEnableVariableRuntimeCache_PROMPT #language en-US "Enable the UEFI variable runtime cache." + +#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEnableVariableRuntimeCache_HELP #language en-US "Indicates if the UEFI variable runtime cache should be enabled.

\n" + "This setting only applies if SMM variables are enabled. When enabled, all variable
\n" + "data for Runtime Service GetVariable () and GetNextVariableName () calls is retrieved
\n" + "from a runtime data buffer referred to as the "runtime cache". An SMI is not triggered
\n" + "at all for these requests. Variables writes still trigger an SMI. This can greatly
\n" + "reduce overall system SMM usage as most boots tend to issue far more variable reads
\n" + "than writes.
\n" + "TRUE - The UEFI variable runtime cache is enabled.
\n" + "FALSE - The UEFI variable runtime cache is disabled.
" + #string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVariableCollectStatistics_PROMPT #language en-US "Enable variable statistics collection" #string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVariableCollectStatistics_HELP #language en-US "Indicates if the statistics about variable usage will be collected. This information is stored as a vendor configuration table into the EFI system table. Set this PCD to TRUE to use VariableInfo application in MdeModulePkg\Application directory to get variable usage info. VariableInfo application will not output information if not set to TRUE.

\n" diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc new file mode 100644 index 00000000000..72a119db456 --- /dev/null +++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc @@ -0,0 +1,32 @@ +## @file +# MdeModulePkg DSC file used to build host-based unit tests. +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME = MdeModulePkgHostTest + PLATFORM_GUID = F74AF7C6-698C-4EBA-BA49-FF6816916354 + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/MdeModulePkg/HostTest + SUPPORTED_ARCHITECTURES = IA32|X64 + BUILD_TARGETS = NOOPT + SKUID_IDENTIFIER = DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc + +[Components] + MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf + + # + # Build MdeModulePkg HOST_APPLICATION Tests + # + MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf { + + ResetSystemLib|MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf + UefiRuntimeServicesTableLib|MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf + } diff --git a/MdeModulePkg/Universal/BdsDxe/BdsEntry.c b/MdeModulePkg/Universal/BdsDxe/BdsEntry.c index d6ec31118c1..d387dbe7ac1 100644 --- a/MdeModulePkg/Universal/BdsDxe/BdsEntry.c +++ b/MdeModulePkg/Universal/BdsDxe/BdsEntry.c @@ -6,7 +6,7 @@ to enter BDS phase. Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
-(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+(C) Copyright 2016-2019 Hewlett Packard Enterprise Development LP
(C) Copyright 2015 Hewlett-Packard Development Company, L.P.
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -1069,7 +1069,7 @@ BdsEntry ( } if (!BootSuccess) { - if (PlatformRecovery) { + if (PcdGetBool (PcdPlatformRecoverySupport)) { LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery); ProcessLoadOptions (LoadOptions, LoadOptionCount); EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount); diff --git a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c index 8e305e4243a..7b453fa98c2 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c +++ b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c @@ -143,7 +143,7 @@ DebuggerDisplaySymbolAccrodingToAddress ( // Find the nearest symbol address // CandidateAddress = EbdFindSymbolAddress (Address, EdbMatchSymbolTypeNearestAddress, &Object, &Entry); - if (CandidateAddress == 0 || CandidateAddress == (UINTN) -1) { + if (CandidateAddress == 0 || CandidateAddress == (UINTN) -1 || Entry == NULL) { EDBPrint (L"Symbole at Address not found!\n"); return EFI_DEBUG_CONTINUE; } else if (Address != CandidateAddress) { diff --git a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c index 85cc275c114..90a9b9fbd7e 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c +++ b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c @@ -2062,7 +2062,7 @@ EdbPrintSource ( &RetObject, &RetEntry ); - if (SymbolAddress == 0) { + if (SymbolAddress == 0 || RetEntry == NULL) { return 0 ; } diff --git a/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.c b/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.c index f48125382db..fff17b98fa3 100644 --- a/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.c +++ b/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.c @@ -239,6 +239,11 @@ DeleteEsrtEntry( goto EXIT; } + if (EsrtRepository == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + if ((RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY)) != 0) { DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n")); // @@ -332,6 +337,11 @@ UpdateEsrtEntry( &RepositorySize ); + if (EsrtRepository == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + if (!EFI_ERROR(Status)) { // // if exist, update Esrt cache repository diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c index 71ea25bc19b..2cad6d29f45 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c @@ -909,6 +909,7 @@ CompareAndMergeDefaultString ( // To find the with AltConfigHdr in AltCfgResp, ignore other which follow it. // StringPtr = StrStr (*AltCfgResp, AltConfigHdr); + ASSERT (StringPtr != NULL); StringPtrNext = StrStr (StringPtr + 1, L"&GUID"); if (StringPtrNext != NULL) { TempCharA = *StringPtrNext; diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c b/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c index ca63df168c9..ee6c65287db 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c @@ -999,6 +999,7 @@ GetSystemFont ( } Info->ForegroundColor = mHiiEfiColors[Private->Attribute & 0x0f]; + ASSERT ((Private->Attribute >> 4) < 8); Info->BackgroundColor = mHiiEfiColors[Private->Attribute >> 4]; Info->FontInfoMask = EFI_FONT_INFO_SYS_FONT | EFI_FONT_INFO_SYS_SIZE | EFI_FONT_INFO_SYS_STYLE; Info->FontInfo.FontStyle = 0; diff --git a/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold1_key.c b/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold1_key.c index 7dbd6a5995b..0aa54ee172b 100644 --- a/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold1_key.c +++ b/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold1_key.c @@ -2983,17 +2983,13 @@ onigenc_unicode_fold1_key(OnigCodePoint codes[]) 4026 }; - if (0 == 0) - { - int key = hash(codes); - - if (key <= MAX_HASH_VALUE) - { - int index = wordlist[key]; - - if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds1 + index, 1) == 0) - return index; - } + int key = hash(codes); + if (key <= MAX_HASH_VALUE) { + int index = wordlist[key]; + if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds1 + index, 1) == 0) { + return index; + } } + return -1; } diff --git a/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold2_key.c b/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold2_key.c index 3d93e2417a2..44f8cb66007 100644 --- a/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold2_key.c +++ b/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold2_key.c @@ -211,17 +211,12 @@ onigenc_unicode_fold2_key(OnigCodePoint codes[]) 129 }; - if (0 == 0) - { - int key = hash(codes); - - if (key <= MAX_HASH_VALUE) - { - int index = wordlist[key]; - - if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds2 + index, 2) == 0) - return index; - } + int key = hash(codes); + if (key <= MAX_HASH_VALUE) { + int index = wordlist[key]; + if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds2 + index, 2) == 0) + return index; } + return -1; } diff --git a/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold3_key.c b/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold3_key.c index bdd5667c6ae..b36500b135e 100644 --- a/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold3_key.c +++ b/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_fold3_key.c @@ -121,17 +121,13 @@ onigenc_unicode_fold3_key(OnigCodePoint codes[]) 0 }; - if (0 == 0) - { - int key = hash(codes); - - if (key <= MAX_HASH_VALUE) - { - int index = wordlist[key]; - - if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds3 + index, 3) == 0) - return index; - } + int key = hash(codes); + if (key <= MAX_HASH_VALUE) { + int index = wordlist[key]; + if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds3 + index, 3) == 0) { + return index; + } } + return -1; } diff --git a/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_unfold_key.c b/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_unfold_key.c index 10f7889ea37..1f03b21cfe5 100644 --- a/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_unfold_key.c +++ b/MdeModulePkg/Universal/RegularExpressionDxe/Oniguruma/unicode_unfold_key.c @@ -3288,17 +3288,12 @@ onigenc_unicode_unfold_key(OnigCodePoint code) {0x1e907, 4005, 1} }; - if (0 == 0) - { - int key = hash(&code); - - if (key <= MAX_HASH_VALUE) - { - OnigCodePoint gcode = wordlist[key].code; - - if (code == gcode && wordlist[key].index >= 0) - return &wordlist[key]; - } + int key = hash(&code); + if (key <= MAX_HASH_VALUE) { + OnigCodePoint gcode = wordlist[key].code; + if (code == gcode && wordlist[key].index >= 0) { + return &wordlist[key]; + } } return 0; } diff --git a/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf b/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf index e9c885465d8..dd33205fceb 100644 --- a/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf +++ b/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf @@ -108,7 +108,7 @@ GCC:*_*_*_CC_FLAGS = -Wno-error=maybe-uninitialized # Oniguruma: implicit conversion from 'UINTN' (aka 'unsigned long long') to 'long' - GCC:*_CLANG9_*_CC_FLAGS = -Wno-error=constant-conversion + GCC:*_CLANGPDB_*_CC_FLAGS = -Wno-error=constant-conversion # Not add -Wno-error=maybe-uninitialized option for XCODE # XCODE doesn't know this option diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c index 7f4929c2fcd..d273d2aac3d 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c @@ -1281,7 +1281,10 @@ IfrToUint ( Result->Type = EFI_IFR_TYPE_UNDEFINED; return EFI_SUCCESS; } + + ASSERT (GetBufferForValue (&Value) != NULL); Result->Value.u64 = *(UINT64*) GetBufferForValue (&Value); + if (Value.Type == EFI_IFR_TYPE_BUFFER) { FreePool (Value.Buffer); } diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c index 891b95cf9fb..edb6a0fc4ce 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c @@ -1,15 +1,15 @@ /** @file Parser for IFR binary encoding. -Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Setup.h" -UINT16 mStatementIndex; -UINT16 mExpressionOpCodeIndex; +UINTN mStatementIndex; +UINTN mExpressionOpCodeIndex; EFI_QUESTION_ID mUsedQuestionId; extern LIST_ENTRY gBrowserStorageList; /** @@ -1106,12 +1106,12 @@ IsUnKnownOpCode ( VOID CountOpCodes ( IN FORM_BROWSER_FORMSET *FormSet, - IN OUT UINT16 *NumberOfStatement, - IN OUT UINT16 *NumberOfExpression + OUT UINTN *NumberOfStatement, + OUT UINTN *NumberOfExpression ) { - UINT16 StatementCount; - UINT16 ExpressionCount; + UINTN StatementCount; + UINTN ExpressionCount; UINT8 *OpCodeData; UINTN Offset; UINTN OpCodeLen; @@ -1169,8 +1169,8 @@ ParseOpCodes ( QUESTION_DEFAULT *CurrentDefault; QUESTION_OPTION *CurrentOption; UINT8 Width; - UINT16 NumberOfStatement; - UINT16 NumberOfExpression; + UINTN NumberOfStatement; + UINTN NumberOfExpression; EFI_IMAGE_ID *ImageId; BOOLEAN SuppressForQuestion; BOOLEAN SuppressForOption; diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c index 7b5d4731466..1050c9b17b8 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c @@ -1,7 +1,7 @@ /** @file This driver measures SMBIOS table to TPM. -Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -20,6 +20,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #define FIELD_SIZE_OF(TYPE, Field) ((UINTN)sizeof(((TYPE *)0)->Field)) @@ -108,6 +109,18 @@ SMBIOS_FILTER_STRUCT mSmbiosFilterStandardTableBlackList[] = { EFI_SMBIOS_PROTOCOL *mSmbios; UINTN mMaxLen; +#pragma pack (1) + +#define SMBIOS_HANDOFF_TABLE_DESC "SmbiosTable" +typedef struct { + UINT8 TableDescriptionSize; + UINT8 TableDescription[sizeof(SMBIOS_HANDOFF_TABLE_DESC)]; + UINT64 NumberOfTables; + EFI_CONFIGURATION_TABLE TableEntry[1]; +} SMBIOS_HANDOFF_TABLE_POINTERS2; + +#pragma pack () + /** This function dump raw data. @@ -460,6 +473,10 @@ MeasureSmbiosTable ( { EFI_STATUS Status; EFI_HANDOFF_TABLE_POINTERS HandoffTables; + SMBIOS_HANDOFF_TABLE_POINTERS2 SmbiosHandoffTables2; + UINT32 EventType; + VOID *EventLog; + UINT32 EventLogSize; SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios3Table; VOID *SmbiosTableAddress; @@ -569,16 +586,29 @@ MeasureSmbiosTable ( CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), &gEfiSmbiosTableGuid); HandoffTables.TableEntry[0].VendorTable = SmbiosTable; } + EventType = EV_EFI_HANDOFF_TABLES; + EventLog = &HandoffTables; + EventLogSize = sizeof (HandoffTables); + + if (PcdGet32(PcdTcgPfpMeasurementRevision) >= TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2_REV_105) { + SmbiosHandoffTables2.TableDescriptionSize = sizeof(SmbiosHandoffTables2.TableDescription); + CopyMem (SmbiosHandoffTables2.TableDescription, SMBIOS_HANDOFF_TABLE_DESC, sizeof(SmbiosHandoffTables2.TableDescription)); + SmbiosHandoffTables2.NumberOfTables = HandoffTables.NumberOfTables; + CopyMem (&(SmbiosHandoffTables2.TableEntry[0]), &(HandoffTables.TableEntry[0]), sizeof(SmbiosHandoffTables2.TableEntry[0])); + EventType = EV_EFI_HANDOFF_TABLES2; + EventLog = &SmbiosHandoffTables2; + EventLogSize = sizeof (SmbiosHandoffTables2); + } Status = TpmMeasureAndLogData ( 1, // PCRIndex - EV_EFI_HANDOFF_TABLES, // EventType - &HandoffTables, // EventLog - sizeof (HandoffTables), // LogLen + EventType, // EventType + EventLog, // EventLog + EventLogSize, // LogLen TableAddress, // HashData TableLength // HashDataLen ); - if (EFI_ERROR (Status)) { - return ; + if (!EFI_ERROR (Status)) { + gBS->CloseEvent (Event) ; } } diff --git a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf index a074044c848..7537bfb519a 100644 --- a/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf +++ b/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf @@ -11,7 +11,7 @@ # # A platform may use its own policy to filter some fields in SMBIOS table. # -# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -48,6 +48,7 @@ UefiLib UefiDriverEntryPoint DebugLib + PcdLib TpmMeasurementLib [Protocols] @@ -57,6 +58,9 @@ gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ## SystemTable gEfiSmbios3TableGuid ## SOMETIMES_CONSUMES ## SystemTable +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision ## CONSUMES + [Depex] gEfiSmbiosProtocolGuid diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Pei/Variable.c index 715802f33c2..f61465fc304 100644 --- a/MdeModulePkg/Universal/Variable/Pei/Variable.c +++ b/MdeModulePkg/Universal/Variable/Pei/Variable.c @@ -896,7 +896,7 @@ FindVariableEx ( // if ((IndexTable != NULL) && !StopRecord) { Offset = (UINTN) Variable - (UINTN) LastVariable; - if ((Offset > 0x0FFFF) || (IndexTable->Length == sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) { + if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) { // // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16), // or the record buffer is full. diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c index f32c9c2808a..d23aea4bc71 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -16,13 +16,16 @@ VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow, integer overflow. It should also check attribute to avoid authentication bypass. -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Variable.h" +#include "VariableNonVolatile.h" +#include "VariableParsing.h" +#include "VariableRuntimeCache.h" VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; @@ -92,131 +95,6 @@ AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = { AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut; -/** - Routine used to track statistical information about variable usage. - The data is stored in the EFI system table so it can be accessed later. - VariableInfo.efi can dump out the table. Only Boot Services variable - accesses are tracked by this code. The PcdVariableCollectStatistics - build flag controls if this feature is enabled. - - A read that hits in the cache will have Read and Cache true for - the transaction. Data is allocated by this routine, but never - freed. - - @param[in] VariableName Name of the Variable to track. - @param[in] VendorGuid Guid of the Variable to track. - @param[in] Volatile TRUE if volatile FALSE if non-volatile. - @param[in] Read TRUE if GetVariable() was called. - @param[in] Write TRUE if SetVariable() was called. - @param[in] Delete TRUE if deleted via SetVariable(). - @param[in] Cache TRUE for a cache hit. - -**/ -VOID -UpdateVariableInfo ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - IN BOOLEAN Volatile, - IN BOOLEAN Read, - IN BOOLEAN Write, - IN BOOLEAN Delete, - IN BOOLEAN Cache - ) -{ - VARIABLE_INFO_ENTRY *Entry; - - if (FeaturePcdGet (PcdVariableCollectStatistics)) { - - if (AtRuntime ()) { - // Don't collect statistics at runtime. - return; - } - - if (gVariableInfo == NULL) { - // - // On the first call allocate a entry and place a pointer to it in - // the EFI System Table. - // - gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); - ASSERT (gVariableInfo != NULL); - - CopyGuid (&gVariableInfo->VendorGuid, VendorGuid); - gVariableInfo->Name = AllocateZeroPool (StrSize (VariableName)); - ASSERT (gVariableInfo->Name != NULL); - StrCpyS (gVariableInfo->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName); - gVariableInfo->Volatile = Volatile; - } - - - for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) { - if (CompareGuid (VendorGuid, &Entry->VendorGuid)) { - if (StrCmp (VariableName, Entry->Name) == 0) { - if (Read) { - Entry->ReadCount++; - } - if (Write) { - Entry->WriteCount++; - } - if (Delete) { - Entry->DeleteCount++; - } - if (Cache) { - Entry->CacheCount++; - } - - return; - } - } - - if (Entry->Next == NULL) { - // - // If the entry is not in the table add it. - // Next iteration of the loop will fill in the data. - // - Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); - ASSERT (Entry->Next != NULL); - - CopyGuid (&Entry->Next->VendorGuid, VendorGuid); - Entry->Next->Name = AllocateZeroPool (StrSize (VariableName)); - ASSERT (Entry->Next->Name != NULL); - StrCpyS (Entry->Next->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName); - Entry->Next->Volatile = Volatile; - } - - } - } -} - - -/** - - This code checks if variable header is valid or not. - - @param Variable Pointer to the Variable Header. - @param VariableStoreEnd Pointer to the Variable Store End. - - @retval TRUE Variable header is valid. - @retval FALSE Variable header is not valid. - -**/ -BOOLEAN -IsValidVariableHeader ( - IN VARIABLE_HEADER *Variable, - IN VARIABLE_HEADER *VariableStoreEnd - ) -{ - if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) { - // - // Variable is NULL or has reached the end of variable store, - // or the StartId is not correct. - // - return FALSE; - } - - return TRUE; -} - - /** This function writes data to the FWH at the correct LBA even if the LBAs @@ -376,345 +254,6 @@ UpdateVariableStore ( return EFI_SUCCESS; } - -/** - - This code gets the current status of Variable Store. - - @param VarStoreHeader Pointer to the Variable Store Header. - - @retval EfiRaw Variable store status is raw. - @retval EfiValid Variable store status is valid. - @retval EfiInvalid Variable store status is invalid. - -**/ -VARIABLE_STORE_STATUS -GetVariableStoreStatus ( - IN VARIABLE_STORE_HEADER *VarStoreHeader - ) -{ - if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) || - CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) && - VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && - VarStoreHeader->State == VARIABLE_STORE_HEALTHY - ) { - - return EfiValid; - } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff && - ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff && - ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff && - ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff && - VarStoreHeader->Size == 0xffffffff && - VarStoreHeader->Format == 0xff && - VarStoreHeader->State == 0xff - ) { - - return EfiRaw; - } else { - return EfiInvalid; - } -} - -/** - This code gets the size of variable header. - - @return Size of variable header in bytes in type UINTN. - -**/ -UINTN -GetVariableHeaderSize ( - VOID - ) -{ - UINTN Value; - - if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { - Value = sizeof (AUTHENTICATED_VARIABLE_HEADER); - } else { - Value = sizeof (VARIABLE_HEADER); - } - - return Value; -} - -/** - - This code gets the size of name of variable. - - @param Variable Pointer to the Variable Header. - - @return UINTN Size of variable in bytes. - -**/ -UINTN -NameSizeOfVariable ( - IN VARIABLE_HEADER *Variable - ) -{ - AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; - if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { - if (AuthVariable->State == (UINT8) (-1) || - AuthVariable->DataSize == (UINT32) (-1) || - AuthVariable->NameSize == (UINT32) (-1) || - AuthVariable->Attributes == (UINT32) (-1)) { - return 0; - } - return (UINTN) AuthVariable->NameSize; - } else { - if (Variable->State == (UINT8) (-1) || - Variable->DataSize == (UINT32) (-1) || - Variable->NameSize == (UINT32) (-1) || - Variable->Attributes == (UINT32) (-1)) { - return 0; - } - return (UINTN) Variable->NameSize; - } -} - -/** - This code sets the size of name of variable. - - @param[in] Variable Pointer to the Variable Header. - @param[in] NameSize Name size to set. - -**/ -VOID -SetNameSizeOfVariable ( - IN VARIABLE_HEADER *Variable, - IN UINTN NameSize - ) -{ - AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; - if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { - AuthVariable->NameSize = (UINT32) NameSize; - } else { - Variable->NameSize = (UINT32) NameSize; - } -} - -/** - - This code gets the size of variable data. - - @param Variable Pointer to the Variable Header. - - @return Size of variable in bytes. - -**/ -UINTN -DataSizeOfVariable ( - IN VARIABLE_HEADER *Variable - ) -{ - AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; - if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { - if (AuthVariable->State == (UINT8) (-1) || - AuthVariable->DataSize == (UINT32) (-1) || - AuthVariable->NameSize == (UINT32) (-1) || - AuthVariable->Attributes == (UINT32) (-1)) { - return 0; - } - return (UINTN) AuthVariable->DataSize; - } else { - if (Variable->State == (UINT8) (-1) || - Variable->DataSize == (UINT32) (-1) || - Variable->NameSize == (UINT32) (-1) || - Variable->Attributes == (UINT32) (-1)) { - return 0; - } - return (UINTN) Variable->DataSize; - } -} - -/** - This code sets the size of variable data. - - @param[in] Variable Pointer to the Variable Header. - @param[in] DataSize Data size to set. - -**/ -VOID -SetDataSizeOfVariable ( - IN VARIABLE_HEADER *Variable, - IN UINTN DataSize - ) -{ - AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; - if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { - AuthVariable->DataSize = (UINT32) DataSize; - } else { - Variable->DataSize = (UINT32) DataSize; - } -} - -/** - - This code gets the pointer to the variable name. - - @param Variable Pointer to the Variable Header. - - @return Pointer to Variable Name which is Unicode encoding. - -**/ -CHAR16 * -GetVariableNamePtr ( - IN VARIABLE_HEADER *Variable - ) -{ - return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize ()); -} - -/** - This code gets the pointer to the variable guid. - - @param Variable Pointer to the Variable Header. - - @return A EFI_GUID* pointer to Vendor Guid. - -**/ -EFI_GUID * -GetVendorGuidPtr ( - IN VARIABLE_HEADER *Variable - ) -{ - AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; - if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { - return &AuthVariable->VendorGuid; - } else { - return &Variable->VendorGuid; - } -} - -/** - - This code gets the pointer to the variable data. - - @param Variable Pointer to the Variable Header. - - @return Pointer to Variable Data. - -**/ -UINT8 * -GetVariableDataPtr ( - IN VARIABLE_HEADER *Variable - ) -{ - UINTN Value; - - // - // Be careful about pad size for alignment. - // - Value = (UINTN) GetVariableNamePtr (Variable); - Value += NameSizeOfVariable (Variable); - Value += GET_PAD_SIZE (NameSizeOfVariable (Variable)); - - return (UINT8 *) Value; -} - -/** - This code gets the variable data offset related to variable header. - - @param Variable Pointer to the Variable Header. - - @return Variable Data offset. - -**/ -UINTN -GetVariableDataOffset ( - IN VARIABLE_HEADER *Variable - ) -{ - UINTN Value; - - // - // Be careful about pad size for alignment - // - Value = GetVariableHeaderSize (); - Value += NameSizeOfVariable (Variable); - Value += GET_PAD_SIZE (NameSizeOfVariable (Variable)); - - return Value; -} - -/** - - This code gets the pointer to the next variable header. - - @param Variable Pointer to the Variable Header. - - @return Pointer to next variable header. - -**/ -VARIABLE_HEADER * -GetNextVariablePtr ( - IN VARIABLE_HEADER *Variable - ) -{ - UINTN Value; - - Value = (UINTN) GetVariableDataPtr (Variable); - Value += DataSizeOfVariable (Variable); - Value += GET_PAD_SIZE (DataSizeOfVariable (Variable)); - - // - // Be careful about pad size for alignment. - // - return (VARIABLE_HEADER *) HEADER_ALIGN (Value); -} - -/** - - Gets the pointer to the first variable header in given variable store area. - - @param VarStoreHeader Pointer to the Variable Store Header. - - @return Pointer to the first variable header. - -**/ -VARIABLE_HEADER * -GetStartPointer ( - IN VARIABLE_STORE_HEADER *VarStoreHeader - ) -{ - // - // The start of variable store. - // - return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1); -} - -/** - - Gets the pointer to the end of the variable storage area. - - This function gets pointer to the end of the variable storage - area, according to the input variable store header. - - @param VarStoreHeader Pointer to the Variable Store Header. - - @return Pointer to the end of the variable storage area. - -**/ -VARIABLE_HEADER * -GetEndPointer ( - IN VARIABLE_STORE_HEADER *VarStoreHeader - ) -{ - // - // The end of variable store - // - return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size); -} - /** Record variable error flag. @@ -774,7 +313,7 @@ RecordVarErrorFlag ( FALSE ); if (!EFI_ERROR (Status)) { - VarErrFlag = (VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr); + VarErrFlag = (VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); TempFlag = *VarErrFlag; TempFlag &= Flag; if (TempFlag == *VarErrFlag) { @@ -794,6 +333,12 @@ RecordVarErrorFlag ( // Update the data in NV cache. // *VarErrFlag = TempFlag; + Status = SynchronizeRuntimeVariableCache ( + &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache, + 0, + mNvVariableCache->Size + ); + ASSERT_EFI_ERROR (Status); } } } @@ -832,7 +377,7 @@ InitializeVarErrorFlag ( FALSE ); if (!EFI_ERROR (Status)) { - VarErrFlag = *((VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr)); + VarErrFlag = *((VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat)); if (VarErrFlag == Flag) { return; } @@ -873,7 +418,11 @@ IsUserVariable ( // then no need to check if the variable is user variable or not specially. // if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) { - if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) { + if (VarCheckLibVariablePropertyGet ( + GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat), + GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat), + &Property + ) == EFI_NOT_FOUND) { return TRUE; } } @@ -902,10 +451,14 @@ CalculateCommonUserVariableTotalSize ( if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) { Variable = GetStartPointer (mNvVariableCache); while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) { - NextVariable = GetNextVariablePtr (Variable); + NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat); VariableSize = (UINTN) NextVariable - (UINTN) Variable; if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) { + if (VarCheckLibVariablePropertyGet ( + GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat), + GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat), + &Property + ) == EFI_NOT_FOUND) { // // No property, it is user variable. // @@ -981,7 +534,9 @@ Reclaim ( UINTN HwErrVariableTotalSize; VARIABLE_HEADER *UpdatingVariable; VARIABLE_HEADER *UpdatingInDeletedTransition; + BOOLEAN AuthFormat; + AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat; UpdatingVariable = NULL; UpdatingInDeletedTransition = NULL; if (UpdatingPtrTrack != NULL) { @@ -1003,7 +558,7 @@ Reclaim ( MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER); while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) { - NextVariable = GetNextVariablePtr (Variable); + NextVariable = GetNextVariablePtr (Variable, AuthFormat); if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) && Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition @@ -1053,7 +608,7 @@ Reclaim ( // Variable = GetStartPointer (VariableStoreHeader); while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) { - NextVariable = GetNextVariablePtr (Variable); + NextVariable = GetNextVariablePtr (Variable, AuthFormat); if (Variable != UpdatingVariable && Variable->State == VAR_ADDED) { VariableSize = (UINTN) NextVariable - (UINTN) Variable; CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); @@ -1075,7 +630,7 @@ Reclaim ( // Variable = GetStartPointer (VariableStoreHeader); while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) { - NextVariable = GetNextVariablePtr (Variable); + NextVariable = GetNextVariablePtr (Variable, AuthFormat); if (Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { // @@ -1087,13 +642,14 @@ Reclaim ( FoundAdded = FALSE; AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer); while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) ValidBuffer))) { - NextAddedVariable = GetNextVariablePtr (AddedVariable); - NameSize = NameSizeOfVariable (AddedVariable); - if (CompareGuid (GetVendorGuidPtr (AddedVariable), GetVendorGuidPtr (Variable)) && - NameSize == NameSizeOfVariable (Variable) - ) { - Point0 = (VOID *) GetVariableNamePtr (AddedVariable); - Point1 = (VOID *) GetVariableNamePtr (Variable); + NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat); + NameSize = NameSizeOfVariable (AddedVariable, AuthFormat); + if (CompareGuid ( + GetVendorGuidPtr (AddedVariable, AuthFormat), + GetVendorGuidPtr (Variable, AuthFormat) + ) && NameSize == NameSizeOfVariable (Variable, AuthFormat)) { + Point0 = (VOID *) GetVariableNamePtr (AddedVariable, AuthFormat); + Point1 = (VOID *) GetVariableNamePtr (Variable, AuthFormat); if (CompareMem (Point0, Point1, NameSize) == 0) { FoundAdded = TRUE; break; @@ -1198,7 +754,7 @@ Reclaim ( mVariableModuleGlobal->CommonUserVariableTotalSize = 0; Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase); while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) { - NextVariable = GetNextVariablePtr (Variable); + NextVariable = GetNextVariablePtr (Variable, AuthFormat); VariableSize = (UINTN) NextVariable - (UINTN) Variable; if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; @@ -1217,86 +773,29 @@ Reclaim ( Done: if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { + Status = SynchronizeRuntimeVariableCache ( + &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache, + 0, + VariableStoreHeader->Size + ); + ASSERT_EFI_ERROR (Status); FreePool (ValidBuffer); } else { // // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back. // - CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size); + CopyMem (mNvVariableCache, (UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size); + Status = SynchronizeRuntimeVariableCache ( + &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache, + 0, + VariableStoreHeader->Size + ); + ASSERT_EFI_ERROR (Status); } return Status; } -/** - Find the variable in the specified variable store. - - @param[in] VariableName Name of the variable to be found - @param[in] VendorGuid Vendor GUID to be found. - @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute - check at runtime when searching variable. - @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information. - - @retval EFI_SUCCESS Variable found successfully - @retval EFI_NOT_FOUND Variable not found -**/ -EFI_STATUS -FindVariableEx ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - IN BOOLEAN IgnoreRtCheck, - IN OUT VARIABLE_POINTER_TRACK *PtrTrack - ) -{ - VARIABLE_HEADER *InDeletedVariable; - VOID *Point; - - PtrTrack->InDeletedTransitionPtr = NULL; - - // - // Find the variable by walk through HOB, volatile and non-volatile variable store. - // - InDeletedVariable = NULL; - - for ( PtrTrack->CurrPtr = PtrTrack->StartPtr - ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr) - ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr) - ) { - if (PtrTrack->CurrPtr->State == VAR_ADDED || - PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) - ) { - if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { - if (VariableName[0] == 0) { - if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { - InDeletedVariable = PtrTrack->CurrPtr; - } else { - PtrTrack->InDeletedTransitionPtr = InDeletedVariable; - return EFI_SUCCESS; - } - } else { - if (CompareGuid (VendorGuid, GetVendorGuidPtr (PtrTrack->CurrPtr))) { - Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr); - - ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0); - if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr)) == 0) { - if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { - InDeletedVariable = PtrTrack->CurrPtr; - } else { - PtrTrack->InDeletedTransitionPtr = InDeletedVariable; - return EFI_SUCCESS; - } - } - } - } - } - } - } - - PtrTrack->CurrPtr = InDeletedVariable; - return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; -} - - /** Finds variable in storage blocks of volatile and non-volatile storage areas. @@ -1361,7 +860,13 @@ FindVariable ( PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]); PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile); - Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack); + Status = FindVariableEx ( + VariableName, + VendorGuid, + IgnoreRtCheck, + PtrTrack, + mVariableModuleGlobal->VariableGlobal.AuthFormat + ); if (!EFI_ERROR (Status)) { return Status; } @@ -1731,7 +1236,11 @@ CheckRemainingSpaceForConsistencyInternal ( VarNameSize += GET_PAD_SIZE (VarNameSize); VarDataSize = VariableEntry->VariableSize; VarDataSize += GET_PAD_SIZE (VarDataSize); - VariableEntry->VariableSize = HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize + VarDataSize); + VariableEntry->VariableSize = HEADER_ALIGN ( + GetVariableHeaderSize ( + mVariableModuleGlobal->VariableGlobal.AuthFormat + ) + VarNameSize + VarDataSize + ); TotalNeededSize += VariableEntry->VariableSize; VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); @@ -1764,13 +1273,14 @@ CheckRemainingSpaceForConsistencyInternal ( VariableEntry->Name, VariableEntry->Guid, FALSE, - &VariablePtrTrack + &VariablePtrTrack, + mVariableModuleGlobal->VariableGlobal.AuthFormat ); if (!EFI_ERROR (Status)) { // // Get size of Variable[Index]. // - NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr); + NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); OriginalVarSize = (UINTN) NextVariable - (UINTN) VariablePtrTrack.CurrPtr; // // Add the original size of Variable[Index] to remaining variable storage size. @@ -1942,8 +1452,8 @@ AutoUpdateLangVariable ( // Update Lang // VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME; - Data = GetVariableDataPtr (Variable.CurrPtr); - DataSize = DataSizeOfVariable (Variable.CurrPtr); + Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); + DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); } else { Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); if (!EFI_ERROR (Status)) { @@ -1951,8 +1461,8 @@ AutoUpdateLangVariable ( // Update PlatformLang // VariableName = EFI_LANG_VARIABLE_NAME; - Data = GetVariableDataPtr (Variable.CurrPtr); - DataSize = DataSizeOfVariable (Variable.CurrPtr); + Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); + DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); } else { // // Neither PlatformLang nor Lang is set, directly return @@ -2078,38 +1588,6 @@ AutoUpdateLangVariable ( } } -/** - Compare two EFI_TIME data. - - - @param FirstTime A pointer to the first EFI_TIME data. - @param SecondTime A pointer to the second EFI_TIME data. - - @retval TRUE The FirstTime is not later than the SecondTime. - @retval FALSE The FirstTime is later than the SecondTime. - -**/ -BOOLEAN -VariableCompareTimeStampInternal ( - IN EFI_TIME *FirstTime, - IN EFI_TIME *SecondTime - ) -{ - if (FirstTime->Year != SecondTime->Year) { - return (BOOLEAN) (FirstTime->Year < SecondTime->Year); - } else if (FirstTime->Month != SecondTime->Month) { - return (BOOLEAN) (FirstTime->Month < SecondTime->Month); - } else if (FirstTime->Day != SecondTime->Day) { - return (BOOLEAN) (FirstTime->Day < SecondTime->Day); - } else if (FirstTime->Hour != SecondTime->Hour) { - return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour); - } else if (FirstTime->Minute != SecondTime->Minute) { - return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute); - } - - return (BOOLEAN) (FirstTime->Second <= SecondTime->Second); -} - /** Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set, index of associated public key is needed. @@ -2155,6 +1633,7 @@ UpdateVariable ( VARIABLE_POINTER_TRACK *Variable; VARIABLE_POINTER_TRACK NvVariable; VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_RUNTIME_CACHE *VolatileCacheInstance; UINT8 *BufferForMerge; UINTN MergedBufSize; BOOLEAN DataReady; @@ -2162,6 +1641,7 @@ UpdateVariable ( BOOLEAN IsCommonVariable; BOOLEAN IsCommonUserVariable; AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + BOOLEAN AuthFormat; if (mVariableModuleGlobal->FvbInstance == NULL && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) { // @@ -2183,6 +1663,8 @@ UpdateVariable ( } } + AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat; + // // Check if CacheVariable points to the variable in variable HOB. // If yes, let CacheVariable points to the variable in NV variable cache. @@ -2194,7 +1676,7 @@ UpdateVariable ( CacheVariable->StartPtr = GetStartPointer (mNvVariableCache); CacheVariable->EndPtr = GetEndPointer (mNvVariableCache); CacheVariable->Volatile = FALSE; - Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable); + Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable, AuthFormat); if (CacheVariable->CurrPtr == NULL || EFI_ERROR (Status)) { // // There is no matched variable in NV variable cache. @@ -2205,7 +1687,7 @@ UpdateVariable ( // go to delete this variable in variable HOB and // try to flush other variables from HOB to flash. // - UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE); + UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE, &gVariableInfo); FlushHobVariableToFlash (VariableName, VendorGuid); return EFI_SUCCESS; } @@ -2322,7 +1804,7 @@ UpdateVariable ( &State ); if (!EFI_ERROR (Status)) { - UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE); + UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE, &gVariableInfo); if (!Variable->Volatile) { CacheVariable->CurrPtr->State = State; FlushHobVariableToFlash (VariableName, VendorGuid); @@ -2334,14 +1816,14 @@ UpdateVariable ( // If the variable is marked valid, and the same data has been passed in, // then return to the caller immediately. // - if (DataSizeOfVariable (CacheVariable->CurrPtr) == DataSize && - (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr), DataSize) == 0) && + if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) == DataSize && + (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, AuthFormat), DataSize) == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (TimeStamp == NULL)) { // // Variable content unchanged and no need to update timestamp, just return. // - UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE); + UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo); Status = EFI_SUCCESS; goto Done; } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) || @@ -2355,9 +1837,13 @@ UpdateVariable ( // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name. // From DataOffset of NextVariable is to save the existing variable data. // - DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr); + DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr, AuthFormat); BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset); - CopyMem (BufferForMerge, (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset), DataSizeOfVariable (CacheVariable->CurrPtr)); + CopyMem ( + BufferForMerge, + (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset), + DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + ); // // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize. @@ -2378,15 +1864,22 @@ UpdateVariable ( MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset; } - if (DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize > MaxDataSize) { + if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + DataSize > MaxDataSize) { // // Existing data size + new data size exceed maximum variable size limitation. // Status = EFI_INVALID_PARAMETER; goto Done; } - CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr)), Data, DataSize); - MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize; + CopyMem ( + (UINT8*) ( + (UINTN) BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + ), + Data, + DataSize + ); + MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + + DataSize; // // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data. @@ -2489,7 +1982,7 @@ UpdateVariable ( // NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE); - VarNameOffset = GetVariableHeaderSize (); + VarNameOffset = GetVariableHeaderSize (AuthFormat); VarNameSize = StrSize (VariableName); CopyMem ( (UINT8 *) ((UINTN) NextVariable + VarNameOffset), @@ -2510,14 +2003,18 @@ UpdateVariable ( ); } - CopyMem (GetVendorGuidPtr (NextVariable), VendorGuid, sizeof (EFI_GUID)); + CopyMem ( + GetVendorGuidPtr (NextVariable, AuthFormat), + VendorGuid, + sizeof (EFI_GUID) + ); // // There will be pad bytes after Data, the NextVariable->NameSize and // NextVariable->DataSize should not include pad size so that variable // service can get actual size in GetVariable. // - SetNameSizeOfVariable (NextVariable, VarNameSize); - SetDataSizeOfVariable (NextVariable, DataSize); + SetNameSizeOfVariable (NextVariable, VarNameSize, AuthFormat); + SetDataSizeOfVariable (NextVariable, DataSize, AuthFormat); // // The actual size of the variable that stores in storage should @@ -2570,7 +2067,7 @@ UpdateVariable ( CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr)); CacheVariable->InDeletedTransitionPtr = NULL; } - UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE); + UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo); FlushHobVariableToFlash (VariableName, VendorGuid); } else { if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) { @@ -2600,7 +2097,7 @@ UpdateVariable ( TRUE, Fvb, mVariableModuleGlobal->NonVolatileLastVariableOffset, - (UINT32) GetVariableHeaderSize (), + (UINT32) GetVariableHeaderSize (AuthFormat), (UINT8 *) NextVariable ); @@ -2633,9 +2130,9 @@ UpdateVariable ( FALSE, TRUE, Fvb, - mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (), - (UINT32) (VarSize - GetVariableHeaderSize ()), - (UINT8 *) NextVariable + GetVariableHeaderSize () + mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (AuthFormat), + (UINT32) (VarSize - GetVariableHeaderSize (AuthFormat)), + (UINT8 *) NextVariable + GetVariableHeaderSize (AuthFormat) ); if (EFI_ERROR (Status)) { @@ -2720,7 +2217,7 @@ UpdateVariable ( CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr)); CacheVariable->InDeletedTransitionPtr = NULL; } - UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE); + UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo); } goto Done; } @@ -2790,14 +2287,31 @@ UpdateVariable ( } } - if (!EFI_ERROR (Status)) { - UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE); - if (!Volatile) { - FlushHobVariableToFlash (VariableName, VendorGuid); + if (!EFI_ERROR (Status)) { + UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo); + if (!Volatile) { + FlushHobVariableToFlash (VariableName, VendorGuid); + } + } + +Done: + if (!EFI_ERROR (Status)) { + if ((Variable->CurrPtr != NULL && !Variable->Volatile) || (Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache); + } else { + VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache); + } + + if (VolatileCacheInstance->Store != NULL) { + Status = SynchronizeRuntimeVariableCache ( + VolatileCacheInstance, + 0, + VolatileCacheInstance->Store->Size + ); + ASSERT_EFI_ERROR (Status); } } -Done: return Status; } @@ -2855,7 +2369,7 @@ VariableServiceGetVariable ( // // Get data size // - VarDataSize = DataSizeOfVariable (Variable.CurrPtr); + VarDataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); ASSERT (VarDataSize != 0); if (*DataSize >= VarDataSize) { @@ -2864,13 +2378,13 @@ VariableServiceGetVariable ( goto Done; } - CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), VarDataSize); if (Attributes != NULL) { *Attributes = Variable.CurrPtr->Attributes; } *DataSize = VarDataSize; - UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE); + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE, &gVariableInfo); Status = EFI_SUCCESS; goto Done; @@ -2885,166 +2399,6 @@ VariableServiceGetVariable ( return Status; } -/** - This code Finds the Next available variable. - - Caution: This function may receive untrusted input. - This function may be invoked in SMM mode. This function will do basic validation, before parse the data. - - @param[in] VariableName Pointer to variable name. - @param[in] VendorGuid Variable Vendor Guid. - @param[out] VariablePtr Pointer to variable header address. - - @retval EFI_SUCCESS The function completed successfully. - @retval EFI_NOT_FOUND The next variable was not found. - @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL. - @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and - GUID of an existing variable. - -**/ -EFI_STATUS -EFIAPI -VariableServiceGetNextVariableInternal ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - OUT VARIABLE_HEADER **VariablePtr - ) -{ - VARIABLE_STORE_TYPE Type; - VARIABLE_POINTER_TRACK Variable; - VARIABLE_POINTER_TRACK VariableInHob; - VARIABLE_POINTER_TRACK VariablePtrTrack; - EFI_STATUS Status; - VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; - - Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); - if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { - // - // For VariableName is an empty string, FindVariable() will try to find and return - // the first qualified variable, and if FindVariable() returns error (EFI_NOT_FOUND) - // as no any variable is found, still go to return the error (EFI_NOT_FOUND). - // - if (VariableName[0] != 0) { - // - // For VariableName is not an empty string, and FindVariable() returns error as - // VariableName and VendorGuid are not a name and GUID of an existing variable, - // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER. - // - Status = EFI_INVALID_PARAMETER; - } - goto Done; - } - - if (VariableName[0] != 0) { - // - // If variable name is not NULL, get next variable. - // - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); - } - - // - // 0: Volatile, 1: HOB, 2: Non-Volatile. - // The index and attributes mapping must be kept in this order as FindVariable - // makes use of this mapping to implement search algorithm. - // - VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; - VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase; - VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache; - - while (TRUE) { - // - // Switch from Volatile to HOB, to Non-Volatile. - // - while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) { - // - // Find current storage index - // - for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) { - if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) { - break; - } - } - ASSERT (Type < VariableStoreTypeMax); - // - // Switch to next storage - // - for (Type++; Type < VariableStoreTypeMax; Type++) { - if (VariableStoreHeader[Type] != NULL) { - break; - } - } - // - // Capture the case that - // 1. current storage is the last one, or - // 2. no further storage - // - if (Type == VariableStoreTypeMax) { - Status = EFI_NOT_FOUND; - goto Done; - } - Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]); - Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]); - Variable.CurrPtr = Variable.StartPtr; - } - - // - // Variable is found - // - if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { - if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { - if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { - // - // If it is a IN_DELETED_TRANSITION variable, - // and there is also a same ADDED one at the same time, - // don't return it. - // - VariablePtrTrack.StartPtr = Variable.StartPtr; - VariablePtrTrack.EndPtr = Variable.EndPtr; - Status = FindVariableEx ( - GetVariableNamePtr (Variable.CurrPtr), - GetVendorGuidPtr (Variable.CurrPtr), - FALSE, - &VariablePtrTrack - ); - if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) { - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); - continue; - } - } - - // - // Don't return NV variable when HOB overrides it - // - if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) && - (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv])) - ) { - VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]); - VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]); - Status = FindVariableEx ( - GetVariableNamePtr (Variable.CurrPtr), - GetVendorGuidPtr (Variable.CurrPtr), - FALSE, - &VariableInHob - ); - if (!EFI_ERROR (Status)) { - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); - continue; - } - } - - *VariablePtr = Variable.CurrPtr; - Status = EFI_SUCCESS; - goto Done; - } - } - - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); - } - -Done: - return Status; -} - /** This code Finds the Next available variable. @@ -3081,12 +2435,16 @@ VariableServiceGetNextVariableName ( EFI_STATUS Status; UINTN MaxLen; UINTN VarNameSize; + BOOLEAN AuthFormat; VARIABLE_HEADER *VariablePtr; + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { return EFI_INVALID_PARAMETER; } + AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat; + // // Calculate the possible maximum length of name string, including the Null terminator. // @@ -3101,13 +2459,36 @@ VariableServiceGetNextVariableName ( AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); - Status = VariableServiceGetNextVariableInternal (VariableName, VendorGuid, &VariablePtr); + // + // 0: Volatile, 1: HOB, 2: Non-Volatile. + // The index and attributes mapping must be kept in this order as FindVariable + // makes use of this mapping to implement search algorithm. + // + VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; + VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase; + VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache; + + Status = VariableServiceGetNextVariableInternal ( + VariableName, + VendorGuid, + VariableStoreHeader, + &VariablePtr, + AuthFormat + ); if (!EFI_ERROR (Status)) { - VarNameSize = NameSizeOfVariable (VariablePtr); + VarNameSize = NameSizeOfVariable (VariablePtr, AuthFormat); ASSERT (VarNameSize != 0); if (VarNameSize <= *VariableNameSize) { - CopyMem (VariableName, GetVariableNamePtr (VariablePtr), VarNameSize); - CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr), sizeof (EFI_GUID)); + CopyMem ( + VariableName, + GetVariableNamePtr (VariablePtr, AuthFormat), + VarNameSize + ); + CopyMem ( + VendorGuid, + GetVendorGuidPtr (VariablePtr, AuthFormat), + sizeof (EFI_GUID) + ); Status = EFI_SUCCESS; } else { Status = EFI_BUFFER_TOO_SMALL; @@ -3160,6 +2541,9 @@ VariableServiceSetVariable ( VARIABLE_HEADER *NextVariable; EFI_PHYSICAL_ADDRESS Point; UINTN PayloadSize; + BOOLEAN AuthFormat; + + AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat; // // Check input parameters. @@ -3258,7 +2642,8 @@ VariableServiceSetVariable ( // bytes for HwErrRec#### variable. // if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ()) { + if (StrSize (VariableName) + PayloadSize > + PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize (AuthFormat)) { return EFI_INVALID_PARAMETER; } } else { @@ -3267,7 +2652,9 @@ VariableServiceSetVariable ( // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes. // if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { - if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ()) { + if (StrSize (VariableName) + PayloadSize > + mVariableModuleGlobal->MaxAuthVariableSize - + GetVariableHeaderSize (AuthFormat)) { DEBUG ((DEBUG_ERROR, "%a: Failed to set variable '%s' with Guid %g\n", __FUNCTION__, VariableName, VendorGuid)); @@ -3276,12 +2663,13 @@ VariableServiceSetVariable ( "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n", StrSize (VariableName), PayloadSize, mVariableModuleGlobal->MaxAuthVariableSize, - GetVariableHeaderSize () + GetVariableHeaderSize (AuthFormat) )); return EFI_INVALID_PARAMETER; } } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { - if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ()) { + if (StrSize (VariableName) + PayloadSize > + mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize (AuthFormat)) { DEBUG ((DEBUG_ERROR, "%a: Failed to set variable '%s' with Guid %g\n", __FUNCTION__, VariableName, VendorGuid)); @@ -3290,12 +2678,13 @@ VariableServiceSetVariable ( "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n", StrSize (VariableName), PayloadSize, mVariableModuleGlobal->MaxVariableSize, - GetVariableHeaderSize () + GetVariableHeaderSize (AuthFormat) )); return EFI_INVALID_PARAMETER; } } else { - if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ()) { + if (StrSize (VariableName) + PayloadSize > + mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize (AuthFormat)) { DEBUG ((DEBUG_ERROR, "%a: Failed to set variable '%s' with Guid %g\n", __FUNCTION__, VariableName, VendorGuid)); @@ -3304,7 +2693,7 @@ VariableServiceSetVariable ( "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n", StrSize (VariableName), PayloadSize, mVariableModuleGlobal->MaxVolatileVariableSize, - GetVariableHeaderSize () + GetVariableHeaderSize (AuthFormat) )); return EFI_INVALID_PARAMETER; } @@ -3343,7 +2732,7 @@ VariableServiceSetVariable ( // NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point); while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))) { - NextVariable = GetNextVariablePtr (NextVariable); + NextVariable = GetNextVariablePtr (NextVariable, AuthFormat); } mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point; } @@ -3468,7 +2857,8 @@ VariableServiceQueryVariableInfoInternal ( // if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize); - *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize (); + *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - + GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat); } else { if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { if (AtRuntime ()) { @@ -3482,11 +2872,14 @@ VariableServiceQueryVariableInfoInternal ( // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size. // if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) { - *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize (); + *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - + GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat); } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { - *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize (); + *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - + GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat); } else { - *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize (); + *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize - + GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat); } } @@ -3499,7 +2892,7 @@ VariableServiceQueryVariableInfoInternal ( // Now walk through the related variable store. // while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) { - NextVariable = GetNextVariablePtr (Variable); + NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat); VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable; if (AtRuntime ()) { @@ -3534,10 +2927,11 @@ VariableServiceQueryVariableInfoInternal ( VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader); VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader); Status = FindVariableEx ( - GetVariableNamePtr (Variable), - GetVendorGuidPtr (Variable), + GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat), + GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat), FALSE, - &VariablePtrTrack + &VariablePtrTrack, + mVariableModuleGlobal->VariableGlobal.AuthFormat ); if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State != VAR_ADDED) { if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { @@ -3565,10 +2959,13 @@ VariableServiceQueryVariableInfoInternal ( } } - if (*RemainingVariableStorageSize < GetVariableHeaderSize ()) { + if (*RemainingVariableStorageSize < GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) { *MaximumVariableSize = 0; - } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize ()) < *MaximumVariableSize) { - *MaximumVariableSize = *RemainingVariableStorageSize - GetVariableHeaderSize (); + } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) < + *MaximumVariableSize + ) { + *MaximumVariableSize = *RemainingVariableStorageSize - + GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat); } return EFI_SUCCESS; @@ -3720,25 +3117,6 @@ ReclaimForOS( } } -/** - Get non-volatile maximum variable size. - - @return Non-volatile maximum variable size. - -**/ -UINTN -GetNonVolatileMaxVariableSize ( - VOID - ) -{ - if (PcdGet32 (PcdHwErrStorageSize) != 0) { - return MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)), - PcdGet32 (PcdMaxHardwareErrorVariableSize)); - } else { - return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)); - } -} - /** Get maximum variable size, covering both non-volatile and volatile variables. @@ -3763,303 +3141,6 @@ GetMaxVariableSize ( return MaxVariableSize; } -/** - Init real non-volatile variable store. - - @param[out] VariableStoreBase Output pointer to real non-volatile variable store base. - - @retval EFI_SUCCESS Function successfully executed. - @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. - @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted. - -**/ -EFI_STATUS -InitRealNonVolatileVariableStore ( - OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase - ) -{ - EFI_FIRMWARE_VOLUME_HEADER *FvHeader; - VARIABLE_STORE_HEADER *VariableStore; - UINT32 VariableStoreLength; - EFI_HOB_GUID_TYPE *GuidHob; - EFI_PHYSICAL_ADDRESS NvStorageBase; - UINT8 *NvStorageData; - UINT32 NvStorageSize; - FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; - UINT32 BackUpOffset; - UINT32 BackUpSize; - UINT32 HwErrStorageSize; - UINT32 MaxUserNvVariableSpaceSize; - UINT32 BoottimeReservedNvVariableSpaceSize; - EFI_STATUS Status; - VOID *FtwProtocol; - - mVariableModuleGlobal->FvbInstance = NULL; - - // - // Allocate runtime memory used for a memory copy of the FLASH region. - // Keep the memory and the FLASH in sync as updates occur. - // - NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize); - NvStorageData = AllocateRuntimeZeroPool (NvStorageSize); - if (NvStorageData == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - NvStorageBase = NV_STORAGE_VARIABLE_BASE; - ASSERT (NvStorageBase != 0); - - // - // Copy NV storage data to the memory buffer. - // - CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize); - - Status = GetFtwProtocol ((VOID **)&FtwProtocol); - // - // If FTW protocol has been installed, no need to check FTW last write data hob. - // - if (EFI_ERROR (Status)) { - // - // Check the FTW last write data hob. - // - GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid); - if (GuidHob != NULL) { - FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob); - if (FtwLastWriteData->TargetAddress == NvStorageBase) { - DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress)); - // - // Copy the backed up NV storage data to the memory buffer from spare block. - // - CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize); - } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && - (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) { - // - // Flash NV storage from the Offset is backed up in spare block. - // - BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase); - BackUpSize = NvStorageSize - BackUpOffset; - DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress)); - // - // Copy the partial backed up NV storage data to the memory buffer from spare block. - // - CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize); - } - } - } - - FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData; - - // - // Check if the Firmware Volume is not corrupted - // - if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) { - FreePool (NvStorageData); - DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n")); - return EFI_VOLUME_CORRUPTED; - } - - VariableStore = (VARIABLE_STORE_HEADER *) ((UINTN) FvHeader + FvHeader->HeaderLength); - VariableStoreLength = NvStorageSize - FvHeader->HeaderLength; - ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength); - ASSERT (VariableStore->Size == VariableStoreLength); - - // - // Check if the Variable Store header is not corrupted - // - if (GetVariableStoreStatus (VariableStore) != EfiValid) { - FreePool (NvStorageData); - DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n")); - return EFI_VOLUME_CORRUPTED; - } - - mNvFvHeaderCache = FvHeader; - - *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore; - - HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize); - MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize); - BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize); - - // - // Note that in EdkII variable driver implementation, Hardware Error Record type variable - // is stored with common variable in the same NV region. So the platform integrator should - // ensure that the value of PcdHwErrStorageSize is less than the value of - // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). - // - ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))); - // - // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of - // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize). - // - ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize)); - // - // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of - // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize). - // - ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize)); - - mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize); - mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace); - mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize; - - DEBUG ((EFI_D_INFO, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonRuntimeVariableSpace)); - - // - // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). - // - ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))); - - return EFI_SUCCESS; -} - -/** - Init emulated non-volatile variable store. - - @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base. - - @retval EFI_SUCCESS Function successfully executed. - @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. - -**/ -EFI_STATUS -InitEmuNonVolatileVariableStore ( - EFI_PHYSICAL_ADDRESS *VariableStoreBase - ) -{ - VARIABLE_STORE_HEADER *VariableStore; - UINT32 VariableStoreLength; - BOOLEAN FullyInitializeStore; - UINT32 HwErrStorageSize; - - FullyInitializeStore = TRUE; - - VariableStoreLength = PcdGet32 (PcdVariableStoreSize); - ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength); - - // - // Allocate memory for variable store. - // - if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) { - VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength); - if (VariableStore == NULL) { - return EFI_OUT_OF_RESOURCES; - } - } else { - // - // A memory location has been reserved for the NV variable store. Certain - // platforms may be able to preserve a memory range across system resets, - // thereby providing better NV variable emulation. - // - VariableStore = - (VARIABLE_STORE_HEADER *)(VOID*)(UINTN) - PcdGet64 (PcdEmuVariableNvStoreReserved); - if ((VariableStore->Size == VariableStoreLength) && - (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) || - CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) && - (VariableStore->Format == VARIABLE_STORE_FORMATTED) && - (VariableStore->State == VARIABLE_STORE_HEALTHY)) { - DEBUG(( - DEBUG_INFO, - "Variable Store reserved at %p appears to be valid\n", - VariableStore - )); - FullyInitializeStore = FALSE; - } - } - - if (FullyInitializeStore) { - SetMem (VariableStore, VariableStoreLength, 0xff); - // - // Use gEfiAuthenticatedVariableGuid for potential auth variable support. - // - CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid); - VariableStore->Size = VariableStoreLength; - VariableStore->Format = VARIABLE_STORE_FORMATTED; - VariableStore->State = VARIABLE_STORE_HEALTHY; - VariableStore->Reserved = 0; - VariableStore->Reserved1 = 0; - } - - *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore; - - HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize); - - // - // Note that in EdkII variable driver implementation, Hardware Error Record type variable - // is stored with common variable in the same NV region. So the platform integrator should - // ensure that the value of PcdHwErrStorageSize is less than the value of - // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). - // - ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))); - - mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize); - mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace; - mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace; - - return EFI_SUCCESS; -} - -/** - Init non-volatile variable store. - - @retval EFI_SUCCESS Function successfully executed. - @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. - @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted. - -**/ -EFI_STATUS -InitNonVolatileVariableStore ( - VOID - ) -{ - VARIABLE_HEADER *Variable; - VARIABLE_HEADER *NextVariable; - EFI_PHYSICAL_ADDRESS VariableStoreBase; - UINTN VariableSize; - EFI_STATUS Status; - - if (PcdGetBool (PcdEmuVariableNvModeEnable)) { - Status = InitEmuNonVolatileVariableStore (&VariableStoreBase); - if (EFI_ERROR (Status)) { - return Status; - } - mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE; - DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n")); - } else { - Status = InitRealNonVolatileVariableStore (&VariableStoreBase); - if (EFI_ERROR (Status)) { - return Status; - } - mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE; - } - - mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; - mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase; - mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid)); - - mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize); - mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize); - - // - // Parse non-volatile variable data and get last variable offset. - // - Variable = GetStartPointer (mNvVariableCache); - while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) { - NextVariable = GetNextVariablePtr (Variable); - VariableSize = (UINTN) NextVariable - (UINTN) Variable; - if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; - } else { - mVariableModuleGlobal->CommonVariableTotalSize += VariableSize; - } - - Variable = NextVariable; - } - mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) mNvVariableCache; - - return EFI_SUCCESS; -} - /** Flush the HOB variable to flash. @@ -4079,8 +3160,10 @@ FlushHobVariableToFlash ( VOID *VariableData; VARIABLE_POINTER_TRACK VariablePtrTrack; BOOLEAN ErrorFlag; + BOOLEAN AuthFormat; ErrorFlag = FALSE; + AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat; // // Flush the HOB variable to flash. @@ -4093,7 +3176,7 @@ FlushHobVariableToFlash ( mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0; for ( Variable = GetStartPointer (VariableStoreHeader) ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader)) - ; Variable = GetNextVariablePtr (Variable) + ; Variable = GetNextVariablePtr (Variable, AuthFormat) ) { if (Variable->State != VAR_ADDED) { // @@ -4103,22 +3186,33 @@ FlushHobVariableToFlash ( } ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0); if (VendorGuid == NULL || VariableName == NULL || - !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable)) || - StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) { - VariableData = GetVariableDataPtr (Variable); - FindVariable (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &VariablePtrTrack, &mVariableModuleGlobal->VariableGlobal, FALSE); + !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable, AuthFormat)) || + StrCmp (VariableName, GetVariableNamePtr (Variable, AuthFormat)) != 0) { + VariableData = GetVariableDataPtr (Variable, AuthFormat); + FindVariable ( + GetVariableNamePtr (Variable, AuthFormat), + GetVendorGuidPtr (Variable, AuthFormat), + &VariablePtrTrack, + &mVariableModuleGlobal->VariableGlobal, FALSE + ); Status = UpdateVariable ( - GetVariableNamePtr (Variable), - GetVendorGuidPtr (Variable), + GetVariableNamePtr (Variable, AuthFormat), + GetVendorGuidPtr (Variable, AuthFormat), VariableData, - DataSizeOfVariable (Variable), + DataSizeOfVariable (Variable, AuthFormat), Variable->Attributes, 0, 0, &VariablePtrTrack, NULL ); - DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable), Status)); + DEBUG (( + DEBUG_INFO, + "Variable driver flush the HOB variable to flash: %g %s %r\n", + GetVendorGuidPtr (Variable, AuthFormat), + GetVariableNamePtr (Variable, AuthFormat), + Status + )); } else { // // The updated or deleted variable is matched with this HOB variable. @@ -4132,12 +3226,25 @@ FlushHobVariableToFlash ( // If set variable successful, or the updated or deleted variable is matched with the HOB variable, // set the HOB variable to DELETED state in local. // - DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable))); + DEBUG (( + DEBUG_INFO, + "Variable driver set the HOB variable to DELETED state in local: %g %s\n", + GetVendorGuidPtr (Variable, AuthFormat), + GetVariableNamePtr (Variable, AuthFormat) + )); Variable->State &= VAR_DELETED; } else { ErrorFlag = TRUE; } } + if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store != NULL) { + Status = SynchronizeRuntimeVariableCache ( + &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache, + 0, + mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store->Size + ); + ASSERT_EFI_ERROR (Status); + } if (ErrorFlag) { // // We still have HOB variable(s) not flushed in flash. @@ -4148,6 +3255,9 @@ FlushHobVariableToFlash ( // All HOB variables have been flushed in flash. // DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n")); + if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete != NULL) { + *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete) = TRUE; + } if (!AtRuntime ()) { FreePool ((VOID *) VariableStoreHeader); } @@ -4209,7 +3319,8 @@ VariableWriteServiceInitialize ( // Authenticated variable initialize. // mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN); - mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize (); + mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - + GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat); Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut); if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable support!\n")); @@ -4288,7 +3399,7 @@ ConvertNormalVarStorageToAuthVarStorage ( AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize); AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize); } - StartPtr = GetNextVariablePtr (StartPtr); + StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); } // @@ -4322,18 +3433,22 @@ ConvertNormalVarStorageToAuthVarStorage ( // Copy Variable Name // NextPtr = (UINT8 *) (AuthStartPtr + 1); - CopyMem (NextPtr, GetVariableNamePtr (StartPtr), AuthStartPtr->NameSize); + CopyMem ( + NextPtr, + GetVariableNamePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), + AuthStartPtr->NameSize + ); // // Copy Variable Data // NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize); - CopyMem (NextPtr, GetVariableDataPtr (StartPtr), AuthStartPtr->DataSize); + CopyMem (NextPtr, GetVariableDataPtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), AuthStartPtr->DataSize); // // Go to next variable // AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) (NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize)); } - StartPtr = GetNextVariablePtr (StartPtr); + StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); } // // Update Auth Storage Header diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h index 9eac43759fd..0b2bb6ae664 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h @@ -64,6 +64,21 @@ typedef enum { VariableStoreTypeMax } VARIABLE_STORE_TYPE; +typedef struct { + UINT32 PendingUpdateOffset; + UINT32 PendingUpdateLength; + VARIABLE_STORE_HEADER *Store; +} VARIABLE_RUNTIME_CACHE; + +typedef struct { + BOOLEAN *ReadLock; + BOOLEAN *PendingUpdate; + BOOLEAN *HobFlushComplete; + VARIABLE_RUNTIME_CACHE VariableRuntimeHobCache; + VARIABLE_RUNTIME_CACHE VariableRuntimeNvCache; + VARIABLE_RUNTIME_CACHE VariableRuntimeVolatileCache; +} VARIABLE_RUNTIME_CACHE_CONTEXT; + typedef struct { VARIABLE_HEADER *CurrPtr; // @@ -79,14 +94,15 @@ typedef struct { } VARIABLE_POINTER_TRACK; typedef struct { - EFI_PHYSICAL_ADDRESS HobVariableBase; - EFI_PHYSICAL_ADDRESS VolatileVariableBase; - EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; - EFI_LOCK VariableServicesLock; - UINT32 ReentrantState; - BOOLEAN AuthFormat; - BOOLEAN AuthSupport; - BOOLEAN EmuNvMode; + EFI_PHYSICAL_ADDRESS HobVariableBase; + EFI_PHYSICAL_ADDRESS VolatileVariableBase; + EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; + VARIABLE_RUNTIME_CACHE_CONTEXT VariableRuntimeCacheContext; + EFI_LOCK VariableServicesLock; + UINT32 ReentrantState; + BOOLEAN AuthFormat; + BOOLEAN AuthSupport; + BOOLEAN EmuNvMode; } VARIABLE_GLOBAL; typedef struct { @@ -179,89 +195,6 @@ FindVariable ( IN BOOLEAN IgnoreRtCheck ); -/** - - Gets the pointer to the end of the variable storage area. - - This function gets pointer to the end of the variable storage - area, according to the input variable store header. - - @param VarStoreHeader Pointer to the Variable Store Header. - - @return Pointer to the end of the variable storage area. - -**/ -VARIABLE_HEADER * -GetEndPointer ( - IN VARIABLE_STORE_HEADER *VarStoreHeader - ); - -/** - This code gets the size of variable header. - - @return Size of variable header in bytes in type UINTN. - -**/ -UINTN -GetVariableHeaderSize ( - VOID - ); - -/** - - This code gets the pointer to the variable name. - - @param Variable Pointer to the Variable Header. - - @return Pointer to Variable Name which is Unicode encoding. - -**/ -CHAR16 * -GetVariableNamePtr ( - IN VARIABLE_HEADER *Variable - ); - -/** - This code gets the pointer to the variable guid. - - @param Variable Pointer to the Variable Header. - - @return A EFI_GUID* pointer to Vendor Guid. - -**/ -EFI_GUID * -GetVendorGuidPtr ( - IN VARIABLE_HEADER *Variable - ); - -/** - - This code gets the pointer to the variable data. - - @param Variable Pointer to the Variable Header. - - @return Pointer to Variable Data. - -**/ -UINT8 * -GetVariableDataPtr ( - IN VARIABLE_HEADER *Variable - ); - -/** - - This code gets the size of variable data. - - @param Variable Pointer to the Variable Header. - - @return Size of variable in bytes. - -**/ -UINTN -DataSizeOfVariable ( - IN VARIABLE_HEADER *Variable - ); - /** This function is to check if the remaining variable space is enough to set all Variables from argument list successfully. The purpose of the check @@ -450,17 +383,6 @@ ReclaimForOS( VOID ); -/** - Get non-volatile maximum variable size. - - @return Non-volatile maximum variable size. - -**/ -UINTN -GetNonVolatileMaxVariableSize ( - VOID - ); - /** Get maximum variable size, covering both non-volatile and volatile variables. @@ -546,31 +468,6 @@ VariableServiceGetVariable ( OUT VOID *Data OPTIONAL ); -/** - This code Finds the Next available variable. - - Caution: This function may receive untrusted input. - This function may be invoked in SMM mode. This function will do basic validation, before parse the data. - - @param[in] VariableName Pointer to variable name. - @param[in] VendorGuid Variable Vendor Guid. - @param[out] VariablePtr Pointer to variable header address. - - @retval EFI_SUCCESS The function completed successfully. - @retval EFI_NOT_FOUND The next variable was not found. - @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL. - @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and - GUID of an existing variable. - -**/ -EFI_STATUS -EFIAPI -VariableServiceGetNextVariableInternal ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - OUT VARIABLE_HEADER **VariablePtr - ); - /** This code Finds the Next available variable. diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c index cb6fcebe2d9..e865a089d17 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c @@ -1,12 +1,13 @@ /** @file Provides variable driver extended services. -Copyright (c) 2015, Intel Corporation. All rights reserved.
+Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Variable.h" +#include "VariableParsing.h" /** Finds variable in storage blocks of volatile and non-volatile storage areas. @@ -55,8 +56,8 @@ VariableExLibFindVariable ( return Status; } - AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr); - AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr); + AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); + AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes; if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable.CurrPtr; @@ -97,11 +98,18 @@ VariableExLibFindNextVariable ( EFI_STATUS Status; VARIABLE_HEADER *VariablePtr; AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr; + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; + + VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; + VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase; + VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache; Status = VariableServiceGetNextVariableInternal ( VariableName, VendorGuid, - &VariablePtr + VariableStoreHeader, + &VariablePtr, + mVariableModuleGlobal->VariableGlobal.AuthFormat ); if (EFI_ERROR (Status)) { AuthVariableInfo->VariableName = NULL; @@ -115,10 +123,10 @@ VariableExLibFindNextVariable ( return Status; } - AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr); - AuthVariableInfo->VendorGuid = GetVendorGuidPtr (VariablePtr); - AuthVariableInfo->DataSize = DataSizeOfVariable (VariablePtr); - AuthVariableInfo->Data = GetVariableDataPtr (VariablePtr); + AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); + AuthVariableInfo->VendorGuid = GetVendorGuidPtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); + AuthVariableInfo->DataSize = DataSizeOfVariable (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); + AuthVariableInfo->Data = GetVariableDataPtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat); AuthVariableInfo->Attributes = VariablePtr->Attributes; if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *) VariablePtr; diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c new file mode 100644 index 00000000000..0637a828b33 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c @@ -0,0 +1,334 @@ +/** @file + Common variable non-volatile store routines. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "VariableNonVolatile.h" +#include "VariableParsing.h" + +extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; + +/** + Get non-volatile maximum variable size. + + @return Non-volatile maximum variable size. + +**/ +UINTN +GetNonVolatileMaxVariableSize ( + VOID + ) +{ + if (PcdGet32 (PcdHwErrStorageSize) != 0) { + return MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)), + PcdGet32 (PcdMaxHardwareErrorVariableSize)); + } else { + return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)); + } +} + +/** + Init emulated non-volatile variable store. + + @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + +**/ +EFI_STATUS +InitEmuNonVolatileVariableStore ( + OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase + ) +{ + VARIABLE_STORE_HEADER *VariableStore; + UINT32 VariableStoreLength; + BOOLEAN FullyInitializeStore; + UINT32 HwErrStorageSize; + + FullyInitializeStore = TRUE; + + VariableStoreLength = PcdGet32 (PcdVariableStoreSize); + ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength); + + // + // Allocate memory for variable store. + // + if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) { + VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength); + if (VariableStore == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // A memory location has been reserved for the NV variable store. Certain + // platforms may be able to preserve a memory range across system resets, + // thereby providing better NV variable emulation. + // + VariableStore = + (VARIABLE_STORE_HEADER *)(VOID*)(UINTN) + PcdGet64 (PcdEmuVariableNvStoreReserved); + if ((VariableStore->Size == VariableStoreLength) && + (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) || + CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) && + (VariableStore->Format == VARIABLE_STORE_FORMATTED) && + (VariableStore->State == VARIABLE_STORE_HEALTHY)) { + DEBUG(( + DEBUG_INFO, + "Variable Store reserved at %p appears to be valid\n", + VariableStore + )); + FullyInitializeStore = FALSE; + } + } + + if (FullyInitializeStore) { + SetMem (VariableStore, VariableStoreLength, 0xff); + // + // Use gEfiAuthenticatedVariableGuid for potential auth variable support. + // + CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid); + VariableStore->Size = VariableStoreLength; + VariableStore->Format = VARIABLE_STORE_FORMATTED; + VariableStore->State = VARIABLE_STORE_HEALTHY; + VariableStore->Reserved = 0; + VariableStore->Reserved1 = 0; + } + + *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore; + + HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize); + + // + // Note that in EdkII variable driver implementation, Hardware Error Record type variable + // is stored with common variable in the same NV region. So the platform integrator should + // ensure that the value of PcdHwErrStorageSize is less than the value of + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). + // + ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))); + + mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize); + mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace; + mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace; + + return EFI_SUCCESS; +} + +/** + Init real non-volatile variable store. + + @param[out] VariableStoreBase Output pointer to real non-volatile variable store base. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted. + +**/ +EFI_STATUS +InitRealNonVolatileVariableStore ( + OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + VARIABLE_STORE_HEADER *VariableStore; + UINT32 VariableStoreLength; + EFI_HOB_GUID_TYPE *GuidHob; + EFI_PHYSICAL_ADDRESS NvStorageBase; + UINT8 *NvStorageData; + UINT32 NvStorageSize; + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; + UINT32 BackUpOffset; + UINT32 BackUpSize; + UINT32 HwErrStorageSize; + UINT32 MaxUserNvVariableSpaceSize; + UINT32 BoottimeReservedNvVariableSpaceSize; + EFI_STATUS Status; + VOID *FtwProtocol; + + mVariableModuleGlobal->FvbInstance = NULL; + + // + // Allocate runtime memory used for a memory copy of the FLASH region. + // Keep the memory and the FLASH in sync as updates occur. + // + NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize); + NvStorageData = AllocateRuntimeZeroPool (NvStorageSize); + if (NvStorageData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NvStorageBase = NV_STORAGE_VARIABLE_BASE; + ASSERT (NvStorageBase != 0); + + // + // Copy NV storage data to the memory buffer. + // + CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize); + + Status = GetFtwProtocol ((VOID **)&FtwProtocol); + // + // If FTW protocol has been installed, no need to check FTW last write data hob. + // + if (EFI_ERROR (Status)) { + // + // Check the FTW last write data hob. + // + GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid); + if (GuidHob != NULL) { + FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob); + if (FtwLastWriteData->TargetAddress == NvStorageBase) { + DEBUG ((DEBUG_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress)); + // + // Copy the backed up NV storage data to the memory buffer from spare block. + // + CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize); + } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && + (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) { + // + // Flash NV storage from the Offset is backed up in spare block. + // + BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase); + BackUpSize = NvStorageSize - BackUpOffset; + DEBUG ((DEBUG_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress)); + // + // Copy the partial backed up NV storage data to the memory buffer from spare block. + // + CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize); + } + } + } + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData; + + // + // Check if the Firmware Volume is not corrupted + // + if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) { + FreePool (NvStorageData); + DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n")); + return EFI_VOLUME_CORRUPTED; + } + + VariableStore = (VARIABLE_STORE_HEADER *) ((UINTN) FvHeader + FvHeader->HeaderLength); + VariableStoreLength = NvStorageSize - FvHeader->HeaderLength; + ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength); + ASSERT (VariableStore->Size == VariableStoreLength); + + // + // Check if the Variable Store header is not corrupted + // + if (GetVariableStoreStatus (VariableStore) != EfiValid) { + FreePool (NvStorageData); + DEBUG((DEBUG_ERROR, "Variable Store header is corrupted\n")); + return EFI_VOLUME_CORRUPTED; + } + + mNvFvHeaderCache = FvHeader; + + *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore; + + HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize); + MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize); + BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize); + + // + // Note that in EdkII variable driver implementation, Hardware Error Record type variable + // is stored with common variable in the same NV region. So the platform integrator should + // ensure that the value of PcdHwErrStorageSize is less than the value of + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). + // + ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))); + // + // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize). + // + ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize)); + // + // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize). + // + ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize)); + + mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize); + mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace); + mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize; + + DEBUG (( + DEBUG_INFO, + "Variable driver common space: 0x%x 0x%x 0x%x\n", + mVariableModuleGlobal->CommonVariableSpace, + mVariableModuleGlobal->CommonMaxUserVariableSpace, + mVariableModuleGlobal->CommonRuntimeVariableSpace + )); + + // + // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). + // + ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))); + + return EFI_SUCCESS; +} + +/** + Init non-volatile variable store. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted. + +**/ +EFI_STATUS +InitNonVolatileVariableStore ( + VOID + ) +{ + VARIABLE_HEADER *Variable; + VARIABLE_HEADER *NextVariable; + EFI_PHYSICAL_ADDRESS VariableStoreBase; + UINTN VariableSize; + EFI_STATUS Status; + + if (PcdGetBool (PcdEmuVariableNvModeEnable)) { + Status = InitEmuNonVolatileVariableStore (&VariableStoreBase); + if (EFI_ERROR (Status)) { + return Status; + } + mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE; + DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n")); + } else { + Status = InitRealNonVolatileVariableStore (&VariableStoreBase); + if (EFI_ERROR (Status)) { + return Status; + } + mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE; + } + + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; + mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase; + mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid)); + + mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize); + mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize); + + // + // Parse non-volatile variable data and get last variable offset. + // + Variable = GetStartPointer (mNvVariableCache); + while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) { + NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat); + VariableSize = (UINTN) NextVariable - (UINTN) Variable; + if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; + } else { + mVariableModuleGlobal->CommonVariableTotalSize += VariableSize; + } + + Variable = NextVariable; + } + mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) mNvVariableCache; + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.h new file mode 100644 index 00000000000..43653f27e6e --- /dev/null +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.h @@ -0,0 +1,67 @@ +/** @file + Common variable non-volatile store routines. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _VARIABLE_NON_VOLATILE_H_ +#define _VARIABLE_NON_VOLATILE_H_ + +#include "Variable.h" + +/** + Get non-volatile maximum variable size. + + @return Non-volatile maximum variable size. + +**/ +UINTN +GetNonVolatileMaxVariableSize ( + VOID + ); + +/** + Init emulated non-volatile variable store. + + @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + +**/ +EFI_STATUS +InitEmuNonVolatileVariableStore ( + EFI_PHYSICAL_ADDRESS *VariableStoreBase + ); + +/** + Init real non-volatile variable store. + + @param[out] VariableStoreBase Output pointer to real non-volatile variable store base. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted. + +**/ +EFI_STATUS +InitRealNonVolatileVariableStore ( + OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase + ); + +/** + Init non-volatile variable store. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted. + +**/ +EFI_STATUS +InitNonVolatileVariableStore ( + VOID + ); + +#endif diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c new file mode 100644 index 00000000000..f6d187543d0 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c @@ -0,0 +1,788 @@ +/** @file + Functions in this module are associated with variable parsing operations and + are intended to be usable across variable driver source files. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "VariableParsing.h" + +/** + + This code checks if variable header is valid or not. + + @param[in] Variable Pointer to the Variable Header. + @param[in] VariableStoreEnd Pointer to the Variable Store End. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableStoreEnd + ) +{ + if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) { + // + // Variable is NULL or has reached the end of variable store, + // or the StartId is not correct. + // + return FALSE; + } + + return TRUE; +} + +/** + + This code gets the current status of Variable Store. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @retval EfiRaw Variable store status is raw. + @retval EfiValid Variable store status is valid. + @retval EfiInvalid Variable store status is invalid. + +**/ +VARIABLE_STORE_STATUS +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) || + CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) && + VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && + VarStoreHeader->State == VARIABLE_STORE_HEALTHY + ) { + + return EfiValid; + } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff && + VarStoreHeader->Size == 0xffffffff && + VarStoreHeader->Format == 0xff && + VarStoreHeader->State == 0xff + ) { + + return EfiRaw; + } else { + return EfiInvalid; + } +} + +/** + This code gets the size of variable header. + + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Size of variable header in bytes in type UINTN. + +**/ +UINTN +GetVariableHeaderSize ( + IN BOOLEAN AuthFormat + ) +{ + UINTN Value; + + if (AuthFormat) { + Value = sizeof (AUTHENTICATED_VARIABLE_HEADER); + } else { + Value = sizeof (VARIABLE_HEADER); + } + + return Value; +} + +/** + + This code gets the size of name of variable. + + @param[in] Variable Pointer to the variable header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return UINTN Size of variable in bytes. + +**/ +UINTN +NameSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (AuthFormat) { + if (AuthVariable->State == (UINT8) (-1) || + AuthVariable->DataSize == (UINT32) (-1) || + AuthVariable->NameSize == (UINT32) (-1) || + AuthVariable->Attributes == (UINT32) (-1)) { + return 0; + } + return (UINTN) AuthVariable->NameSize; + } else { + if (Variable->State == (UINT8) (-1) || + Variable->DataSize == (UINT32) (-1) || + Variable->NameSize == (UINT32) (-1) || + Variable->Attributes == (UINT32) (-1)) { + return 0; + } + return (UINTN) Variable->NameSize; + } +} + +/** + This code sets the size of name of variable. + + @param[in] Variable Pointer to the Variable Header. + @param[in] NameSize Name size to set. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + +**/ +VOID +SetNameSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN UINTN NameSize, + IN BOOLEAN AuthFormat + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (AuthFormat) { + AuthVariable->NameSize = (UINT32) NameSize; + } else { + Variable->NameSize = (UINT32) NameSize; + } +} + +/** + + This code gets the size of variable data. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Size of variable in bytes. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (AuthFormat) { + if (AuthVariable->State == (UINT8) (-1) || + AuthVariable->DataSize == (UINT32) (-1) || + AuthVariable->NameSize == (UINT32) (-1) || + AuthVariable->Attributes == (UINT32) (-1)) { + return 0; + } + return (UINTN) AuthVariable->DataSize; + } else { + if (Variable->State == (UINT8) (-1) || + Variable->DataSize == (UINT32) (-1) || + Variable->NameSize == (UINT32) (-1) || + Variable->Attributes == (UINT32) (-1)) { + return 0; + } + return (UINTN) Variable->DataSize; + } +} + +/** + This code sets the size of variable data. + + @param[in] Variable Pointer to the Variable Header. + @param[in] DataSize Data size to set. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + +**/ +VOID +SetDataSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN UINTN DataSize, + IN BOOLEAN AuthFormat + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (AuthFormat) { + AuthVariable->DataSize = (UINT32) DataSize; + } else { + Variable->DataSize = (UINT32) DataSize; + } +} + +/** + + This code gets the pointer to the variable name. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Pointer to Variable Name which is Unicode encoding. + +**/ +CHAR16 * +GetVariableNamePtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ) +{ + return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize (AuthFormat)); +} + +/** + This code gets the pointer to the variable guid. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return A EFI_GUID* pointer to Vendor Guid. + +**/ +EFI_GUID * +GetVendorGuidPtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; + if (AuthFormat) { + return &AuthVariable->VendorGuid; + } else { + return &Variable->VendorGuid; + } +} + +/** + + This code gets the pointer to the variable data. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Pointer to Variable Data. + +**/ +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ) +{ + UINTN Value; + + // + // Be careful about pad size for alignment. + // + Value = (UINTN) GetVariableNamePtr (Variable, AuthFormat); + Value += NameSizeOfVariable (Variable, AuthFormat); + Value += GET_PAD_SIZE (NameSizeOfVariable (Variable, AuthFormat)); + + return (UINT8 *) Value; +} + +/** + This code gets the variable data offset related to variable header. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Variable Data offset. + +**/ +UINTN +GetVariableDataOffset ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ) +{ + UINTN Value; + + // + // Be careful about pad size for alignment + // + Value = GetVariableHeaderSize (AuthFormat); + Value += NameSizeOfVariable (Variable, AuthFormat); + Value += GET_PAD_SIZE (NameSizeOfVariable (Variable, AuthFormat)); + + return Value; +} + +/** + + This code gets the pointer to the next variable header. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Pointer to next variable header. + +**/ +VARIABLE_HEADER * +GetNextVariablePtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ) +{ + UINTN Value; + + Value = (UINTN) GetVariableDataPtr (Variable, AuthFormat); + Value += DataSizeOfVariable (Variable, AuthFormat); + Value += GET_PAD_SIZE (DataSizeOfVariable (Variable, AuthFormat)); + + // + // Be careful about pad size for alignment. + // + return (VARIABLE_HEADER *) HEADER_ALIGN (Value); +} + +/** + + Gets the pointer to the first variable header in given variable store area. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the first variable header. + +**/ +VARIABLE_HEADER * +GetStartPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The start of variable store. + // + return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1); +} + +/** + + Gets the pointer to the end of the variable storage area. + + This function gets pointer to the end of the variable storage + area, according to the input variable store header. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the end of the variable storage area. + +**/ +VARIABLE_HEADER * +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size); +} + +/** + Compare two EFI_TIME data. + + + @param[in] FirstTime A pointer to the first EFI_TIME data. + @param[in] SecondTime A pointer to the second EFI_TIME data. + + @retval TRUE The FirstTime is not later than the SecondTime. + @retval FALSE The FirstTime is later than the SecondTime. + +**/ +BOOLEAN +VariableCompareTimeStampInternal ( + IN EFI_TIME *FirstTime, + IN EFI_TIME *SecondTime + ) +{ + if (FirstTime->Year != SecondTime->Year) { + return (BOOLEAN) (FirstTime->Year < SecondTime->Year); + } else if (FirstTime->Month != SecondTime->Month) { + return (BOOLEAN) (FirstTime->Month < SecondTime->Month); + } else if (FirstTime->Day != SecondTime->Day) { + return (BOOLEAN) (FirstTime->Day < SecondTime->Day); + } else if (FirstTime->Hour != SecondTime->Hour) { + return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour); + } else if (FirstTime->Minute != SecondTime->Minute) { + return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute); + } + + return (BOOLEAN) (FirstTime->Second <= SecondTime->Second); +} + +/** + Find the variable in the specified variable store. + + @param[in] VariableName Name of the variable to be found + @param[in] VendorGuid Vendor GUID to be found. + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute + check at runtime when searching variable. + @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @retval EFI_SUCCESS Variable found successfully + @retval EFI_NOT_FOUND Variable not found +**/ +EFI_STATUS +FindVariableEx ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN BOOLEAN IgnoreRtCheck, + IN OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN BOOLEAN AuthFormat + ) +{ + VARIABLE_HEADER *InDeletedVariable; + VOID *Point; + + PtrTrack->InDeletedTransitionPtr = NULL; + + // + // Find the variable by walk through HOB, volatile and non-volatile variable store. + // + InDeletedVariable = NULL; + + for ( PtrTrack->CurrPtr = PtrTrack->StartPtr + ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr) + ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr, AuthFormat) + ) { + if (PtrTrack->CurrPtr->State == VAR_ADDED || + PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) + ) { + if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { + if (VariableName[0] == 0) { + if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + InDeletedVariable = PtrTrack->CurrPtr; + } else { + PtrTrack->InDeletedTransitionPtr = InDeletedVariable; + return EFI_SUCCESS; + } + } else { + if (CompareGuid (VendorGuid, GetVendorGuidPtr (PtrTrack->CurrPtr, AuthFormat))) { + Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr, AuthFormat); + + ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr, AuthFormat) != 0); + if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr, AuthFormat)) == 0) { + if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + InDeletedVariable = PtrTrack->CurrPtr; + } else { + PtrTrack->InDeletedTransitionPtr = InDeletedVariable; + return EFI_SUCCESS; + } + } + } + } + } + } + } + + PtrTrack->CurrPtr = InDeletedVariable; + return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; +} + +/** + This code finds the next available variable. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode. This function will do basic validation, before parse the data. + + @param[in] VariableName Pointer to variable name. + @param[in] VendorGuid Variable Vendor Guid. + @param[in] VariableStoreList A list of variable stores that should be used to get the next variable. + The maximum number of entries is the max value of VARIABLE_STORE_TYPE. + @param[out] VariablePtr Pointer to variable header address. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The next variable was not found. + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL. + @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and + GUID of an existing variable. + +**/ +EFI_STATUS +EFIAPI +VariableServiceGetNextVariableInternal ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VARIABLE_STORE_HEADER **VariableStoreList, + OUT VARIABLE_HEADER **VariablePtr, + IN BOOLEAN AuthFormat + ) +{ + EFI_STATUS Status; + VARIABLE_STORE_TYPE StoreType; + VARIABLE_POINTER_TRACK Variable; + VARIABLE_POINTER_TRACK VariableInHob; + VARIABLE_POINTER_TRACK VariablePtrTrack; + + Status = EFI_NOT_FOUND; + + if (VariableStoreList == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Variable, sizeof (Variable)); + + // Check if the variable exists in the given variable store list + for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) { + if (VariableStoreList[StoreType] == NULL) { + continue; + } + + Variable.StartPtr = GetStartPointer (VariableStoreList[StoreType]); + Variable.EndPtr = GetEndPointer (VariableStoreList[StoreType]); + Variable.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile); + + Status = FindVariableEx (VariableName, VendorGuid, FALSE, &Variable, AuthFormat); + if (!EFI_ERROR (Status)) { + break; + } + } + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + // + // For VariableName is an empty string, FindVariableEx() will try to find and return + // the first qualified variable, and if FindVariableEx() returns error (EFI_NOT_FOUND) + // as no any variable is found, still go to return the error (EFI_NOT_FOUND). + // + if (VariableName[0] != 0) { + // + // For VariableName is not an empty string, and FindVariableEx() returns error as + // VariableName and VendorGuid are not a name and GUID of an existing variable, + // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER. + // + Status = EFI_INVALID_PARAMETER; + } + goto Done; + } + + if (VariableName[0] != 0) { + // + // If variable name is not empty, get next variable. + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat); + } + + while (TRUE) { + // + // Switch to the next variable store if needed + // + while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) { + // + // Find current storage index + // + for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) { + if ((VariableStoreList[StoreType] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreList[StoreType]))) { + break; + } + } + ASSERT (StoreType < VariableStoreTypeMax); + // + // Switch to next storage + // + for (StoreType++; StoreType < VariableStoreTypeMax; StoreType++) { + if (VariableStoreList[StoreType] != NULL) { + break; + } + } + // + // Capture the case that + // 1. current storage is the last one, or + // 2. no further storage + // + if (StoreType == VariableStoreTypeMax) { + Status = EFI_NOT_FOUND; + goto Done; + } + Variable.StartPtr = GetStartPointer (VariableStoreList[StoreType]); + Variable.EndPtr = GetEndPointer (VariableStoreList[StoreType]); + Variable.CurrPtr = Variable.StartPtr; + } + + // + // Variable is found + // + if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { + if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + // + // If it is a IN_DELETED_TRANSITION variable, + // and there is also a same ADDED one at the same time, + // don't return it. + // + VariablePtrTrack.StartPtr = Variable.StartPtr; + VariablePtrTrack.EndPtr = Variable.EndPtr; + Status = FindVariableEx ( + GetVariableNamePtr (Variable.CurrPtr, AuthFormat), + GetVendorGuidPtr (Variable.CurrPtr, AuthFormat), + FALSE, + &VariablePtrTrack, + AuthFormat + ); + if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) { + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat); + continue; + } + } + + // + // Don't return NV variable when HOB overrides it + // + if ((VariableStoreList[VariableStoreTypeHob] != NULL) && (VariableStoreList[VariableStoreTypeNv] != NULL) && + (Variable.StartPtr == GetStartPointer (VariableStoreList[VariableStoreTypeNv])) + ) { + VariableInHob.StartPtr = GetStartPointer (VariableStoreList[VariableStoreTypeHob]); + VariableInHob.EndPtr = GetEndPointer (VariableStoreList[VariableStoreTypeHob]); + Status = FindVariableEx ( + GetVariableNamePtr (Variable.CurrPtr, AuthFormat), + GetVendorGuidPtr (Variable.CurrPtr, AuthFormat), + FALSE, + &VariableInHob, + AuthFormat + ); + if (!EFI_ERROR (Status)) { + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat); + continue; + } + } + + *VariablePtr = Variable.CurrPtr; + Status = EFI_SUCCESS; + goto Done; + } + } + + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat); + } + +Done: + return Status; +} + +/** + Routine used to track statistical information about variable usage. + The data is stored in the EFI system table so it can be accessed later. + VariableInfo.efi can dump out the table. Only Boot Services variable + accesses are tracked by this code. The PcdVariableCollectStatistics + build flag controls if this feature is enabled. + + A read that hits in the cache will have Read and Cache true for + the transaction. Data is allocated by this routine, but never + freed. + + @param[in] VariableName Name of the Variable to track. + @param[in] VendorGuid Guid of the Variable to track. + @param[in] Volatile TRUE if volatile FALSE if non-volatile. + @param[in] Read TRUE if GetVariable() was called. + @param[in] Write TRUE if SetVariable() was called. + @param[in] Delete TRUE if deleted via SetVariable(). + @param[in] Cache TRUE for a cache hit. + @param[in,out] VariableInfo Pointer to a pointer of VARIABLE_INFO_ENTRY structures. + +**/ +VOID +UpdateVariableInfo ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN BOOLEAN Volatile, + IN BOOLEAN Read, + IN BOOLEAN Write, + IN BOOLEAN Delete, + IN BOOLEAN Cache, + IN OUT VARIABLE_INFO_ENTRY **VariableInfo + ) +{ + VARIABLE_INFO_ENTRY *Entry; + + if (FeaturePcdGet (PcdVariableCollectStatistics)) { + if (VariableName == NULL || VendorGuid == NULL || VariableInfo == NULL) { + return; + } + if (AtRuntime ()) { + // Don't collect statistics at runtime. + return; + } + + if (*VariableInfo == NULL) { + // + // On the first call allocate a entry and place a pointer to it in + // the EFI System Table. + // + *VariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); + ASSERT (*VariableInfo != NULL); + + CopyGuid (&(*VariableInfo)->VendorGuid, VendorGuid); + (*VariableInfo)->Name = AllocateZeroPool (StrSize (VariableName)); + ASSERT ((*VariableInfo)->Name != NULL); + StrCpyS ((*VariableInfo)->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName); + (*VariableInfo)->Volatile = Volatile; + } + + + for (Entry = (*VariableInfo); Entry != NULL; Entry = Entry->Next) { + if (CompareGuid (VendorGuid, &Entry->VendorGuid)) { + if (StrCmp (VariableName, Entry->Name) == 0) { + if (Read) { + Entry->ReadCount++; + } + if (Write) { + Entry->WriteCount++; + } + if (Delete) { + Entry->DeleteCount++; + } + if (Cache) { + Entry->CacheCount++; + } + + return; + } + } + + if (Entry->Next == NULL) { + // + // If the entry is not in the table add it. + // Next iteration of the loop will fill in the data. + // + Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); + ASSERT (Entry->Next != NULL); + + CopyGuid (&Entry->Next->VendorGuid, VendorGuid); + Entry->Next->Name = AllocateZeroPool (StrSize (VariableName)); + ASSERT (Entry->Next->Name != NULL); + StrCpyS (Entry->Next->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName); + Entry->Next->Volatile = Volatile; + } + } + } +} diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h new file mode 100644 index 00000000000..92a729d1408 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h @@ -0,0 +1,347 @@ +/** @file + Functions in this module are associated with variable parsing operations and + are intended to be usable across variable driver source files. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _VARIABLE_PARSING_H_ +#define _VARIABLE_PARSING_H_ + +#include +#include "Variable.h" + +/** + + This code checks if variable header is valid or not. + + @param[in] Variable Pointer to the Variable Header. + @param[in] VariableStoreEnd Pointer to the Variable Store End. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableStoreEnd + ); + +/** + + This code gets the current status of Variable Store. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @retval EfiRaw Variable store status is raw. + @retval EfiValid Variable store status is valid. + @retval EfiInvalid Variable store status is invalid. + +**/ +VARIABLE_STORE_STATUS +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ); + +/** + This code gets the size of variable header. + + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Size of variable header in bytes in type UINTN. + +**/ +UINTN +GetVariableHeaderSize ( + IN BOOLEAN AuthFormat + ); + +/** + + This code gets the size of name of variable. + + @param[in] Variable Pointer to the variable header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return UINTN Size of variable in bytes. + +**/ +UINTN +NameSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ); + +/** + This code sets the size of name of variable. + + @param[in] Variable Pointer to the Variable Header. + @param[in] NameSize Name size to set. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + +**/ +VOID +SetNameSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN UINTN NameSize, + IN BOOLEAN AuthFormat + ); + +/** + + This code gets the size of variable data. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Size of variable in bytes. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ); + +/** + This code sets the size of variable data. + + @param[in] Variable Pointer to the Variable Header. + @param[in] DataSize Data size to set. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + +**/ +VOID +SetDataSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN UINTN DataSize, + IN BOOLEAN AuthFormat + ); + +/** + + This code gets the pointer to the variable name. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Pointer to Variable Name which is Unicode encoding. + +**/ +CHAR16 * +GetVariableNamePtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ); + +/** + This code gets the pointer to the variable guid. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return A EFI_GUID* pointer to Vendor Guid. + +**/ +EFI_GUID * +GetVendorGuidPtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ); + +/** + + This code gets the pointer to the variable data. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Pointer to Variable Data. + +**/ +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ); + +/** + This code gets the variable data offset related to variable header. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Variable Data offset. + +**/ +UINTN +GetVariableDataOffset ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ); + +/** + + This code gets the pointer to the next variable header. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @return Pointer to next variable header. + +**/ +VARIABLE_HEADER * +GetNextVariablePtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFormat + ); + +/** + + Gets the pointer to the first variable header in given variable store area. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the first variable header. + +**/ +VARIABLE_HEADER * +GetStartPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ); + +/** + + Gets the pointer to the end of the variable storage area. + + This function gets pointer to the end of the variable storage + area, according to the input variable store header. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the end of the variable storage area. + +**/ +VARIABLE_HEADER * +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ); + +/** + Compare two EFI_TIME data. + + + @param[in] FirstTime A pointer to the first EFI_TIME data. + @param[in] SecondTime A pointer to the second EFI_TIME data. + + @retval TRUE The FirstTime is not later than the SecondTime. + @retval FALSE The FirstTime is later than the SecondTime. + +**/ +BOOLEAN +VariableCompareTimeStampInternal ( + IN EFI_TIME *FirstTime, + IN EFI_TIME *SecondTime + ); + +/** + Find the variable in the specified variable store. + + @param[in] VariableName Name of the variable to be found + @param[in] VendorGuid Vendor GUID to be found. + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute + check at runtime when searching variable. + @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @retval EFI_SUCCESS Variable found successfully + @retval EFI_NOT_FOUND Variable not found +**/ +EFI_STATUS +FindVariableEx ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN BOOLEAN IgnoreRtCheck, + IN OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN BOOLEAN AuthFormat + ); + +/** + This code finds the next available variable. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode. This function will do basic validation, before parse the data. + + @param[in] VariableName Pointer to variable name. + @param[in] VendorGuid Variable Vendor Guid. + @param[in] VariableStoreList A list of variable stores that should be used to get the next variable. + The maximum number of entries is the max value of VARIABLE_STORE_TYPE. + @param[out] VariablePtr Pointer to variable header address. + @param[in] AuthFormat TRUE indicates authenticated variables are used. + FALSE indicates authenticated variables are not used. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The next variable was not found. + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL. + @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and + GUID of an existing variable. + +**/ +EFI_STATUS +EFIAPI +VariableServiceGetNextVariableInternal ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VARIABLE_STORE_HEADER **VariableStoreList, + OUT VARIABLE_HEADER **VariablePtr, + IN BOOLEAN AuthFormat + ); + +/** + Routine used to track statistical information about variable usage. + The data is stored in the EFI system table so it can be accessed later. + VariableInfo.efi can dump out the table. Only Boot Services variable + accesses are tracked by this code. The PcdVariableCollectStatistics + build flag controls if this feature is enabled. + + A read that hits in the cache will have Read and Cache true for + the transaction. Data is allocated by this routine, but never + freed. + + @param[in] VariableName Name of the Variable to track. + @param[in] VendorGuid Guid of the Variable to track. + @param[in] Volatile TRUE if volatile FALSE if non-volatile. + @param[in] Read TRUE if GetVariable() was called. + @param[in] Write TRUE if SetVariable() was called. + @param[in] Delete TRUE if deleted via SetVariable(). + @param[in] Cache TRUE for a cache hit. + @param[in,out] VariableInfo Pointer to a pointer of VARIABLE_INFO_ENTRY structures. + +**/ +VOID +UpdateVariableInfo ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN BOOLEAN Volatile, + IN BOOLEAN Read, + IN BOOLEAN Write, + IN BOOLEAN Delete, + IN BOOLEAN Cache, + IN OUT VARIABLE_INFO_ENTRY **VariableInfo + ); + +#endif diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c new file mode 100644 index 00000000000..bc93cc07d21 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c @@ -0,0 +1,153 @@ +/** @file + Functions related to managing the UEFI variable runtime cache. This file should only include functions + used by the SMM UEFI variable driver. + + Caution: This module requires additional review when modified. + This driver will have external input - variable data. They may be input in SMM mode. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "VariableParsing.h" +#include "VariableRuntimeCache.h" + +extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; +extern VARIABLE_STORE_HEADER *mNvVariableCache; + +/** + Copies any pending updates to runtime variable caches. + + @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly. + @retval EFI_SUCCESS The volatile store was updated successfully. + +**/ +EFI_STATUS +FlushPendingRuntimeVariableCacheUpdates ( + VOID + ) +{ + VARIABLE_RUNTIME_CACHE_CONTEXT *VariableRuntimeCacheContext; + + VariableRuntimeCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext; + + if (VariableRuntimeCacheContext->VariableRuntimeNvCache.Store == NULL || + VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store == NULL || + VariableRuntimeCacheContext->PendingUpdate == NULL) { + return EFI_UNSUPPORTED; + } + + if (*(VariableRuntimeCacheContext->PendingUpdate)) { + if (VariableRuntimeCacheContext->VariableRuntimeHobCache.Store != NULL && + mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) { + CopyMem ( + (VOID *) ( + ((UINT8 *) (UINTN) VariableRuntimeCacheContext->VariableRuntimeHobCache.Store) + + VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset + ), + (VOID *) ( + ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase) + + VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset + ), + VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength + ); + VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0; + VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0; + } + + CopyMem ( + (VOID *) ( + ((UINT8 *) (UINTN) VariableRuntimeCacheContext->VariableRuntimeNvCache.Store) + + VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset + ), + (VOID *) ( + ((UINT8 *) (UINTN) mNvVariableCache) + + VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset + ), + VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength + ); + VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength = 0; + VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0; + + CopyMem ( + (VOID *) ( + ((UINT8 *) (UINTN) VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store) + + VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset + ), + (VOID *) ( + ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase) + + VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset + ), + VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength + ); + VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = 0; + VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0; + *(VariableRuntimeCacheContext->PendingUpdate) = FALSE; + } + + return EFI_SUCCESS; +} + +/** + Synchronizes the runtime variable caches with all pending updates outside runtime. + + Ensures all conditions are met to maintain coherency for runtime cache updates. This function will attempt + to write the given update (and any other pending updates) if the ReadLock is available. Otherwise, the + update is added as a pending update for the given variable store and it will be flushed to the runtime cache + at the next opportunity the ReadLock is available. + + @param[in] VariableRuntimeCache Variable runtime cache structure for the runtime cache being synchronized. + @param[in] Offset Offset in bytes to apply the update. + @param[in] Length Length of data in bytes of the update. + + @retval EFI_SUCCESS The update was added as a pending update successfully. If the variable runtime + cache ReadLock was available, the runtime cache was updated successfully. + @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly. + +**/ +EFI_STATUS +SynchronizeRuntimeVariableCache ( + IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache, + IN UINTN Offset, + IN UINTN Length + ) +{ + if (VariableRuntimeCache == NULL) { + return EFI_INVALID_PARAMETER; + } else if (VariableRuntimeCache->Store == NULL) { + // The runtime cache may not be active or allocated yet. + // In either case, return EFI_SUCCESS instead of EFI_NOT_AVAILABLE_YET. + return EFI_SUCCESS; + } + + if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate == NULL || + mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock == NULL) { + return EFI_UNSUPPORTED; + } + + if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) && + VariableRuntimeCache->PendingUpdateLength > 0) { + VariableRuntimeCache->PendingUpdateLength = + (UINT32) ( + MAX ( + (UINTN) (VariableRuntimeCache->PendingUpdateOffset + VariableRuntimeCache->PendingUpdateLength), + Offset + Length + ) - MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, Offset) + ); + VariableRuntimeCache->PendingUpdateOffset = + (UINT32) MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, Offset); + } else { + VariableRuntimeCache->PendingUpdateLength = (UINT32) Length; + VariableRuntimeCache->PendingUpdateOffset = (UINT32) Offset; + } + *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) = TRUE; + + if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock) == FALSE) { + return FlushPendingRuntimeVariableCacheUpdates (); + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.h new file mode 100644 index 00000000000..f9804a1d692 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.h @@ -0,0 +1,51 @@ +/** @file + The common variable volatile store routines shared by the DXE_RUNTIME variable + module and the DXE_SMM variable module. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _VARIABLE_RUNTIME_CACHE_H_ +#define _VARIABLE_RUNTIME_CACHE_H_ + +#include "Variable.h" + +/** + Copies any pending updates to runtime variable caches. + + @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly. + @retval EFI_SUCCESS The volatile store was updated successfully. + +**/ +EFI_STATUS +FlushPendingRuntimeVariableCacheUpdates ( + VOID + ); + +/** + Synchronizes the runtime variable caches with all pending updates outside runtime. + + Ensures all conditions are met to maintain coherency for runtime cache updates. This function will attempt + to write the given update (and any other pending updates) if the ReadLock is available. Otherwise, the + update is added as a pending update for the given variable store and it will be flushed to the runtime cache + at the next opportunity the ReadLock is available. + + @param[in] VariableRuntimeCache Variable runtime cache structure for the runtime cache being synchronized. + @param[in] Offset Offset in bytes to apply the update. + @param[in] Length Length of data in bytes of the update. + + @retval EFI_SUCCESS The update was added as a pending update successfully. If the variable runtime + cache ReadLock was available, the runtime cache was updated successfully. + @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly. + +**/ +EFI_STATUS +SynchronizeRuntimeVariableCache ( + IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache, + IN UINTN Offset, + IN UINTN Length + ); + +#endif diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf index 641376c9c51..ceea5d1ff9a 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf @@ -36,6 +36,12 @@ Variable.c VariableDxe.c Variable.h + VariableNonVolatile.c + VariableNonVolatile.h + VariableParsing.c + VariableParsing.h + VariableRuntimeCache.c + VariableRuntimeCache.h PrivilegePolymorphic.h Measurement.c TcgMorLockDxe.c diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c index ec463d063ea..caca5c32411 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c @@ -30,6 +30,10 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include "Variable.h" +#include "VariableParsing.h" +#include "VariableRuntimeCache.h" + +extern VARIABLE_STORE_HEADER *mNvVariableCache; BOOLEAN mAtRuntime = FALSE; UINT8 *mVariableBufferPayload = NULL; @@ -450,25 +454,29 @@ SmmVariableGetStatistics ( EFI_STATUS EFIAPI SmmVariableHandler ( - IN EFI_HANDLE DispatchHandle, - IN CONST VOID *RegisterContext, - IN OUT VOID *CommBuffer, - IN OUT UINTN *CommBufferSize + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *RegisterContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize ) { - EFI_STATUS Status; - SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; - SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; - SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName; - SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo; - SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *GetPayloadSize; - VARIABLE_INFO_ENTRY *VariableInfo; - SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock; - SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty; - UINTN InfoSize; - UINTN NameBufferSize; - UINTN CommBufferPayloadSize; - UINTN TempCommBufferSize; + EFI_STATUS Status; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; + SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName; + SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo; + SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *GetPayloadSize; + SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *RuntimeVariableCacheContext; + SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *GetRuntimeCacheInfo; + SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock; + SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty; + VARIABLE_INFO_ENTRY *VariableInfo; + VARIABLE_RUNTIME_CACHE_CONTEXT *VariableCacheContext; + VARIABLE_STORE_HEADER *VariableCache; + UINTN InfoSize; + UINTN NameBufferSize; + UINTN CommBufferPayloadSize; + UINTN TempCommBufferSize; // // If input is invalid, stop processing this SMI @@ -788,6 +796,154 @@ SmmVariableHandler ( ); CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize); break; + case SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT: + if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT)) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: SMM communication buffer size invalid!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + if (mEndOfDxe) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Cannot init context after end of DXE!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + + // + // Copy the input communicate buffer payload to the pre-allocated SMM variable payload buffer. + // + CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize); + RuntimeVariableCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) mVariableBufferPayload; + + // + // Verify required runtime cache buffers are provided. + // + if (RuntimeVariableCacheContext->RuntimeVolatileCache == NULL || + RuntimeVariableCacheContext->RuntimeNvCache == NULL || + RuntimeVariableCacheContext->PendingUpdate == NULL || + RuntimeVariableCacheContext->ReadLock == NULL || + RuntimeVariableCacheContext->HobFlushComplete == NULL) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Required runtime cache buffer is NULL!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + + // + // Verify minimum size requirements for the runtime variable store buffers. + // + if ((RuntimeVariableCacheContext->RuntimeHobCache != NULL && + RuntimeVariableCacheContext->RuntimeHobCache->Size < sizeof (VARIABLE_STORE_HEADER)) || + RuntimeVariableCacheContext->RuntimeVolatileCache->Size < sizeof (VARIABLE_STORE_HEADER) || + RuntimeVariableCacheContext->RuntimeNvCache->Size < sizeof (VARIABLE_STORE_HEADER)) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: A runtime cache buffer size is invalid!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + + // + // Verify runtime buffers do not overlap with SMRAM ranges. + // + if (RuntimeVariableCacheContext->RuntimeHobCache != NULL && + !VariableSmmIsBufferOutsideSmmValid ( + (UINTN) RuntimeVariableCacheContext->RuntimeHobCache, + (UINTN) RuntimeVariableCacheContext->RuntimeHobCache->Size)) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime HOB cache buffer in SMRAM or overflow!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + if (!VariableSmmIsBufferOutsideSmmValid ( + (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache, + (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache->Size)) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime volatile cache buffer in SMRAM or overflow!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + if (!VariableSmmIsBufferOutsideSmmValid ( + (UINTN) RuntimeVariableCacheContext->RuntimeNvCache, + (UINTN) RuntimeVariableCacheContext->RuntimeNvCache->Size)) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime non-volatile cache buffer in SMRAM or overflow!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + if (!VariableSmmIsBufferOutsideSmmValid ( + (UINTN) RuntimeVariableCacheContext->PendingUpdate, + sizeof (*(RuntimeVariableCacheContext->PendingUpdate)))) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache pending update buffer in SMRAM or overflow!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + if (!VariableSmmIsBufferOutsideSmmValid ( + (UINTN) RuntimeVariableCacheContext->ReadLock, + sizeof (*(RuntimeVariableCacheContext->ReadLock)))) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache read lock buffer in SMRAM or overflow!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + if (!VariableSmmIsBufferOutsideSmmValid ( + (UINTN) RuntimeVariableCacheContext->HobFlushComplete, + sizeof (*(RuntimeVariableCacheContext->HobFlushComplete)))) { + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache HOB flush complete buffer in SMRAM or overflow!\n")); + Status = EFI_ACCESS_DENIED; + goto EXIT; + } + + VariableCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext; + VariableCacheContext->VariableRuntimeHobCache.Store = RuntimeVariableCacheContext->RuntimeHobCache; + VariableCacheContext->VariableRuntimeVolatileCache.Store = RuntimeVariableCacheContext->RuntimeVolatileCache; + VariableCacheContext->VariableRuntimeNvCache.Store = RuntimeVariableCacheContext->RuntimeNvCache; + VariableCacheContext->PendingUpdate = RuntimeVariableCacheContext->PendingUpdate; + VariableCacheContext->ReadLock = RuntimeVariableCacheContext->ReadLock; + VariableCacheContext->HobFlushComplete = RuntimeVariableCacheContext->HobFlushComplete; + + // Set up the intial pending request since the RT cache needs to be in sync with SMM cache + VariableCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0; + VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0; + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0 && + VariableCacheContext->VariableRuntimeHobCache.Store != NULL) { + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase; + VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache); + CopyGuid (&(VariableCacheContext->VariableRuntimeHobCache.Store->Signature), &(VariableCache->Signature)); + } + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; + VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0; + VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache); + CopyGuid (&(VariableCacheContext->VariableRuntimeVolatileCache.Store->Signature), &(VariableCache->Signature)); + + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache; + VariableCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0; + VariableCacheContext->VariableRuntimeNvCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache); + CopyGuid (&(VariableCacheContext->VariableRuntimeNvCache.Store->Signature), &(VariableCache->Signature)); + + *(VariableCacheContext->PendingUpdate) = TRUE; + *(VariableCacheContext->ReadLock) = FALSE; + *(VariableCacheContext->HobFlushComplete) = FALSE; + + Status = EFI_SUCCESS; + break; + case SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE: + Status = FlushPendingRuntimeVariableCacheUpdates (); + break; + case SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO: + if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO)) { + DEBUG ((DEBUG_ERROR, "GetRuntimeCacheInfo: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + GetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data; + + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) { + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase; + GetRuntimeCacheInfo->TotalHobStorageSize = VariableCache->Size; + } else { + GetRuntimeCacheInfo->TotalHobStorageSize = 0; + } + + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; + GetRuntimeCacheInfo->TotalVolatileStorageSize = VariableCache->Size; + VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache; + GetRuntimeCacheInfo->TotalNvStorageSize = (UINTN) VariableCache->Size; + GetRuntimeCacheInfo->AuthenticatedVariableUsage = mVariableModuleGlobal->VariableGlobal.AuthFormat; + + Status = EFI_SUCCESS; + break; default: Status = EFI_UNSUPPORTED; @@ -974,8 +1130,9 @@ MmVariableServiceInitialize ( ); ASSERT_EFI_ERROR (Status); - mVariableBufferPayloadSize = GetMaxVariableSize () + - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - GetVariableHeaderSize (); + mVariableBufferPayloadSize = GetMaxVariableSize () + + OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - + GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat); Status = gMmst->MmAllocatePool ( EfiRuntimeServicesData, diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf index 0a160d269d4..bc3033588d4 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf @@ -45,6 +45,12 @@ Variable.c VariableTraditionalMm.c VariableSmm.c + VariableNonVolatile.c + VariableNonVolatile.h + VariableParsing.c + VariableParsing.h + VariableRuntimeCache.c + VariableRuntimeCache.h VarCheck.c Variable.h PrivilegePolymorphic.h diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c index 0a1888e5ef6..2cf0ed32ae5 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c @@ -13,7 +13,7 @@ InitCommunicateBuffer() is really function to check the variable data size. -Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -39,6 +39,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include "PrivilegePolymorphic.h" +#include "VariableParsing.h" EFI_HANDLE mHandle = NULL; EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL; @@ -46,8 +47,19 @@ EFI_EVENT mVirtualAddressChangeEvent = NULL; EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL; UINT8 *mVariableBuffer = NULL; UINT8 *mVariableBufferPhysical = NULL; +VARIABLE_INFO_ENTRY *mVariableInfo = NULL; +VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL; +VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL; +VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer = NULL; UINTN mVariableBufferSize; +UINTN mVariableRuntimeHobCacheBufferSize; +UINTN mVariableRuntimeNvCacheBufferSize; +UINTN mVariableRuntimeVolatileCacheBufferSize; UINTN mVariableBufferPayloadSize; +BOOLEAN mVariableRuntimeCachePendingUpdate; +BOOLEAN mVariableRuntimeCacheReadLock; +BOOLEAN mVariableAuthFormat; +BOOLEAN mHobFlushComplete; EFI_LOCK mVariableServicesLock; EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock; EDKII_VAR_CHECK_PROTOCOL mVarCheck; @@ -107,6 +119,72 @@ ReleaseLockOnlyAtBootTime ( } } +/** + Return TRUE if ExitBootServices () has been called. + + @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called. +**/ +BOOLEAN +AtRuntime ( + VOID + ) +{ + return EfiAtRuntime (); +} + +/** + Initialize the variable cache buffer as an empty variable store. + + @param[out] VariableCacheBuffer A pointer to pointer of a cache variable store. + @param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache + buffer that is allocated. On output, the actual size of the buffer allocated. + If TotalVariableCacheSize is zero, a buffer will not be allocated and the + function will return with EFI_SUCCESS. + + @retval EFI_SUCCESS The variable cache was allocated and initialized successfully. + @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified. + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer. + +**/ +EFI_STATUS +InitVariableCache ( + OUT VARIABLE_STORE_HEADER **VariableCacheBuffer, + IN OUT UINTN *TotalVariableCacheSize + ) +{ + VARIABLE_STORE_HEADER *VariableCacheStorePtr; + + if (TotalVariableCacheSize == NULL) { + return EFI_INVALID_PARAMETER; + } + if (*TotalVariableCacheSize == 0) { + return EFI_SUCCESS; + } + if (VariableCacheBuffer == NULL || *TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER)) { + return EFI_INVALID_PARAMETER; + } + *TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof (UINT32)); + + // + // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV) + // + *VariableCacheBuffer = (VARIABLE_STORE_HEADER *) AllocateRuntimePages ( + EFI_SIZE_TO_PAGES (*TotalVariableCacheSize) + ); + if (*VariableCacheBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + VariableCacheStorePtr = *VariableCacheBuffer; + SetMem32 ((VOID *) VariableCacheStorePtr, *TotalVariableCacheSize, (UINT32) 0xFFFFFFFF); + + ZeroMem ((VOID *) VariableCacheStorePtr, sizeof (VARIABLE_STORE_HEADER)); + VariableCacheStorePtr->Size = (UINT32) *TotalVariableCacheSize; + VariableCacheStorePtr->Format = VARIABLE_STORE_FORMATTED; + VariableCacheStorePtr->State = VARIABLE_STORE_HEALTHY; + + return EFI_SUCCESS; +} + /** Initialize the communicate buffer using DataSize and Function. @@ -425,7 +503,56 @@ VarCheckVariablePropertyGet ( } /** - This code finds variable in storage blocks (Volatile or Non-Volatile). + Signals SMM to synchronize any pending variable updates with the runtime cache(s). + +**/ +VOID +SyncRuntimeCache ( + VOID + ) +{ + // + // Init the communicate buffer. The buffer data size is: + // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE. + // + InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE); + + // + // Send data to SMM. + // + SendCommunicateBuffer (0); +} + +/** + Check whether a SMI must be triggered to retrieve pending cache updates. + + If the variable HOB was finished being flushed since the last check for a runtime cache update, this function + will prevent the HOB cache from being used for future runtime cache hits. + +**/ +VOID +CheckForRuntimeCacheSync ( + VOID + ) +{ + if (mVariableRuntimeCachePendingUpdate) { + SyncRuntimeCache (); + } + ASSERT (!mVariableRuntimeCachePendingUpdate); + + // + // The HOB variable data may have finished being flushed in the runtime cache sync update + // + if (mHobFlushComplete && mVariableRuntimeHobCacheBuffer != NULL) { + if (!EfiAtRuntime ()) { + FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize)); + } + mVariableRuntimeHobCacheBuffer = NULL; + } +} + +/** + Finds the given variable in a runtime cache variable store. Caution: This function may receive untrusted input. The data size is external input, so this function will validate it carefully to avoid buffer overflow. @@ -437,20 +564,133 @@ VarCheckVariablePropertyGet ( data, this value contains the required size. @param[out] Data Data pointer. + @retval EFI_SUCCESS Found the specified variable. @retval EFI_INVALID_PARAMETER Invalid parameter. - @retval EFI_SUCCESS Find the specified variable. - @retval EFI_NOT_FOUND Not found. - @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. + @retval EFI_NOT_FOUND The specified variable could not be found. **/ EFI_STATUS -EFIAPI -RuntimeServiceGetVariable ( +FindVariableInRuntimeCache ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, - OUT VOID *Data + OUT VOID *Data OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN TempDataSize; + VARIABLE_POINTER_TRACK RtPtrTrack; + VARIABLE_STORE_TYPE StoreType; + VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax]; + + Status = EFI_NOT_FOUND; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&RtPtrTrack, sizeof (RtPtrTrack)); + + // + // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service + // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent + // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime + // cache read lock should always be free when entering this function. + // + ASSERT (!mVariableRuntimeCacheReadLock); + + mVariableRuntimeCacheReadLock = TRUE; + CheckForRuntimeCacheSync (); + + if (!mVariableRuntimeCachePendingUpdate) { + // + // 0: Volatile, 1: HOB, 2: Non-Volatile. + // The index and attributes mapping must be kept in this order as FindVariable + // makes use of this mapping to implement search algorithm. + // + VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer; + VariableStoreList[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer; + VariableStoreList[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer; + + for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) { + if (VariableStoreList[StoreType] == NULL) { + continue; + } + + RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]); + RtPtrTrack.EndPtr = GetEndPointer (VariableStoreList[StoreType]); + RtPtrTrack.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile); + + Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat); + if (!EFI_ERROR (Status)) { + break; + } + } + + if (!EFI_ERROR (Status)) { + // + // Get data size + // + TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat); + ASSERT (TempDataSize != 0); + + if (*DataSize >= TempDataSize) { + if (Data == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize); + if (Attributes != NULL) { + *Attributes = RtPtrTrack.CurrPtr->Attributes; + } + + *DataSize = TempDataSize; + + UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo); + + Status = EFI_SUCCESS; + goto Done; + } else { + *DataSize = TempDataSize; + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + } + } + +Done: + mVariableRuntimeCacheReadLock = FALSE; + + return Status; +} + +/** + Finds the given variable in a variable store in SMM. + + Caution: This function may receive untrusted input. + The data size is external input, so this function will validate it carefully to avoid buffer overflow. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[out] Attributes Attribute value of the variable found. + @param[in, out] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[out] Data Data pointer. + + @retval EFI_SUCCESS Found the specified variable. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_NOT_FOUND The specified variable could not be found. + +**/ +EFI_STATUS +FindVariableInSmm ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data OPTIONAL ) { EFI_STATUS Status; @@ -474,8 +714,6 @@ RuntimeServiceGetVariable ( return EFI_INVALID_PARAMETER; } - AcquireLockOnlyAtBootTime(&mVariableServicesLock); - // // Init the communicate buffer. The buffer data size is: // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. @@ -488,7 +726,7 @@ RuntimeServiceGetVariable ( } PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize; - Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE); + Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE); if (EFI_ERROR (Status)) { goto Done; } @@ -534,13 +772,134 @@ RuntimeServiceGetVariable ( } Done: + return Status; +} + +/** + This code finds variable in storage blocks (Volatile or Non-Volatile). + + Caution: This function may receive untrusted input. + The data size is external input, so this function will validate it carefully to avoid buffer overflow. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[out] Attributes Attribute value of the variable found. + @param[in, out] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[out] Data Data pointer. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_SUCCESS Find the specified variable. + @retval EFI_NOT_FOUND Not found. + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +RuntimeServiceGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + EFI_STATUS Status; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + if (VariableName[0] == 0) { + return EFI_NOT_FOUND; + } + + AcquireLockOnlyAtBootTime (&mVariableServicesLock); + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { + Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data); + } else { + Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data); + } ReleaseLockOnlyAtBootTime (&mVariableServicesLock); + return Status; } +/** + Finds the next available variable in a runtime cache variable store. + + @param[in, out] VariableNameSize Size of the variable name. + @param[in, out] VariableName Pointer to variable name. + @param[in, out] VendorGuid Variable Vendor Guid. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_SUCCESS Find the specified variable. + @retval EFI_NOT_FOUND Not found. + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +GetNextVariableNameInRuntimeCache ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +{ + EFI_STATUS Status; + UINTN VarNameSize; + VARIABLE_HEADER *VariablePtr; + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; + + Status = EFI_NOT_FOUND; + + // + // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service + // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent + // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime + // cache read lock should always be free when entering this function. + // + ASSERT (!mVariableRuntimeCacheReadLock); + + CheckForRuntimeCacheSync (); + + mVariableRuntimeCacheReadLock = TRUE; + if (!mVariableRuntimeCachePendingUpdate) { + // + // 0: Volatile, 1: HOB, 2: Non-Volatile. + // The index and attributes mapping must be kept in this order as FindVariable + // makes use of this mapping to implement search algorithm. + // + VariableStoreHeader[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer; + VariableStoreHeader[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer; + VariableStoreHeader[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer; + + Status = VariableServiceGetNextVariableInternal ( + VariableName, + VendorGuid, + VariableStoreHeader, + &VariablePtr, + mVariableAuthFormat + ); + if (!EFI_ERROR (Status)) { + VarNameSize = NameSizeOfVariable (VariablePtr, mVariableAuthFormat); + ASSERT (VarNameSize != 0); + if (VarNameSize <= *VariableNameSize) { + CopyMem (VariableName, GetVariableNamePtr (VariablePtr, mVariableAuthFormat), VarNameSize); + CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr, mVariableAuthFormat), sizeof (EFI_GUID)); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + } + } + mVariableRuntimeCacheReadLock = FALSE; + + return Status; +} /** - This code Finds the Next available variable. + Finds the next available variable in a SMM variable store. @param[in, out] VariableNameSize Size of the variable name. @param[in, out] VariableName Pointer to variable name. @@ -553,8 +912,7 @@ RuntimeServiceGetVariable ( **/ EFI_STATUS -EFIAPI -RuntimeServiceGetNextVariableName ( +GetNextVariableNameInSmm ( IN OUT UINTN *VariableNameSize, IN OUT CHAR16 *VariableName, IN OUT EFI_GUID *VendorGuid @@ -566,10 +924,6 @@ RuntimeServiceGetNextVariableName ( UINTN OutVariableNameSize; UINTN InVariableNameSize; - if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { - return EFI_INVALID_PARAMETER; - } - OutVariableNameSize = *VariableNameSize; InVariableNameSize = StrSize (VariableName); SmmGetNextVariableName = NULL; @@ -581,8 +935,6 @@ RuntimeServiceGetNextVariableName ( return EFI_INVALID_PARAMETER; } - AcquireLockOnlyAtBootTime(&mVariableServicesLock); - // // Init the communicate buffer. The buffer data size is: // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. @@ -641,7 +993,59 @@ RuntimeServiceGetNextVariableName ( CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); Done: + return Status; +} + +/** + This code Finds the Next available variable. + + @param[in, out] VariableNameSize Size of the variable name. + @param[in, out] VariableName Pointer to variable name. + @param[in, out] VendorGuid Variable Vendor Guid. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_SUCCESS Find the specified variable. + @retval EFI_NOT_FOUND Not found. + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +RuntimeServiceGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +{ + EFI_STATUS Status; + UINTN MaxLen; + + Status = EFI_NOT_FOUND; + + if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Calculate the possible maximum length of name string, including the Null terminator. + // + MaxLen = *VariableNameSize / sizeof (CHAR16); + if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) { + // + // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer, + // follow spec to return EFI_INVALID_PARAMETER. + // + return EFI_INVALID_PARAMETER; + } + + AcquireLockOnlyAtBootTime (&mVariableServicesLock); + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { + Status = GetNextVariableNameInRuntimeCache (VariableNameSize, VariableName, VendorGuid); + } else { + Status = GetNextVariableNameInSmm (VariableNameSize, VariableName, VendorGuid); + } ReleaseLockOnlyAtBootTime (&mVariableServicesLock); + return Status; } @@ -870,6 +1274,17 @@ OnReadyToBoot ( // SendCommunicateBuffer (0); + // + // Install the system configuration table for variable info data captured + // + if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) { + if (mVariableAuthFormat) { + gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo); + } else { + gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo); + } + } + gBS->CloseEvent (Event); } @@ -893,6 +1308,9 @@ VariableAddressChangeEvent ( { EfiConvertPointer (0x0, (VOID **) &mVariableBuffer); EfiConvertPointer (0x0, (VOID **) &mSmmCommunication); + EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeHobCacheBuffer); + EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeNvCacheBuffer); + EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeVolatileCacheBuffer); } /** @@ -969,6 +1387,159 @@ GetVariablePayloadSize ( return Status; } +/** + This code gets information needed from SMM for runtime cache initialization. + + @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes. + @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes. + @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes. + @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used. + + @retval EFI_SUCCESS Retrieved the size successfully. + @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL. + @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available. + @retval Others Could not retrieve the size successfully. + +**/ +EFI_STATUS +GetRuntimeCacheInfo ( + OUT UINTN *TotalHobStorageSize, + OUT UINTN *TotalNvStorageSize, + OUT UINTN *TotalVolatileStorageSize, + OUT BOOLEAN *AuthenticatedVariableUsage + ) +{ + EFI_STATUS Status; + SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *SmmGetRuntimeCacheInfo; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + UINTN CommSize; + UINT8 *CommBuffer; + + SmmGetRuntimeCacheInfo = NULL; + CommBuffer = mVariableBuffer; + + if (TotalHobStorageSize == NULL || TotalNvStorageSize == NULL || TotalVolatileStorageSize == NULL || AuthenticatedVariableUsage == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (CommBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AcquireLockOnlyAtBootTime (&mVariableServicesLock); + + CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO); + ZeroMem (CommBuffer, CommSize); + + SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer; + CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid); + SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO); + + SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data; + SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO; + SmmGetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data; + + // + // Send data to SMM. + // + Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize); + ASSERT_EFI_ERROR (Status); + if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + Status = SmmVariableFunctionHeader->ReturnStatus; + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Get data from SMM. + // + *TotalHobStorageSize = SmmGetRuntimeCacheInfo->TotalHobStorageSize; + *TotalNvStorageSize = SmmGetRuntimeCacheInfo->TotalNvStorageSize; + *TotalVolatileStorageSize = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize; + *AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage; + +Done: + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); + return Status; +} + +/** + Sends the runtime variable cache context information to SMM. + + @retval EFI_SUCCESS Retrieved the size successfully. + @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL. + @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available. + @retval Others Could not retrieve the size successfully.; + +**/ +EFI_STATUS +SendRuntimeVariableCacheContextToSmm ( + VOID + ) +{ + EFI_STATUS Status; + SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *SmmRuntimeVarCacheContext; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + UINTN CommSize; + UINT8 *CommBuffer; + + SmmRuntimeVarCacheContext = NULL; + CommBuffer = mVariableBuffer; + + if (CommBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AcquireLockOnlyAtBootTime (&mVariableServicesLock); + + // + // Init the communicate buffer. The buffer data size is: + // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); + // + CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); + ZeroMem (CommBuffer, CommSize); + + SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer; + CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid); + SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); + + SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data; + SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT; + SmmRuntimeVarCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) SmmVariableFunctionHeader->Data; + + SmmRuntimeVarCacheContext->RuntimeHobCache = mVariableRuntimeHobCacheBuffer; + SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer; + SmmRuntimeVarCacheContext->RuntimeNvCache = mVariableRuntimeNvCacheBuffer; + SmmRuntimeVarCacheContext->PendingUpdate = &mVariableRuntimeCachePendingUpdate; + SmmRuntimeVarCacheContext->ReadLock = &mVariableRuntimeCacheReadLock; + SmmRuntimeVarCacheContext->HobFlushComplete = &mHobFlushComplete; + + // + // Send data to SMM. + // + Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize); + ASSERT_EFI_ERROR (Status); + if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + Status = SmmVariableFunctionHeader->ReturnStatus; + if (EFI_ERROR (Status)) { + goto Done; + } + +Done: + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); + return Status; +} + /** Initialize variable service and install Variable Architectural protocol. @@ -985,7 +1556,7 @@ SmmVariableReady ( { EFI_STATUS Status; - Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable); + Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable); if (EFI_ERROR (Status)) { return; } @@ -1007,6 +1578,42 @@ SmmVariableReady ( // mVariableBufferPhysical = mVariableBuffer; + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { + DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n")); + // + // Allocate runtime variable cache memory buffers. + // + Status = GetRuntimeCacheInfo ( + &mVariableRuntimeHobCacheBufferSize, + &mVariableRuntimeNvCacheBufferSize, + &mVariableRuntimeVolatileCacheBufferSize, + &mVariableAuthFormat + ); + if (!EFI_ERROR (Status)) { + Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize); + if (!EFI_ERROR (Status)) { + Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize); + if (!EFI_ERROR (Status)) { + Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize); + if (!EFI_ERROR (Status)) { + Status = SendRuntimeVariableCacheContextToSmm (); + if (!EFI_ERROR (Status)) { + SyncRuntimeCache (); + } + } + } + } + if (EFI_ERROR (Status)) { + mVariableRuntimeHobCacheBuffer = NULL; + mVariableRuntimeNvCacheBuffer = NULL; + mVariableRuntimeVolatileCacheBuffer = NULL; + } + } + ASSERT_EFI_ERROR (Status); + } else { + DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n")); + } + gRT->GetVariable = RuntimeServiceGetVariable; gRT->GetNextVariableName = RuntimeServiceGetNextVariableName; gRT->SetVariable = RuntimeServiceSetVariable; diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf index 14894e6f138..59286277339 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf @@ -13,7 +13,7 @@ # may not be modified without authorization. If platform fails to protect these resources, # the authentication service provided in this driver will be broken, and the behavior is undefined. # -# Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -39,6 +39,9 @@ VariableSmmRuntimeDxe.c PrivilegePolymorphic.h Measurement.c + VariableParsing.c + VariableParsing.h + Variable.h [Packages] MdePkg/MdePkg.dec @@ -65,7 +68,21 @@ gEdkiiVariableLockProtocolGuid ## PRODUCES gEdkiiVarCheckProtocolGuid ## PRODUCES +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES + [Guids] + ## PRODUCES ## GUID # Signature of Variable store header + ## CONSUMES ## GUID # Signature of Variable store header + ## SOMETIMES_PRODUCES ## SystemTable + gEfiAuthenticatedVariableGuid + + ## PRODUCES ## GUID # Signature of Variable store header + ## CONSUMES ## GUID # Signature of Variable store header + ## SOMETIMES_PRODUCES ## SystemTable + gEfiVariableGuid + gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event gEfiEventExitBootServicesGuid ## CONSUMES ## Event ## CONSUMES ## GUID # Locate protocol diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf index 21bc81163b8..6e17f6cdf58 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf @@ -45,6 +45,12 @@ Variable.c VariableSmm.c VariableStandaloneMm.c + VariableNonVolatile.c + VariableNonVolatile.h + VariableParsing.c + VariableParsing.h + VariableRuntimeCache.c + VariableRuntimeCache.h VarCheck.c Variable.h PrivilegePolymorphic.h diff --git a/MdePkg/Include/Base.h b/MdePkg/Include/Base.h index 4680e641363..321d729c04b 100644 --- a/MdePkg/Include/Base.h +++ b/MdePkg/Include/Base.h @@ -195,7 +195,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent /// #define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) -#if __APPLE__ +#ifdef __APPLE__ // // Apple extension that is used by the linker to optimize code size // with assembly functions. Put at the end of your .S files @@ -781,11 +781,9 @@ typedef UINTN *BASE_LIST; @return Offset, in bytes, of field. **/ -#ifdef __GNUC__ -#if __GNUC__ >= 4 +#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__) #define OFFSET_OF(TYPE, Field) ((UINTN) __builtin_offsetof(TYPE, Field)) #endif -#endif #ifndef OFFSET_OF #define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field)) @@ -801,7 +799,7 @@ typedef UINTN *BASE_LIST; **/ #ifdef MDE_CPU_EBC #define STATIC_ASSERT(Expression, Message) -#elif _MSC_EXTENSIONS +#elif defined(_MSC_EXTENSIONS) #define STATIC_ASSERT static_assert #else #define STATIC_ASSERT _Static_assert diff --git a/MdePkg/Include/IndustryStandard/AcpiAml.h b/MdePkg/Include/IndustryStandard/AcpiAml.h index 6919622af21..3dd5408b359 100644 --- a/MdePkg/Include/IndustryStandard/AcpiAml.h +++ b/MdePkg/Include/IndustryStandard/AcpiAml.h @@ -2,6 +2,7 @@ This file contains AML code definition in the latest ACPI spec. Copyright (c) 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2019, ARM Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -30,6 +31,7 @@ #define AML_PACKAGE_OP 0x12 #define AML_VAR_PACKAGE_OP 0x13 #define AML_METHOD_OP 0x14 +#define AML_EXTERNAL_OP 0x15 #define AML_DUAL_NAME_PREFIX 0x2e #define AML_MULTI_NAME_PREFIX 0x2f #define AML_NAME_CHAR_A 0x41 diff --git a/MdePkg/Include/IndustryStandard/FirmwareInterfaceTable.h b/MdePkg/Include/IndustryStandard/FirmwareInterfaceTable.h new file mode 100644 index 00000000000..be3e34ae1b2 --- /dev/null +++ b/MdePkg/Include/IndustryStandard/FirmwareInterfaceTable.h @@ -0,0 +1,76 @@ +/** @file + Industry Standard Definitions of Firmware Interface Table BIOS Specification 1.0. + + Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __FIRMWARE_INTERFACE_TABLE_H__ +#define __FIRMWARE_INTERFACE_TABLE_H__ + +// +// FIT Entry type definitions +// +#define FIT_TYPE_00_HEADER 0x00 +#define FIT_TYPE_01_MICROCODE 0x01 +#define FIT_TYPE_02_STARTUP_ACM 0x02 +#define FIT_TYPE_07_BIOS_STARTUP_MODULE 0x07 +#define FIT_TYPE_08_TPM_POLICY 0x08 +#define FIT_TYPE_09_BIOS_POLICY 0x09 +#define FIT_TYPE_0A_TXT_POLICY 0x0A +#define FIT_TYPE_0B_KEY_MANIFEST 0x0B +#define FIT_TYPE_0C_BOOT_POLICY_MANIFEST 0x0C +#define FIT_TYPE_10_CSE_SECURE_BOOT 0x10 +#define FIT_TYPE_2D_TXTSX_POLICY 0x2D +#define FIT_TYPE_2F_JMP_DEBUG_POLICY 0x2F +#define FIT_TYPE_7F_SKIP 0x7F + +#define FIT_POINTER_ADDRESS 0xFFFFFFC0 ///< Fixed address at 4G - 40h + +#define FIT_TYPE_VERSION 0x0100 + +#define FIT_TYPE_00_SIGNATURE SIGNATURE_64 ('_', 'F', 'I', 'T', '_', ' ', ' ', ' ') + +#pragma pack(1) + +typedef struct { + // + // Address is the base address of the firmware component + // must be aligned on 16 byte boundary + // + UINT64 Address; + // + // Size is the span of the component in multiple of 16 bytes + // + UINT8 Size[3]; + // + // Reserved must be set to 0 + // + UINT8 Reserved; + // + // Component's version number in binary coded decimal (BCD) format. + // For the FIT header entry, the value in this field will indicate the revision + // number of the FIT data structure. The upper byte of the revision field + // indicates the major revision and the lower byte indicates the minor revision. + // + UINT16 Version; + // + // FIT types 0x00 to 0x7F + // + UINT8 Type : 7; + // + // Checksum Valid indicates whether component has valid checksum. + // + UINT8 C_V : 1; + // + // Component's checksum. The modulo sum of all the bytes in the component and + // the value in this field (Chksum) must add up to zero. This field is only + // valid if the C_V flag is non-zero. + // + UINT8 Chksum; +} FIRMWARE_INTERFACE_TABLE_ENTRY; + +#pragma pack() + +#endif diff --git a/MdePkg/Include/IndustryStandard/PciExpress21.h b/MdePkg/Include/IndustryStandard/PciExpress21.h index f17f5707755..2c07cb560e9 100644 --- a/MdePkg/Include/IndustryStandard/PciExpress21.h +++ b/MdePkg/Include/IndustryStandard/PciExpress21.h @@ -304,7 +304,7 @@ typedef union { UINT16 AtomicOpEgressBlocking : 1; UINT16 IdoRequest : 1; UINT16 IdoCompletion : 1; - UINT16 LtrMechanism : 2; + UINT16 LtrMechanism : 1; UINT16 EmergencyPowerReductionRequest : 1; UINT16 TenBitTagRequesterEnable : 1; UINT16 Obff : 2; diff --git a/MdePkg/Include/IndustryStandard/SerialPortConsoleRedirectionTable.h b/MdePkg/Include/IndustryStandard/SerialPortConsoleRedirectionTable.h index b069fb2be97..2066c7895e5 100644 --- a/MdePkg/Include/IndustryStandard/SerialPortConsoleRedirectionTable.h +++ b/MdePkg/Include/IndustryStandard/SerialPortConsoleRedirectionTable.h @@ -90,6 +90,16 @@ typedef struct { /// #define EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_ARM_SBSA_GENERIC_UART 0x0e +/// +/// ARM DCC +/// +#define EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_DCC 0x0f + +/// +/// BCM2835 UART +/// +#define EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_BCM2835_UART 0x10 + // // Interrupt Type // diff --git a/MdePkg/Include/IndustryStandard/SmBios.h b/MdePkg/Include/IndustryStandard/SmBios.h index f504cc84e70..8b3c4d7ba9d 100644 --- a/MdePkg/Include/IndustryStandard/SmBios.h +++ b/MdePkg/Include/IndustryStandard/SmBios.h @@ -1,7 +1,7 @@ /** @file Industry Standard Definitions of SMBIOS Table Specification v3.3.0. -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
(C) Copyright 2015-2017 Hewlett Packard Enterprise Development LP
(C) Copyright 2015 - 2019 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -1285,6 +1285,7 @@ typedef enum { SlotTypePciExpressMini52pinWithBSKO = 0x21, ///< PCI Express Mini 52-pin (CEM spec. 2.0) with bottom-side keep-outs. SlotTypePciExpressMini52pinWithoutBSKO = 0x22, ///< PCI Express Mini 52-pin (CEM spec. 2.0) without bottom-side keep-outs. SlotTypePciExpressMini76pin = 0x23, ///< PCI Express Mini 76-pin (CEM spec. 2.0) Corresponds to Display-Mini card. + SlotTypeCXLFlexbus10 = 0x30, SlotTypePC98C20 = 0xA0, SlotTypePC98C24 = 0xA1, SlotTypePC98E = 0xA2, @@ -1307,7 +1308,13 @@ typedef enum { SlotTypePciExpressGen3X2 = 0xB3, SlotTypePciExpressGen3X4 = 0xB4, SlotTypePciExpressGen3X8 = 0xB5, - SlotTypePciExpressGen3X16 = 0xB6 + SlotTypePciExpressGen3X16 = 0xB6, + SlotTypePciExpressGen4 = 0xB8, + SlotTypePciExpressGen4X1 = 0xB9, + SlotTypePciExpressGen4X2 = 0xBA, + SlotTypePciExpressGen4X4 = 0xBB, + SlotTypePciExpressGen4X8 = 0xBC, + SlotTypePciExpressGen4X16 = 0xBD } MISC_SLOT_TYPE; /// @@ -1606,7 +1613,8 @@ typedef enum { MemoryArrayLocationPc98C20AddonCard = 0xA0, MemoryArrayLocationPc98C24AddonCard = 0xA1, MemoryArrayLocationPc98EAddonCard = 0xA2, - MemoryArrayLocationPc98LocalBusAddonCard = 0xA3 + MemoryArrayLocationPc98LocalBusAddonCard = 0xA3, + MemoryArrayLocationCXLFlexbus10AddonCard = 0xA4 } MEMORY_ARRAY_LOCATION; /// @@ -1673,7 +1681,8 @@ typedef enum { MemoryFormFactorRimm = 0x0C, MemoryFormFactorSodimm = 0x0D, MemoryFormFactorSrimm = 0x0E, - MemoryFormFactorFbDimm = 0x0F + MemoryFormFactorFbDimm = 0x0F, + MemoryFormFactorDie = 0x10 } MEMORY_FORM_FACTOR; /// @@ -1707,7 +1716,9 @@ typedef enum { MemoryTypeLpddr2 = 0x1C, MemoryTypeLpddr3 = 0x1D, MemoryTypeLpddr4 = 0x1E, - MemoryTypeLogicalNonVolatileDevice = 0x1F + MemoryTypeLogicalNonVolatileDevice = 0x1F, + MemoryTypeHBM = 0x20, + MemoryTypeHBM2 = 0x21 } MEMORY_DEVICE_TYPE; /// @@ -1742,6 +1753,10 @@ typedef enum { MemoryTechnologyNvdimmN = 0x04, MemoryTechnologyNvdimmF = 0x05, MemoryTechnologyNvdimmP = 0x06, + // + // This definition is updated to represent Intel + // Optane DC Presistent Memory in SMBIOS spec 3.3.0 + // MemoryTechnologyIntelPersistentMemory = 0x07 } MEMORY_DEVICE_TECHNOLOGY; diff --git a/MdePkg/Include/IndustryStandard/Spdm.h b/MdePkg/Include/IndustryStandard/Spdm.h new file mode 100644 index 00000000000..38ec7748a70 --- /dev/null +++ b/MdePkg/Include/IndustryStandard/Spdm.h @@ -0,0 +1,320 @@ +/** @file + Definitions of Security Protocol & Data Model Specification (SPDM) + version 1.0.0 in Distributed Management Task Force (DMTF). + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef __SPDM_H__ +#define __SPDM_H__ + +#pragma pack(1) + +/// +/// SPDM response code +/// +#define SPDM_DIGESTS 0x01 +#define SPDM_CERTIFICATE 0x02 +#define SPDM_CHALLENGE_AUTH 0x03 +#define SPDM_VERSION 0x04 +#define SPDM_MEASUREMENTS 0x60 +#define SPDM_CAPABILITIES 0x61 +#define SPDM_SET_CERT_RESPONSE 0x62 +#define SPDM_ALGORITHMS 0x63 +#define SPDM_ERROR 0x7F +/// +/// SPDM request code +/// +#define SPDM_GET_DIGESTS 0x81 +#define SPDM_GET_CERTIFICATE 0x82 +#define SPDM_CHALLENGE 0x83 +#define SPDM_GET_VERSION 0x84 +#define SPDM_GET_MEASUREMENTS 0xE0 +#define SPDM_GET_CAPABILITIES 0xE1 +#define SPDM_NEGOTIATE_ALGORITHMS 0xE3 +#define SPDM_RESPOND_IF_READY 0xFF + +/// +/// SPDM message header +/// +typedef struct { + UINT8 SPDMVersion; + UINT8 RequestResponseCode; + UINT8 Param1; + UINT8 Param2; +} SPDM_MESSAGE_HEADER; + +#define SPDM_MESSAGE_VERSION 0x10 + +/// +/// SPDM GET_VERSION request +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; +} SPDM_GET_VERSION_REQUEST; + +/// +/// SPDM GET_VERSION response +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + UINT8 Reserved; + UINT8 VersionNumberEntryCount; +//SPDM_VERSION_NUMBER VersionNumberEntry[VersionNumberEntryCount]; +} SPDM_VERSION_RESPONSE; + +/// +/// SPDM VERSION structure +/// +typedef struct { + UINT16 Alpha:4; + UINT16 UpdateVersionNumber:4; + UINT16 MinorVersion:4; + UINT16 MajorVersion:4; +} SPDM_VERSION_NUMBER; + +/// +/// SPDM GET_CAPABILITIES request +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; +} SPDM_GET_CAPABILITIES_REQUEST; + +/// +/// SPDM GET_CAPABILITIES response +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + UINT8 Reserved; + UINT8 CTExponent; + UINT16 Reserved2; + UINT32 Flags; +} SPDM_CAPABILITIES_RESPONSE; + +/// +/// SPDM GET_CAPABILITIES response Flags +/// +#define SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CACHE_CAP BIT0 +#define SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP BIT1 +#define SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHAL_CAP BIT2 +#define SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP (BIT3 | BIT4) +#define SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_NO_SIG BIT3 +#define SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG BIT4 +#define SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_FRESH_CAP BIT5 + +/// +/// SPDM NEGOTIATE_ALGORITHMS request +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + UINT16 Length; + UINT8 MeasurementSpecification; + UINT8 Reserved; + UINT32 BaseAsymAlgo; + UINT32 BaseHashAlgo; + UINT8 Reserved2[12]; + UINT8 ExtAsymCount; + UINT8 ExtHashCount; + UINT16 Reserved3; +//UINT32 ExtAsym[ExtAsymCount]; +//UINT32 ExtHash[ExtHashCount]; +} SPDM_NEGOTIATE_ALGORITHMS_REQUEST; + +/// +/// SPDM NEGOTIATE_ALGORITHMS request BaseAsymAlgo +/// +#define SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048 BIT0 +#define SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048 BIT1 +#define SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072 BIT2 +#define SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072 BIT3 +#define SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256 BIT4 +#define SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096 BIT5 +#define SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096 BIT6 +#define SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384 BIT7 +#define SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521 BIT8 + +/// +/// SPDM NEGOTIATE_ALGORITHMS request BaseHashAlgo +/// +#define SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256 BIT0 +#define SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384 BIT1 +#define SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_512 BIT2 +#define SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA3_256 BIT3 +#define SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA3_384 BIT4 +#define SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA3_512 BIT5 + +/// +/// SPDM NEGOTIATE_ALGORITHMS response +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + UINT16 Length; + UINT8 MeasurementSpecificationSel; + UINT8 Reserved; + UINT32 MeasurementHashAlgo; + UINT32 BaseAsymSel; + UINT32 BaseHashSel; + UINT8 Reserved2[12]; + UINT8 ExtAsymSelCount; + UINT8 ExtHashSelCount; + UINT16 Reserved3; +//UINT32 ExtAsymSel[ExtAsymSelCount]; +//UINT32 ExtHashSel[ExtHashSelCount]; +} SPDM_ALGORITHMS_RESPONSE; + +/// +/// SPDM NEGOTIATE_ALGORITHMS response MeasurementHashAlgo +/// +#define SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_RAW_BIT_STREAM_ONLY BIT0 +#define SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_256 BIT1 +#define SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_384 BIT2 +#define SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_512 BIT3 +#define SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA3_256 BIT4 +#define SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA3_384 BIT5 +#define SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA3_512 BIT6 + +/// +/// SPDM GET_DIGESTS request +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; +} SPDM_GET_DIGESTS_REQUEST; + +/// +/// SPDM GET_DIGESTS response +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; +//UINT8 Digest[DigestSize]; +} SPDM_DIGESTS_RESPONSE; + +/// +/// SPDM GET_DIGESTS request +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + UINT16 Offset; + UINT16 Length; +} SPDM_GET_CERTIFICATE_REQUEST; + +/// +/// SPDM GET_DIGESTS response +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + UINT16 PortionLength; + UINT16 RemainderLength; +//UINT8 CertChain[CertChainSize]; +} SPDM_CERTIFICATE_RESPONSE; + +/// +/// SPDM CHALLENGE request +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + UINT8 Nonce[32]; +} SPDM_CHALLENGE_REQUEST; + +/// +/// SPDM CHALLENGE response +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; +//UINT8 CertChainHash[DigestSize]; +//UINT8 Nonce[32]; +//UINT8 MeasurementSummaryHash[DigestSize]; +//UINT16 OpaqueLength; +//UINT8 OpaqueData[OpaqueLength]; +//UINT8 Signature[KeySize]; +} SPDM_CHALLENGE_AUTH_RESPONSE; + +/// +/// SPDM GET_MEASUREMENTS request +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + UINT8 Nonce[32]; +} SPDM_GET_MEASUREMENTS_REQUEST; + +/// +/// SPDM MEASUREMENTS block common header +/// +typedef struct { + UINT8 Index; + UINT8 MeasurementSpecification; + UINT16 MeasurementSize; +//UINT8 Measurement[MeasurementSize]; +} SPDM_MEASUREMENT_BLOCK_COMMON_HEADER; + +#define SPDM_MEASUREMENT_BLOCK_HEADER_SPECIFICATION_DMTF BIT0 + +/// +/// SPDM MEASUREMENTS block DMTF header +/// +typedef struct { + UINT8 DMTFSpecMeasurementValueType; + UINT16 DMTFSpecMeasurementValueSize; +//UINT8 DMTFSpecMeasurementValue[DMTFSpecMeasurementValueSize]; +} SPDM_MEASUREMENT_BLOCK_DMTF_HEADER; + +/// +/// SPDM MEASUREMENTS block MeasurementValueType +/// +#define SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_IMMUTABLE_ROM 0 +#define SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_MUTABLE_FIRMWARE 1 +#define SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_HARDWARE_CONFIGURATION 2 +#define SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_FIRMWARE_CONFIGURATION 3 +#define SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_RAW_BIT_STREAM BIT7 + +/// +/// SPDM GET_MEASUREMENTS response +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + UINT8 NumberOfBlocks; + UINT8 MeasurementRecordLength[3]; +//UINT8 MeasurementRecord[MeasurementRecordLength]; +//UINT8 Nonce[32]; +//UINT16 OpaqueLength; +//UINT8 OpaqueData[OpaqueLength]; +//UINT8 Signature[KeySize]; +} SPDM_MEASUREMENTS_RESPONSE; + +/// +/// SPDM ERROR response +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + // Param1 == Error Code + // Param2 == Error Data +//UINT8 ExtendedErrorData[]; +} SPDM_ERROR_RESPONSE; + +/// +/// SPDM error code +/// +#define SPDM_ERROR_CODE_INVALID_REQUEST 0x01 +#define SPDM_ERROR_CODE_BUSY 0x03 +#define SPDM_ERROR_CODE_UNEXPECTED_REQUEST 0x04 +#define SPDM_ERROR_CODE_UNSPECIFIED 0x05 +#define SPDM_ERROR_CODE_UNSUPPORTED_REQUEST 0x07 +#define SPDM_ERROR_CODE_MAJOR_VERSION_MISMATCH 0x41 +#define SPDM_ERROR_CODE_RESPONSE_NOT_READY 0x42 +#define SPDM_ERROR_CODE_REQUEST_RESYNCH 0x43 + +/// +/// SPDM RESPONSE_IF_READY request +/// +typedef struct { + SPDM_MESSAGE_HEADER Header; + // Param1 == RequestCode + // Param2 == Token +} SPDM_RESPONSE_IF_READY_REQUEST; + +#pragma pack() + +#endif + diff --git a/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h index 3f1d444aed0..84023c43476 100644 --- a/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h +++ b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h @@ -1,7 +1,8 @@ /** @file - TCG EFI Platform Definition in TCG_EFI_Platform_1_20_Final + TCG EFI Platform Definition in TCG_EFI_Platform_1_20_Final and + TCG PC Client Platform Firmware Profile Specification, Revision 1.05 - Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -21,6 +22,7 @@ #define EV_NO_ACTION ((TCG_EVENTTYPE) 0x00000003) #define EV_SEPARATOR ((TCG_EVENTTYPE) 0x00000004) #define EV_ACTION ((TCG_EVENTTYPE) 0x00000005) +#define EV_EVENT_TAG ((TCG_EVENTTYPE) 0x00000006) #define EV_S_CRTM_CONTENTS ((TCG_EVENTTYPE) 0x00000007) #define EV_S_CRTM_VERSION ((TCG_EVENTTYPE) 0x00000008) #define EV_CPU_MICROCODE ((TCG_EVENTTYPE) 0x00000009) @@ -45,8 +47,12 @@ #define EV_EFI_ACTION (EV_EFI_EVENT_BASE + 7) #define EV_EFI_PLATFORM_FIRMWARE_BLOB (EV_EFI_EVENT_BASE + 8) #define EV_EFI_HANDOFF_TABLES (EV_EFI_EVENT_BASE + 9) +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2 (EV_EFI_EVENT_BASE + 0xA) +#define EV_EFI_HANDOFF_TABLES2 (EV_EFI_EVENT_BASE + 0xB) #define EV_EFI_HCRTM_EVENT (EV_EFI_EVENT_BASE + 0x10) #define EV_EFI_VARIABLE_AUTHORITY (EV_EFI_EVENT_BASE + 0xE0) +#define EV_EFI_SPDM_FIRMWARE_BLOB (EV_EFI_EVENT_BASE + 0xE1) +#define EV_EFI_SPDM_FIRMWARE_CONFIG (EV_EFI_EVENT_BASE + 0xE2) #define EFI_CALLING_EFI_APPLICATION \ "Calling EFI Application from Boot Option" @@ -78,6 +84,9 @@ #define EV_POSTCODE_INFO_OPROM "Embedded Option ROM" #define OPROM_LEN (sizeof(EV_POSTCODE_INFO_OPROM) - 1) +#define EV_POSTCODE_INFO_EMBEDDED_UEFI_DRIVER "Embedded UEFI Driver" +#define EMBEDDED_UEFI_DRIVER_LEN (sizeof(EV_POSTCODE_INFO_EMBEDDED_UEFI_DRIVER) - 1) + #define FIRMWARE_DEBUGGER_EVENT_STRING "UEFI Debug Mode" #define FIRMWARE_DEBUGGER_EVENT_STRING_LEN (sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1) @@ -123,6 +132,30 @@ typedef struct tdEFI_PLATFORM_FIRMWARE_BLOB { UINT64 BlobLength; } EFI_PLATFORM_FIRMWARE_BLOB; +/// +/// UEFI_PLATFORM_FIRMWARE_BLOB +/// +/// This structure is used in EV_EFI_PLATFORM_FIRMWARE_BLOB +/// event to facilitate the measurement of firmware volume. +/// +typedef struct tdUEFI_PLATFORM_FIRMWARE_BLOB { + EFI_PHYSICAL_ADDRESS BlobBase; + UINT64 BlobLength; +} UEFI_PLATFORM_FIRMWARE_BLOB; + +/// +/// UEFI_PLATFORM_FIRMWARE_BLOB2 +/// +/// This structure is used in EV_EFI_PLATFORM_FIRMWARE_BLOB2 +/// event to facilitate the measurement of firmware volume. +/// +typedef struct tdUEFI_PLATFORM_FIRMWARE_BLOB2 { + UINT8 BlobDescriptionSize; +//UINT8 BlobDescription[BlobDescriptionSize]; +//EFI_PHYSICAL_ADDRESS BlobBase; +//UINT64 BlobLength; +} UEFI_PLATFORM_FIRMWARE_BLOB2; + /// /// EFI_IMAGE_LOAD_EVENT /// @@ -137,6 +170,20 @@ typedef struct tdEFI_IMAGE_LOAD_EVENT { EFI_DEVICE_PATH_PROTOCOL DevicePath[1]; } EFI_IMAGE_LOAD_EVENT; +/// +/// UEFI_IMAGE_LOAD_EVENT +/// +/// This structure is used in EV_EFI_BOOT_SERVICES_APPLICATION, +/// EV_EFI_BOOT_SERVICES_DRIVER and EV_EFI_RUNTIME_SERVICES_DRIVER +/// +typedef struct tdUEFI_IMAGE_LOAD_EVENT { + EFI_PHYSICAL_ADDRESS ImageLocationInMemory; + UINT64 ImageLengthInMemory; + UINT64 ImageLinkTimeAddress; + UINT64 LengthOfDevicePath; + EFI_DEVICE_PATH_PROTOCOL DevicePath[1]; +} UEFI_IMAGE_LOAD_EVENT; + /// /// EFI_HANDOFF_TABLE_POINTERS /// @@ -148,6 +195,30 @@ typedef struct tdEFI_HANDOFF_TABLE_POINTERS { EFI_CONFIGURATION_TABLE TableEntry[1]; } EFI_HANDOFF_TABLE_POINTERS; +/// +/// UEFI_HANDOFF_TABLE_POINTERS +/// +/// This structure is used in EV_EFI_HANDOFF_TABLES event to facilitate +/// the measurement of given configuration tables. +/// +typedef struct tdUEFI_HANDOFF_TABLE_POINTERS { + UINT64 NumberOfTables; + EFI_CONFIGURATION_TABLE TableEntry[1]; +} UEFI_HANDOFF_TABLE_POINTERS; + +/// +/// UEFI_HANDOFF_TABLE_POINTERS2 +/// +/// This structure is used in EV_EFI_HANDOFF_TABLES2 event to facilitate +/// the measurement of given configuration tables. +/// +typedef struct tdUEFI_HANDOFF_TABLE_POINTERS2 { + UINT8 TableDescriptionSize; +//UINT8 TableDescription[TableDescriptionSize]; +//UINT64 NumberOfTables; +//EFI_CONFIGURATION_TABLE TableEntry[1]; +} UEFI_HANDOFF_TABLE_POINTERS2; + /// /// EFI_VARIABLE_DATA /// @@ -197,6 +268,66 @@ typedef struct tdEFI_GPT_DATA { EFI_PARTITION_ENTRY Partitions[1]; } EFI_GPT_DATA; +typedef struct tdUEFI_GPT_DATA { + EFI_PARTITION_TABLE_HEADER EfiPartitionHeader; + UINT64 NumberOfPartitions; + EFI_PARTITION_ENTRY Partitions[1]; +} UEFI_GPT_DATA; + +#define TCG_DEVICE_SECURITY_EVENT_DATA_SIGNATURE "SPDM Device Sec" +#define TCG_DEVICE_SECURITY_EVENT_DATA_VERSION 0 + +#define TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_NULL 0 +#define TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_PCI 1 +#define TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_USB 2 + +/// +/// TCG_DEVICE_SECURITY_EVENT_DATA_HEADER +/// This is the header of TCG_DEVICE_SECURITY_EVENT_DATA, which is +/// used in EV_EFI_SPDM_FIRMWARE_BLOB and EV_EFI_SPDM_FIRMWARE_CONFIG. +/// +typedef struct { + UINT8 Signature[16]; + UINT16 Version; + UINT16 Length; + UINT32 SpdmHashAlgo; + UINT32 DeviceType; +//SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock; +} TCG_DEVICE_SECURITY_EVENT_DATA_HEADER; + +#define TCG_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT_VERSION 0 + +/// +/// TCG_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT +/// This is the PCI context data of TCG_DEVICE_SECURITY_EVENT_DATA, which is +/// used in EV_EFI_SPDM_FIRMWARE_BLOB and EV_EFI_SPDM_FIRMWARE_CONFIG. +/// +typedef struct { + UINT16 Version; + UINT16 Length; + UINT16 VendorId; + UINT16 DeviceId; + UINT8 RevisionID; + UINT8 ClassCode[3]; + UINT16 SubsystemVendorID; + UINT16 SubsystemID; +} TCG_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT; + +#define TCG_DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT_VERSION 0 + +/// +/// TCG_DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT +/// This is the USB context data of TCG_DEVICE_SECURITY_EVENT_DATA, which is +/// used in EV_EFI_SPDM_FIRMWARE_BLOB and EV_EFI_SPDM_FIRMWARE_CONFIG. +/// +typedef struct { + UINT16 Version; + UINT16 Length; +//UINT8 DeviceDescriptor[DescLen]; +//UINT8 BodDescriptor[DescLen]; +//UINT8 ConfigurationDescriptor[DescLen][NumOfConfiguration]; +} TCG_DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT; + // // Crypto Agile Log Entry Format // @@ -243,6 +374,7 @@ typedef struct { #define TCG_EfiSpecIDEventStruct_SPEC_VERSION_MAJOR_TPM2 2 #define TCG_EfiSpecIDEventStruct_SPEC_VERSION_MINOR_TPM2 0 #define TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2 0 +#define TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2_REV_105 105 typedef struct { UINT8 signature[16]; @@ -299,20 +431,52 @@ typedef struct { //UINT8 vendorInfo[vendorInfoSize]; } TCG_EfiSpecIDEventStruct; +typedef struct tdTCG_PCClientTaggedEvent { + UINT32 taggedEventID; + UINT32 taggedEventDataSize; +//UINT8 taggedEventData[taggedEventDataSize]; +} TCG_PCClientTaggedEvent; + +#define TCG_Sp800_155_PlatformId_Event_SIGNATURE "SP800-155 Event" +#define TCG_Sp800_155_PlatformId_Event2_SIGNATURE "SP800-155 Event2" +typedef struct tdTCG_Sp800_155_PlatformId_Event2 { + UINT8 Signature[16]; + // + // Where Vendor ID is an integer defined + // at http://www.iana.org/assignments/enterprisenumbers + // + UINT32 VendorId; + // + // 16-byte identifier of a given platform's static configuration of code + // + EFI_GUID ReferenceManifestGuid; + // + // Below structure is newly added in TCG_Sp800_155_PlatformId_Event2. + // +//UINT8 PlatformManufacturerStrSize; +//UINT8 PlatformManufacturerStr[PlatformManufacturerStrSize]; +//UINT8 PlatformModelSize; +//UINT8 PlatformModel[PlatformModelSize]; +//UINT8 PlatformVersionSize; +//UINT8 PlatformVersion[PlatformVersionSize]; +//UINT8 PlatformModelSize; +//UINT8 PlatformModel[PlatformModelSize]; +//UINT8 FirmwareManufacturerStrSize; +//UINT8 FirmwareManufacturerStr[FirmwareManufacturerStrSize]; +//UINT32 FirmwareManufacturerId; +//UINT8 FirmwareVersion; +//UINT8 FirmwareVersion[FirmwareVersionSize]]; +} TCG_Sp800_155_PlatformId_Event2; #define TCG_EfiStartupLocalityEvent_SIGNATURE "StartupLocality" // -// PC Client PTP spec Table 8 Relationship between Locality and Locality Attribute +// The Locality Indicator which sent the TPM2_Startup command // -#define LOCALITY_0_INDICATOR 0x01 -#define LOCALITY_1_INDICATOR 0x02 -#define LOCALITY_2_INDICATOR 0x03 -#define LOCALITY_3_INDICATOR 0x04 -#define LOCALITY_4_INDICATOR 0x05 - +#define LOCALITY_0_INDICATOR 0x00 +#define LOCALITY_3_INDICATOR 0x03 // // Startup Locality Event diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h index 2a75bc023f5..ecadff8b235 100644 --- a/MdePkg/Include/Library/BaseLib.h +++ b/MdePkg/Include/Library/BaseLib.h @@ -5387,10 +5387,19 @@ typedef union { UINT32 OSXMMEXCPT:1; ///< Operating System Support for ///< Unmasked SIMD Floating Point ///< Exceptions. - UINT32 Reserved_2:1; ///< Reserved. + UINT32 UMIP:1; ///< User-Mode Instruction Prevention. UINT32 LA57:1; ///< Linear Address 57bit. - UINT32 VMXE:1; ///< VMX Enable - UINT32 Reserved_1:18; ///< Reserved. + UINT32 VMXE:1; ///< VMX Enable. + UINT32 SMXE:1; ///< SMX Enable. + UINT32 Reserved_3:1; ///< Reserved. + UINT32 FSGSBASE:1; ///< FSGSBASE Enable. + UINT32 PCIDE:1; ///< PCID Enable. + UINT32 OSXSAVE:1; ///< XSAVE and Processor Extended States Enable. + UINT32 Reserved_4:1; ///< Reserved. + UINT32 SMEP:1; ///< SMEP Enable. + UINT32 SMAP:1; ///< SMAP Enable. + UINT32 PKE:1; ///< Protection-Key Enable. + UINT32 Reserved_5:9; ///< Reserved. } Bits; UINTN UintN; } IA32_CR4; diff --git a/MdePkg/Include/Library/UefiLib.h b/MdePkg/Include/Library/UefiLib.h index 67c6f96747c..0abb40d6ecb 100644 --- a/MdePkg/Include/Library/UefiLib.h +++ b/MdePkg/Include/Library/UefiLib.h @@ -462,15 +462,16 @@ EfiTestChildHandle ( ); /** - * This function checks the supported languages list for a target language, - * This only supports RFC 4646 Languages. - * - * @param SupportedLanguages The supported languages - * @param TargetLanguage The target language - * - * @return Returns EFI_SUCCESS if the language is supported, - * EFI_UNSUPPORTED otherwise - */ + This function checks the supported languages list for a target language, + This only supports RFC 4646 Languages. + + @param SupportedLanguages The supported languages + @param TargetLanguage The target language + + @retval Returns EFI_SUCCESS if the language is supported, + EFI_UNSUPPORTED otherwise + +**/ EFI_STATUS EFIAPI IsLanguageSupported ( diff --git a/MdePkg/Include/Library/UnitTestLib.h b/MdePkg/Include/Library/UnitTestLib.h new file mode 100644 index 00000000000..74a61caf4cb --- /dev/null +++ b/MdePkg/Include/Library/UnitTestLib.h @@ -0,0 +1,757 @@ +/** @file + Provides a unit test framework. This allows tests to focus on testing logic + and the framework to focus on runnings, reporting, statistics, etc. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef __UNIT_TEST_LIB_H__ +#define __UNIT_TEST_LIB_H__ + +/// +/// Unit Test Status +/// +typedef UINT32 UNIT_TEST_STATUS; +#define UNIT_TEST_PASSED (0) +#define UNIT_TEST_ERROR_PREREQUISITE_NOT_MET (1) +#define UNIT_TEST_ERROR_TEST_FAILED (2) +#define UNIT_TEST_ERROR_CLEANUP_FAILED (3) +#define UNIT_TEST_SKIPPED (0xFFFFFFFD) +#define UNIT_TEST_RUNNING (0xFFFFFFFE) +#define UNIT_TEST_PENDING (0xFFFFFFFF) + +/// +/// Declare PcdUnitTestLogLevel bits and UnitTestLog() ErrorLevel parameter. +/// +#define UNIT_TEST_LOG_LEVEL_ERROR BIT0 +#define UNIT_TEST_LOG_LEVEL_WARN BIT1 +#define UNIT_TEST_LOG_LEVEL_INFO BIT2 +#define UNIT_TEST_LOG_LEVEL_VERBOSE BIT3 + +/// +/// Unit Test Framework Handle +/// +struct UNIT_TEST_FRAMEWORK_OBJECT; +typedef struct UNIT_TEST_FRAMEWORK_OBJECT *UNIT_TEST_FRAMEWORK_HANDLE; + +/// +/// Unit Test Suite Handle +/// +struct UNIT_TEST_SUITE_OBJECT; +typedef struct UNIT_TEST_SUITE_OBJECT *UNIT_TEST_SUITE_HANDLE; + +/// +/// Unit Test Handle +/// +struct UNIT_TEST_OBJECT; +typedef struct UNIT_TEST_OBJECT *UNIT_TEST_HANDLE; + +/// +/// Unit Test Context +/// +typedef VOID* UNIT_TEST_CONTEXT; + +/** + The prototype for a single UnitTest case function. + + Funtions with this prototype are registered to be dispatched by the + UnitTest framework, and results are recorded as test Pass or Fail. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. + +**/ +typedef +UNIT_TEST_STATUS +(EFIAPI *UNIT_TEST_FUNCTION)( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit-Test Prerequisite Function pointer type. + + Funtions with this prototype are registered to be dispatched by the unit test + framework prior to a given test case. If this prereq function returns + UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, the test case will be skipped. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED Unit test case prerequisites + are met. + @retval UNIT_TEST_ERROR_PREREQUISITE_NOT_MET Test case should be skipped. + +**/ +typedef +UNIT_TEST_STATUS +(EFIAPI *UNIT_TEST_PREREQUISITE)( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit-Test Cleanup (after) function pointer type. + + Funtions with this prototype are registered to be dispatched by the + unit test framework after a given test case. This will be called even if the + test case returns an error, but not if the prerequisite fails and the test is + skipped. The purpose of this function is to clean up any global state or + test data. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED Test case cleanup succeeded. + @retval UNIT_TEST_ERROR_CLEANUP_FAILED Test case cleanup failed. + +**/ +typedef +VOID +(EFIAPI *UNIT_TEST_CLEANUP)( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit-Test Test Suite Setup (before) function pointer type. Funtions with this + prototype are registered to be dispatched by the UnitTest framework prior to + running any of the test cases in a test suite. It will only be run once at + the beginning of the suite (not prior to each case). + + The purpose of this function is to set up any global state or test data. +**/ +typedef +VOID +(EFIAPI *UNIT_TEST_SUITE_SETUP)( + VOID + ); + +/** + Unit-Test Test Suite Teardown (after) function pointer type. Funtions with + this prototype are registered to be dispatched by the UnitTest framework after + running all of the test cases in a test suite. It will only be run once at + the end of the suite. + + The purpose of this function is to clean up any global state or test data. +**/ +typedef +VOID +(EFIAPI *UNIT_TEST_SUITE_TEARDOWN)( + VOID + ); + +/** + Method to Initialize the Unit Test framework. This function registers the + test name and also initializes the internal state of the test framework to + receive any new suites and tests. + + @param[out] FrameworkHandle Unit test framework to be created. + @param[in] Title Null-terminated ASCII string that is the user + friendly name of the framework. String is + copied. + @param[in] ShortTitle Null-terminaled ASCII short string that is the + short name of the framework with no spaces. + String is copied. + @param[in] VersionString Null-terminaled ASCII version string for the + framework. String is copied. + + @retval EFI_SUCCESS The unit test framework was initialized. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is NULL. + @retval EFI_INVALID_PARAMETER VersionString is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is invalid. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + initialize the unit test framework. +**/ +EFI_STATUS +EFIAPI +InitUnitTestFramework ( + OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *ShortTitle, + IN CHAR8 *VersionString + ); + +/** + Registers a Unit Test Suite in the Unit Test Framework. + At least one test suite must be registered, because all test cases must be + within a unit test suite. + + @param[out] SuiteHandle Unit test suite to create + @param[in] FrameworkHandle Unit test framework to add unit test suite to + @param[in] Title Null-terminated ASCII string that is the user + friendly name of the test suite. String is + copied. + @param[in] Name Null-terminated ASCII string that is the short + name of the test suite with no spaces. String + is copied. + @param[in] Setup Setup function, runs before suite. This is an + optional parameter that may be NULL. + @param[in] Teardown Teardown function, runs after suite. This is an + optional parameter that may be NULL. + + @retval EFI_SUCCESS The unit test suite was created. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + initialize the unit test suite. +**/ +EFI_STATUS +EFIAPI +CreateUnitTestSuite ( + OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle, + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *Name, + IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL, + IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL + ); + +/** + Adds test case to Suite + + @param[in] SuiteHandle Unit test suite to add test to. + @param[in] Description Null-terminated ASCII string that is the user + friendly description of a test. String is copied. + @param[in] Name Null-terminated ASCII string that is the short name + of the test with no spaces. String is copied. + @param[in] Function Unit test function. + @param[in] Prerequisite Prerequisite function, runs before test. This is + an optional parameter that may be NULL. + @param[in] CleanUp Clean up function, runs after test. This is an + optional parameter that may be NULL. + @param[in] Context Pointer to context. This is an optional parameter + that may be NULL. + + @retval EFI_SUCCESS The unit test case was added to Suite. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER Description is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_INVALID_PARAMETER Function is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + add the unit test case to Suite. +**/ +EFI_STATUS +EFIAPI +AddTestCase ( + IN UNIT_TEST_SUITE_HANDLE SuiteHandle, + IN CHAR8 *Description, + IN CHAR8 *Name, + IN UNIT_TEST_FUNCTION Function, + IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL, + IN UNIT_TEST_CLEANUP CleanUp OPTIONAL, + IN UNIT_TEST_CONTEXT Context OPTIONAL + ); + +/** + Execute all unit test cases in all unit test suites added to a Framework. + + Once a unit test framework is initialized and all unit test suites and unit + test cases are registered, this function will cause the unit test framework to + dispatch all unit test cases in sequence and record the results for reporting. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + + @retval EFI_SUCCESS All test cases were dispached. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +RunAllTestSuites ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ); + +/** + Cleanup a test framework. + + After tests are run, this will teardown the entire framework and free all + allocated data within. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + + @retval EFI_SUCCESS All resources associated with framework were + freed. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +FreeUnitTestFramework ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ); + +/** + Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're + a framework author) to save the state of the executing framework along with + any allocated data so that the test may be resumed upon reentry. A test case + should pass any needed context (which, to prevent an infinite loop, should be + at least the current execution count) which will be saved by the framework and + passed to the test case upon resume. + + Generally called from within a test case prior to quitting or rebooting. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + @param[in] ContextToSave A buffer of test case-specific data to be saved + along with framework state. Will be passed as + "Context" to the test case upon resume. This + is an optional parameter that may be NULL. + @param[in] ContextToSaveSize Size of the ContextToSave buffer. + + @retval EFI_SUCCESS The framework state and context were saved. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and + ContextToSaveSize is 0. + @retval EFI_INVALID_PARAMETER ContextToSave is >= 4GB. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + save the framework and context state. + @retval EFI_DEVICE_ERROR The framework and context state could not be + saved to a persistent storage devide due to a + device error. +**/ +EFI_STATUS +EFIAPI +SaveFrameworkState ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize + ); + +/** + This macro uses the framework assertion logic to check an expression for + "TRUE". If the expression evaluates to TRUE, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Expression Expression to be evaluated for TRUE. +**/ +#define UT_ASSERT_TRUE(Expression) \ + if(!UnitTestAssertTrue ((Expression), __FUNCTION__, __LINE__, __FILE__, #Expression)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; \ + } + +/** + This macro uses the framework assertion logic to check an expression for + "FALSE". If the expression evaluates to FALSE, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Expression Expression to be evaluated for FALSE. +**/ +#define UT_ASSERT_FALSE(Expression) \ + if(!UnitTestAssertFalse ((Expression), __FUNCTION__, __LINE__, __FILE__, #Expression)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; \ + } + +/** + This macro uses the framework assertion logic to check whether two simple + values are equal. If the values are equal, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] ValueA Value to be compared for equality (64-bit comparison). + @param[in] ValueB Value to be compared for equality (64-bit comparison). +**/ +#define UT_ASSERT_EQUAL(ValueA, ValueB) \ + if(!UnitTestAssertEqual ((UINT64)(ValueA), (UINT64)(ValueB), __FUNCTION__, __LINE__, __FILE__, #ValueA, #ValueB)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; \ + } + +/** + This macro uses the framework assertion logic to check whether two memory + buffers are equal. If the buffers are equal, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and BufferB. +**/ +#define UT_ASSERT_MEM_EQUAL(BufferA, BufferB, Length) \ + if(!UnitTestAssertMemEqual ((VOID *)(UINTN)(BufferA), (VOID *)(UINTN)(BufferB), (UINTN)Length, __FUNCTION__, __LINE__, __FILE__, #BufferA, #BufferB)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; \ + } + +/** + This macro uses the framework assertion logic to check whether two simple + values are non-equal. If the values are non-equal, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] ValueA Value to be compared for inequality (64-bit comparison). + @param[in] ValueB Value to be compared for inequality (64-bit comparison). +**/ +#define UT_ASSERT_NOT_EQUAL(ValueA, ValueB) \ + if(!UnitTestAssertNotEqual ((UINT64)(ValueA), (UINT64)(ValueB), __FUNCTION__, __LINE__, __FILE__, #ValueA, #ValueB)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; \ + } + +/** + This macro uses the framework assertion logic to check whether an EFI_STATUS + value is !EFI_ERROR(). If the status is !EFI_ERROR(), execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Status EFI_STATUS value to check. +**/ +#define UT_ASSERT_NOT_EFI_ERROR(Status) \ + if(!UnitTestAssertNotEfiError ((Status), __FUNCTION__, __LINE__, __FILE__, #Status)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; \ + } + +/** + This macro uses the framework assertion logic to check whether two EFI_STATUS + values are equal. If the values are equal, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Status EFI_STATUS values to compare for equality. + @param[in] Expected EFI_STATUS values to compare for equality. +**/ +#define UT_ASSERT_STATUS_EQUAL(Status, Expected) \ + if(!UnitTestAssertStatusEqual ((Status), (Expected), __FUNCTION__, __LINE__, __FILE__, #Status)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; \ + } + +/** + This macro uses the framework assertion logic to check whether a pointer is + not NULL. If the pointer is not NULL, execution continues. Otherwise, the + test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Pointer Pointer to be checked against NULL. +**/ +#define UT_ASSERT_NOT_NULL(Pointer) \ + if(!UnitTestAssertNotNull ((Pointer), __FUNCTION__, __LINE__, __FILE__, #Pointer)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; \ + } + +/** + If Expression is TRUE, then TRUE is returned. + If Expression is FALSE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is TRUE. + @retval FALSE Expression is FALSE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ); + +/** + If Expression is FALSE, then TRUE is returned. + If Expression is TRUE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is FALSE. + @retval FALSE Expression is TRUE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ); + +/** + If Status is not an EFI_ERROR(), then TRUE is returned. + If Status is an EFI_ERROR(), then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Status The EFI_STATUS value to evaluate. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the status + expression being evaluated. + + @retval TRUE Status is not an EFI_ERROR(). + @retval FALSE Status is an EFI_ERROR(). +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ); + +/** + If ValueA is equal ValueB, then TRUE is returned. + If ValueA is not equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA, + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is equal to ValueB. + @retval FALSE ValueA is not equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ); + +/** + If the contents of BufferA are identical to the contents of BufferB, then TRUE + is returned. If the contents of BufferA are not identical to the contents of + BufferB, then an assert is triggered and the location of the assert provided + by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are + recorded and FALSE is returned. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and BufferB. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of BufferA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of BufferB. + + @retval TRUE The contents of BufferA are identical to the contents of + BufferB. + @retval FALSE The contents of BufferA are not identical to the contents of + BufferB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertMemEqual ( + IN VOID *BufferA, + IN VOID *BufferB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ); + +/** + If ValueA is not equal ValueB, then TRUE is returned. + If ValueA is equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is not equal to ValueB. + @retval FALSE ValueA is equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ); + +/** + If Status is equal to Expected, then TRUE is returned. + If Status is not equal to Expected, then an assert is triggered and the + location of the assert provided by FunctionName, LineNumber, FileName, and + Description are recorded and FALSE is returned. + + @param[in] Status EFI_STATUS value returned from an API under test. + @param[in] Expected The expected EFI_STATUS return value from an API + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string that is a description + of Status. + + @retval TRUE Status is equal to Expected. + @retval FALSE Status is not equal to Expected. +**/ +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ); + +/** + If Pointer is not equal to NULL, then TRUE is returned. + If Pointer is equal to NULL, then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and PointerName + are recorded and FALSE is returned. + + @param[in] Pointer Pointer value to be checked against NULL. + @param[in] Expected The expected EFI_STATUS return value from a function + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] PointerName Null-terminated ASCII string that is a description + of Pointer. + + @retval TRUE Pointer is not equal to NULL. + @retval FALSE Pointer is equal to NULL. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotNull ( + IN VOID *Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *PointerName + ); + +/** + Test logging macro that records an ERROR message in the test framework log. + Record is associated with the currently executing test case. + + @param[in] Format Formatting string following the format defined in + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +#define UT_LOG_ERROR(Format, ...) \ + UnitTestLog (UNIT_TEST_LOG_LEVEL_ERROR, Format, ##__VA_ARGS__) + +/** + Test logging macro that records a WARNING message in the test framework log. + Record is associated with the currently executing test case. + + @param[in] Format Formatting string following the format defined in + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +#define UT_LOG_WARNING(Format, ...) \ + UnitTestLog (UNIT_TEST_LOG_LEVEL_WARN, Format, ##__VA_ARGS__) + +/** + Test logging macro that records an INFO message in the test framework log. + Record is associated with the currently executing test case. + + @param[in] Format Formatting string following the format defined in + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +#define UT_LOG_INFO(Format, ...) \ + UnitTestLog (UNIT_TEST_LOG_LEVEL_INFO, Format, ##__VA_ARGS__) + +/** + Test logging macro that records a VERBOSE message in the test framework log. + Record is associated with the currently executing test case. + + @param[in] Format Formatting string following the format defined in + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +#define UT_LOG_VERBOSE(Format, ...) \ + UnitTestLog (UNIT_TEST_LOG_LEVEL_VERBOSE, Format, ##__VA_ARGS__) + +/** + Test logging function that records a messages in the test framework log. + Record is associated with the currently executing test case. + + @param[in] ErrorLevel The error level of the unit test log message. + @param[in] Format Formatting string following the format defined in the + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +VOID +EFIAPI +UnitTestLog ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ); + +#endif \ No newline at end of file diff --git a/MdePkg/Include/Protocol/Tls.h b/MdePkg/Include/Protocol/Tls.h index bf1b6727a1e..af524ae2a60 100644 --- a/MdePkg/Include/Protocol/Tls.h +++ b/MdePkg/Include/Protocol/Tls.h @@ -41,10 +41,6 @@ typedef struct _EFI_TLS_PROTOCOL EFI_TLS_PROTOCOL; /// EFI_TLS_SESSION_DATA_TYPE /// typedef enum { - /// - /// Session Configuration - /// - /// /// TLS session Version. The corresponding Data is of type EFI_TLS_VERSION. /// @@ -86,11 +82,6 @@ typedef enum { /// The corresponding Data is of type EFI_TLS_SESSION_STATE. /// EfiTlsSessionState, - - /// - /// Session information - /// - /// /// TLS session data client random. /// The corresponding Data is of type EFI_TLS_RANDOM. @@ -106,9 +97,15 @@ typedef enum { /// The corresponding Data is of type EFI_TLS_MASTER_SECRET. /// EfiTlsKeyMaterial, + /// + /// TLS session hostname for validation which is used to verify whether the name + /// within the peer certificate matches a given host name. + /// This parameter is invalid when EfiTlsVerifyMethod is EFI_TLS_VERIFY_NONE. + /// The corresponding Data is of type EFI_TLS_VERIFY_HOST. + /// + EfiTlsVerifyHost, EfiTlsSessionDataTypeMaximum - } EFI_TLS_SESSION_DATA_TYPE; /// @@ -178,7 +175,8 @@ typedef UINT32 EFI_TLS_VERIFY; /// #define EFI_TLS_VERIFY_PEER 0x1 /// -/// TLS session will fail peer certificate is absent. +/// EFI_TLS_VERIFY_FAIL_IF_NO_PEER_CERT is only meaningful in the server mode. +/// TLS session will fail if client certificate is absent. /// #define EFI_TLS_VERIFY_FAIL_IF_NO_PEER_CERT 0x2 /// @@ -187,6 +185,54 @@ typedef UINT32 EFI_TLS_VERIFY; /// #define EFI_TLS_VERIFY_CLIENT_ONCE 0x4 +/// +/// EFI_TLS_VERIFY_HOST_FLAG +/// +typedef UINT32 EFI_TLS_VERIFY_HOST_FLAG; +/// +/// There is no additional flags set for hostname validation. +/// Wildcards are supported and they match only in the left-most label. +/// +#define EFI_TLS_VERIFY_FLAG_NONE 0x00 +/// +/// Always check the Subject Distinguished Name (DN) in the peer certificate even if the +/// certificate contains Subject Alternative Name (SAN). +/// +#define EFI_TLS_VERIFY_FLAG_ALWAYS_CHECK_SUBJECT 0x01 +/// +/// Disable the match of all wildcards. +/// +#define EFI_TLS_VERIFY_FLAG_NO_WILDCARDS 0x02 +/// +/// Disable the "*" as wildcard in labels that have a prefix or suffix (e.g. "www*" or "*www"). +/// +#define EFI_TLS_VERIFY_FLAG_NO_PARTIAL_WILDCARDS 0x04 +/// +/// Allow the "*" to match more than one labels. Otherwise, only matches a single label. +/// +#define EFI_TLS_VERIFY_FLAG_MULTI_LABEL_WILDCARDS 0x08 +/// +/// Restrict to only match direct child sub-domains which start with ".". +/// For example, a name of ".example.com" would match "www.example.com" with this flag, +/// but would not match "www.sub.example.com". +/// +#define EFI_TLS_VERIFY_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10 +/// +/// Never check the Subject Distinguished Name (DN) even there is no +/// Subject Alternative Name (SAN) in the certificate. +/// +#define EFI_TLS_VERIFY_FLAG_NEVER_CHECK_SUBJECT 0x20 + +/// +/// EFI_TLS_VERIFY_HOST +/// +#pragma pack (1) +typedef struct { + EFI_TLS_VERIFY_HOST_FLAG Flags; + CHAR8 *HostName; +} EFI_TLS_VERIFY_HOST; +#pragma pack () + /// /// EFI_TLS_RANDOM /// Note: The definition of EFI_TLS_RANDOM is from "RFC 5246 A.4.1. diff --git a/MdePkg/Include/Uefi/UefiSpec.h b/MdePkg/Include/Uefi/UefiSpec.h index 44a0a6a7fa6..444aa35ecab 100644 --- a/MdePkg/Include/Uefi/UefiSpec.h +++ b/MdePkg/Include/Uefi/UefiSpec.h @@ -82,6 +82,26 @@ typedef enum { // If all memory has the same reliability, then this bit is not used. // #define EFI_MEMORY_MORE_RELIABLE 0x0000000000010000ULL + +// +// Note: UEFI spec 2.8 and following: +// +// Specific-purpose memory (SPM). The memory is earmarked for +// specific purposes such as for specific device drivers or applications. +// The SPM attribute serves as a hint to the OS to avoid allocating this +// memory for core OS data or code that can not be relocated. +// +#define EFI_MEMORY_SP 0x0000000000040000ULL +// +// If this flag is set, the memory region is capable of being +// protected with the CPU?s memory cryptographic +// capabilities. If this flag is clear, the memory region is not +// capable of being protected with the CPU?s memory +// cryptographic capabilities or the CPU does not support CPU +// memory cryptographic capabilities. +// +#define EFI_MEMORY_CPU_CRYPTO 0x0000000000080000ULL + // // Runtime memory attribute // diff --git a/MdePkg/Library/BaseRngLibNull/BaseRngLibNull.c b/MdePkg/Library/BaseRngLibNull/BaseRngLibNull.c new file mode 100644 index 00000000000..cad30599eae --- /dev/null +++ b/MdePkg/Library/BaseRngLibNull/BaseRngLibNull.c @@ -0,0 +1,94 @@ +/** @file + Null version of Random number generator services. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +/** + Generates a 16-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 16-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber16 ( + OUT UINT16 *Rand + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Generates a 32-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 32-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber32 ( + OUT UINT32 *Rand + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Generates a 64-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 64-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber64 ( + OUT UINT64 *Rand + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Generates a 128-bit random number. + + if Rand is NULL, then ASSERT(). + + @param[out] Rand Buffer pointer to store the 128-bit random value. + + @retval TRUE Random number generated successfully. + @retval FALSE Failed to generate the random number. + +**/ +BOOLEAN +EFIAPI +GetRandomNumber128 ( + OUT UINT64 *Rand + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/MdePkg/Library/BaseRngLibNull/BaseRngLibNull.inf b/MdePkg/Library/BaseRngLibNull/BaseRngLibNull.inf new file mode 100644 index 00000000000..f21e20a9cca --- /dev/null +++ b/MdePkg/Library/BaseRngLibNull/BaseRngLibNull.inf @@ -0,0 +1,30 @@ +## @file +# Null instance of RNG (Random Number Generator) Library. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010029 + BASE_NAME = BaseRngLibNull + MODULE_UNI_FILE = BaseRngLibNull.uni + FILE_GUID = CD8991F8-2061-4084-8C9E-9C6F352DC58D + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RngLib + +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 EBC +# + +[Sources] + BaseRngLibNull.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + DebugLib diff --git a/MdePkg/Library/BaseRngLibNull/BaseRngLibNull.uni b/MdePkg/Library/BaseRngLibNull/BaseRngLibNull.uni new file mode 100644 index 00000000000..f32be6a617e --- /dev/null +++ b/MdePkg/Library/BaseRngLibNull/BaseRngLibNull.uni @@ -0,0 +1,14 @@ +// /** @file +// Null Instance of RNG (Random Number Generator) Library. +// +// Copyright (c) 2019, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Null Instance of RNG Library" + +#string STR_MODULE_DESCRIPTION #language en-US "This library instance should be used with modules that inherit an (indirect) dependency on the RngLib class, but never actually call RngLib APIs for consuming randomness." + diff --git a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c index 862c6bff09f..cc79843b1cd 100644 --- a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c +++ b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c @@ -77,9 +77,8 @@ DxeRuntimeDebugLibSerialPortConstructor ( return Status; } - return SystemTable->BootServices->CreateEventEx (EVT_NOTIFY_SIGNAL, + return SystemTable->BootServices->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, - &gEfiEventExitBootServicesGuid, &mEfiExitBootServicesEvent); } diff --git a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDebugLibSerialPort.inf b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDebugLibSerialPort.inf index 655c1c14c17..31d169ad7c0 100644 --- a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDebugLibSerialPort.inf +++ b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDebugLibSerialPort.inf @@ -41,9 +41,6 @@ PrintLib SerialPortLib -[Guids] - gEfiEventExitBootServicesGuid ## CONSUMES ## Event - [Pcd] gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES diff --git a/MdePkg/Library/DxeRuntimePciExpressLib/DxeRuntimePciExpressLib.inf b/MdePkg/Library/DxeRuntimePciExpressLib/DxeRuntimePciExpressLib.inf index 45bfe9dc6fc..8d2ba1d1873 100644 --- a/MdePkg/Library/DxeRuntimePciExpressLib/DxeRuntimePciExpressLib.inf +++ b/MdePkg/Library/DxeRuntimePciExpressLib/DxeRuntimePciExpressLib.inf @@ -47,7 +47,3 @@ [Pcd] gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## CONSUMES - -[Guids] - gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event - diff --git a/MdePkg/Library/DxeRuntimePciExpressLib/PciExpressLib.c b/MdePkg/Library/DxeRuntimePciExpressLib/PciExpressLib.c index 6e784763be7..7e5852e641d 100644 --- a/MdePkg/Library/DxeRuntimePciExpressLib/PciExpressLib.c +++ b/MdePkg/Library/DxeRuntimePciExpressLib/PciExpressLib.c @@ -124,12 +124,11 @@ DxeRuntimePciExpressLibConstructor ( // // Register SetVirtualAddressMap () notify function // - Status = gBS->CreateEventEx ( - EVT_NOTIFY_SIGNAL, + Status = gBS->CreateEvent ( + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, TPL_NOTIFY, DxeRuntimePciExpressLibVirtualNotify, NULL, - &gEfiEventVirtualAddressChangeGuid, &mDxeRuntimePciExpressLibVirtualNotifyEvent ); ASSERT_EFI_ERROR (Status); diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c index 2f503ecffe0..b0dbdec0cf8 100644 --- a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c +++ b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c @@ -109,12 +109,11 @@ DxeRuntimePciSegmentLibConstructor ( // // Register SetVirtualAddressMap () notify function // - Status = gBS->CreateEventEx ( - EVT_NOTIFY_SIGNAL, + Status = gBS->CreateEvent ( + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, TPL_NOTIFY, DxeRuntimePciSegmentLibVirtualNotify, NULL, - &gEfiEventVirtualAddressChangeGuid, &mDxeRuntimePciSegmentLibVirtualNotifyEvent ); ASSERT_EFI_ERROR (Status); diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf index f6445f4abb0..ae9f11b697d 100644 --- a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf +++ b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf @@ -45,6 +45,3 @@ MemoryAllocationLib DxeServicesTableLib UefiBootServicesTableLib - -[Guids] - gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event diff --git a/MdePkg/Library/UefiDebugLibConOut/DebugLib.c b/MdePkg/Library/UefiDebugLibConOut/DebugLib.c index cf168d05cf2..8ea38ea7cc7 100644 --- a/MdePkg/Library/UefiDebugLibConOut/DebugLib.c +++ b/MdePkg/Library/UefiDebugLibConOut/DebugLib.c @@ -104,9 +104,9 @@ DebugPrintMarker ( // Convert the DEBUG() message to a Unicode String // if (BaseListMarker == NULL) { - UnicodeVSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, VaListMarker); + UnicodeVSPrintAsciiFormat (Buffer, sizeof (Buffer), Format, VaListMarker); } else { - UnicodeBSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, BaseListMarker); + UnicodeBSPrintAsciiFormat (Buffer, sizeof (Buffer), Format, BaseListMarker); } diff --git a/MdePkg/Library/UefiDebugLibConOut/DebugLibConstructor.c b/MdePkg/Library/UefiDebugLibConOut/DebugLibConstructor.c index ed73f928187..b4ac17cf55a 100644 --- a/MdePkg/Library/UefiDebugLibConOut/DebugLibConstructor.c +++ b/MdePkg/Library/UefiDebugLibConOut/DebugLibConstructor.c @@ -64,12 +64,11 @@ DxeDebugLibConstructor( { mDebugST = SystemTable; - SystemTable->BootServices->CreateEventEx ( - EVT_NOTIFY_SIGNAL, + SystemTable->BootServices->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesCallback, NULL, - &gEfiEventExitBootServicesGuid, &mExitBootServicesEvent ); diff --git a/MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf b/MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf index b577d52ac66..53bbc8ce3f6 100644 --- a/MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf +++ b/MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf @@ -46,9 +46,6 @@ PrintLib DebugPrintErrorLevelLib -[Guids] - gEfiEventExitBootServicesGuid ## CONSUMES - [Pcd] gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES diff --git a/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLibConstructor.c b/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLibConstructor.c index 6ea0912f2b3..96fc1c422fe 100644 --- a/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLibConstructor.c +++ b/MdePkg/Library/UefiDebugLibDebugPortProtocol/DebugLibConstructor.c @@ -64,12 +64,11 @@ DxeDebugLibConstructor( { mDebugBS = SystemTable->BootServices; - mDebugBS->CreateEventEx ( - EVT_NOTIFY_SIGNAL, + mDebugBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesCallback, NULL, - &gEfiEventExitBootServicesGuid, &mExitBootServicesEvent ); diff --git a/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf b/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf index ff09a12ce40..e12a1025c6c 100644 --- a/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf +++ b/MdePkg/Library/UefiDebugLibDebugPortProtocol/UefiDebugLibDebugPortProtocol.inf @@ -46,9 +46,6 @@ PrintLib DebugPrintErrorLevelLib -[Guids] - gEfiEventExitBootServicesGuid ## CONSUMES - [Protocols] gEfiDebugPortProtocolGuid ## CONSUMES diff --git a/MdePkg/Library/UefiDebugLibStdErr/DebugLib.c b/MdePkg/Library/UefiDebugLibStdErr/DebugLib.c index 40eb697e7e2..fcfdafede08 100644 --- a/MdePkg/Library/UefiDebugLibStdErr/DebugLib.c +++ b/MdePkg/Library/UefiDebugLibStdErr/DebugLib.c @@ -106,9 +106,9 @@ DebugPrintMarker ( // Convert the DEBUG() message to a Unicode String // if (BaseListMarker == NULL) { - UnicodeVSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, VaListMarker); + UnicodeVSPrintAsciiFormat (Buffer, sizeof (Buffer), Format, VaListMarker); } else { - UnicodeBSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, BaseListMarker); + UnicodeBSPrintAsciiFormat (Buffer, sizeof (Buffer), Format, BaseListMarker); } // diff --git a/MdePkg/Library/UefiDebugLibStdErr/DebugLibConstructor.c b/MdePkg/Library/UefiDebugLibStdErr/DebugLibConstructor.c index ed73f928187..b4ac17cf55a 100644 --- a/MdePkg/Library/UefiDebugLibStdErr/DebugLibConstructor.c +++ b/MdePkg/Library/UefiDebugLibStdErr/DebugLibConstructor.c @@ -64,12 +64,11 @@ DxeDebugLibConstructor( { mDebugST = SystemTable; - SystemTable->BootServices->CreateEventEx ( - EVT_NOTIFY_SIGNAL, + SystemTable->BootServices->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesCallback, NULL, - &gEfiEventExitBootServicesGuid, &mExitBootServicesEvent ); diff --git a/MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf b/MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf index 11f7594626e..5ecb971a0ac 100644 --- a/MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf +++ b/MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf @@ -44,9 +44,6 @@ PrintLib DebugPrintErrorLevelLib -[Guids] - gEfiEventExitBootServicesGuid ## CONSUMES - [Pcd] gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES diff --git a/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c b/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c index 96913c5c02b..28e28e5f67d 100644 --- a/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c +++ b/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c @@ -68,19 +68,21 @@ FileHandleGetInfo ( // error is expected. getting size to allocate // FileInfo = AllocateZeroPool(FileInfoSize); - // - // now get the information - // - Status = FileHandle->GetInfo(FileHandle, - &gEfiFileInfoGuid, - &FileInfoSize, - FileInfo); - // - // if we got an error free the memory and return NULL - // - if (EFI_ERROR(Status) && (FileInfo != NULL)) { - FreePool(FileInfo); - FileInfo = NULL; + if (FileInfo != NULL) { + // + // now get the information + // + Status = FileHandle->GetInfo(FileHandle, + &gEfiFileInfoGuid, + &FileInfoSize, + FileInfo); + // + // if we got an error free the memory and return NULL + // + if (EFI_ERROR(Status)) { + FreePool(FileInfo); + FileInfo = NULL; + } } } return (FileInfo); @@ -814,10 +816,25 @@ FileHandleGetFileName ( Status = EFI_OUT_OF_RESOURCES; break; } else { + // + // Prepare to move to the parent directory. + // Also determine whether CurrentHandle refers to the Root directory. + // + Status = CurrentHandle->Open (CurrentHandle, &NextHigherHandle, L"..", EFI_FILE_MODE_READ, 0); // // We got info... do we have a name? if yes precede the current path with it... // - if (StrLen (FileInfo->FileName) == 0) { + if ((StrLen (FileInfo->FileName) == 0) || EFI_ERROR (Status)) { + // + // Both FileInfo->FileName being '\0' and EFI_ERROR() suggest that + // CurrentHandle refers to the Root directory. As this loop ensures + // FullFileName is starting with '\\' at all times, signal success + // and exit the loop. + // While FileInfo->FileName could theoretically be a value other than + // '\0' or '\\', '\\' is guaranteed to be supported by the + // specification and hence its value can safely be ignored. + // + Status = EFI_SUCCESS; if (*FullFileName == NULL) { ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL)); *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0); @@ -835,15 +852,11 @@ FileHandleGetFileName ( FreePool(FileInfo); } } + + FileHandleClose(CurrentHandle); // // Move to the parent directory // - Status = CurrentHandle->Open (CurrentHandle, &NextHigherHandle, L"..", EFI_FILE_MODE_READ, 0); - if (EFI_ERROR (Status)) { - break; - } - - FileHandleClose(CurrentHandle); CurrentHandle = NextHigherHandle; } } else if (Status == EFI_NOT_FOUND) { diff --git a/MdePkg/Library/UefiLib/UefiLib.c b/MdePkg/Library/UefiLib/UefiLib.c index cc03be84c2d..07c45d1e91f 100644 --- a/MdePkg/Library/UefiLib/UefiLib.c +++ b/MdePkg/Library/UefiLib/UefiLib.c @@ -641,15 +641,15 @@ EfiTestChildHandle ( } /** - * This function checks the supported languages list for a target language, - * This only supports RFC 4646 Languages. - * - * @param SupportedLanguages The supported languages - * @param TargetLanguage The target language - * - * @return Returns EFI_SUCCESS if the language is supported, - * EFI_UNSUPPORTED otherwise - */ + This function checks the supported languages list for a target language, + This only supports RFC 4646 Languages. + + @param SupportedLanguages The supported languages + @param TargetLanguage The target language + + @retval Returns EFI_SUCCESS if the language is supported, + EFI_UNSUPPORTED otherwise +**/ EFI_STATUS EFIAPI IsLanguageSupported ( diff --git a/MdePkg/Library/UefiRuntimeLib/RuntimeLib.c b/MdePkg/Library/UefiRuntimeLib/RuntimeLib.c index 933e0099cee..a2eadafac86 100644 --- a/MdePkg/Library/UefiRuntimeLib/RuntimeLib.c +++ b/MdePkg/Library/UefiRuntimeLib/RuntimeLib.c @@ -93,23 +93,21 @@ RuntimeDriverLibConstruct ( // // Register SetVirtualAddressMap () notify function // - Status = gBS->CreateEventEx ( - EVT_NOTIFY_SIGNAL, + Status = gBS->CreateEvent ( + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, TPL_NOTIFY, RuntimeLibVirtualNotifyEvent, NULL, - &gEfiEventVirtualAddressChangeGuid, &mEfiVirtualNotifyEvent ); ASSERT_EFI_ERROR (Status); - Status = gBS->CreateEventEx ( - EVT_NOTIFY_SIGNAL, + Status = gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, RuntimeLibExitBootServicesEvent, NULL, - &gEfiEventExitBootServicesGuid, &mEfiExitBootServicesEvent ); diff --git a/MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf b/MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf index 5527f9f02f7..cc4ee151100 100644 --- a/MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf +++ b/MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf @@ -39,8 +39,3 @@ UefiBootServicesTableLib UefiRuntimeServicesTableLib DebugLib - -[Guids] - gEfiEventExitBootServicesGuid ## CONSUMES ## Event - gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event - diff --git a/MdePkg/MdePkg.ci.yaml b/MdePkg/MdePkg.ci.yaml new file mode 100644 index 00000000000..88e490fcb66 --- /dev/null +++ b/MdePkg/MdePkg.ci.yaml @@ -0,0 +1,103 @@ +## @file +# CI configuration for MdePkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + ## options defined ci/Plugin/CompilerPlugin + "CompilerPlugin": { + "DscPath": "MdePkg.dsc" + }, + + ## options defined ci/Plugin/HostUnitTestCompilerPlugin + "HostUnitTestCompilerPlugin": { + "DscPath": "Test/MdePkgHostTest.dsc" + }, + + ## options defined ci/Plugin/CharEncodingCheck + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + + ## options defined ci/Plugin/DependencyCheck + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[ + "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec" + ], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + + ## options defined ci/Plugin/DscCompleteCheck + "DscCompleteCheck": { + "IgnoreInf": [""], + "DscPath": "MdePkg.dsc" + }, + + ## options defined ci/Plugin/HostUnitTestDscCompleteCheck + "HostUnitTestDscCompleteCheck": { + "IgnoreInf": [""], + "DscPath": "Test/MdePkgHostTest.dsc" + }, + + ## options defined ci/Plugin/GuidCheck + "GuidCheck": { + "IgnoreGuidName": [ + "gEfiFirmwareVolumeTopFileGuid" # sec modules must be set to this guid + ], + "IgnoreGuidValue": ["00000000-0000-0000-0000-000000000000"], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [ + "gEfiFirmwareVolumeBlockProtocolGuid=gEfiFirmwareVolumeBlock2ProtocolGuid", + "gEfiMmAccessProtocolGuid=gEfiSmmAccess2ProtocolGuid", + "gEfiSmmCommunicationProtocolGuid=gEfiMmCommunicationProtocolGuid", + "gEfiMmPciRootBridgeIoProtocolGuid=gEfiSmmPciRootBridgeIoProtocolGuid", + "gEfiTrEEProtocolGuid=gEfiTcg2ProtocolGuid", + "gEfiSmmPowerButtonDispatch2ProtocolGuid=gEfiMmPowerButtonDispatchProtocolGuid", + "gEfiSmmBase2ProtocolGuid=gEfiMmBaseProtocolGuid", + "gEfiSmmUsbDispatch2ProtocolGuid=gEfiMmUsbDispatchProtocolGuid", + "gEfiSmmCpuProtocolGuid=gEfiMmCpuProtocolGuid", + "gEfiAcpiTableGuid=gEfiAcpi20TableGuid", + "gEfiSmmControl2ProtocolGuid=gEfiMmControlProtocolGuid", + "gEfiSmmStandbyButtonDispatch2ProtocolGuid=gEfiMmStandbyButtonDispatchProtocolGuid", + "gEfiSmmStatusCodeProtocolGuid=gEfiMmStatusCodeProtocolGuid", + "gEfiDxeSmmReadyToLockProtocolGuid=gEfiDxeMmReadyToLockProtocolGuid", + "gEfiSmmIoTrapDispatch2ProtocolGuid=gEfiMmIoTrapDispatchProtocolGuid", + "gEfiSmmReadyToLockProtocolGuid=gEfiMmReadyToLockProtocolGuid", + "gEfiSmmSxDispatch2ProtocolGuid=gEfiMmSxDispatchProtocolGuid", + "gEfiPeiCapsulePpiGuid=gPeiCapsulePpiGuid", + "gEfiSmmCpuIo2ProtocolGuid=gEfiMmCpuIoProtocolGuid", + "gEfiSmmRscHandlerProtocolGuid=gEfiMmRscHandlerProtocolGuid", + "gEfiSmmConfigurationProtocolGuid=gEfiMmConfigurationProtocolGuid", + "gEfiSmmGpiDispatch2ProtocolGuid=gEfiMmGpiDispatchProtocolGuid", + "gEfiSmmEndOfDxeProtocolGuid=gEfiMmEndOfDxeProtocolGuid", + "gEfiSmmSwDispatch2ProtocolGuid=gEfiMmSwDispatchProtocolGuid", + "gEfiDebugPortProtocolGuid=gEfiDebugPortVariableGuid=gEfiDebugPortDevicePathGuid", ## is this a bug + "gEfiProcessorSpecificErrorSectionGuid=gEfiIa32X64ProcessorErrorSectionGuid", ## is this a bug + "gEfiSmmPeriodicTimerDispatch2ProtocolGuid=gEfiMmPeriodicTimerDispatchProtocolGuid", + "gEdkiiFormBrowserExProtocolGuid=gEfiFormBrowserExProtocolGuid", + "gEfiPeiMmAccessPpiGuid=gPeiSmmAccessPpiGuid", + "gPeiSmmControlPpiGuid=gEfiPeiMmControlPpiGuid" + ] + }, + + ## options defined ci/Plugin/LibraryClassCheck + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined ci/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log + "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files + "ExtendWords": [], # words to extend to the dictionary for this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + } +} diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index d022cc5e3ef..ac1f5339af0 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -244,6 +244,10 @@ ## @libraryclass Module entry point library for standalone MM drivers. StandaloneMmDriverEntryPoint|Include/Library/StandaloneMmDriverEntryPoint.h + ## @libraryclass Provides a unit test framework + # + UnitTestLib|Include/Library/UnitTestLib.h + [LibraryClasses.IA32, LibraryClasses.X64] ## @libraryclass Abstracts both S/W SMI generation and detection. ## diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index c1278e79070..87af7408539 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -18,6 +18,8 @@ BUILD_TARGETS = DEBUG|RELEASE|NOOPT SKUID_IDENTIFIER = DEFAULT +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc + [PcdsFeatureFlag] gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport|TRUE @@ -26,6 +28,9 @@ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000 gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xE0000000 +[LibraryClasses] + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + [Components] MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf @@ -61,6 +66,7 @@ MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf MdePkg/Library/BaseSmbusLibNull/BaseSmbusLibNull.inf MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + MdePkg/Library/BaseRngLibNull/BaseRngLibNull.inf MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf @@ -114,6 +120,19 @@ MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib.inf + # + # Add UEFI Target Based Unit Tests + # + MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsUefi.inf + + # + # Build PEIM, DXE_DRIVER, SMM_DRIVER, UEFI Shell components that test SafeIntLib + # + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibPei.inf + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibDxe.inf + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibSmm.inf + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibUefiShell.inf + [Components.IA32, Components.X64] MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf diff --git a/MdePkg/Test/MdePkgHostTest.dsc b/MdePkg/Test/MdePkgHostTest.dsc new file mode 100644 index 00000000000..3d677ee75ce --- /dev/null +++ b/MdePkg/Test/MdePkgHostTest.dsc @@ -0,0 +1,30 @@ +## @file +# MdePkg DSC file used to build host-based unit tests. +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME = MdePkgHostTest + PLATFORM_GUID = 50652B4C-88CB-4481-96E8-37F2D0034440 + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/MdePkg/HostTest + SUPPORTED_ARCHITECTURES = IA32|X64 + BUILD_TARGETS = NOOPT + SKUID_IDENTIFIER = DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc + +[LibraryClasses] + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + +[Components] + # + # Build HOST_APPLICATION that tests the SafeIntLib + # + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf + MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHost.inf diff --git a/MdePkg/Test/UnitTest/Library/BaseLib/Base64UnitTest.c b/MdePkg/Test/UnitTest/Library/BaseLib/Base64UnitTest.c new file mode 100644 index 00000000000..0ad078155cd --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseLib/Base64UnitTest.c @@ -0,0 +1,404 @@ +/** @file + Unit tests of Base64 conversion APIs in BaseLib. + + Copyright (C) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#define UNIT_TEST_APP_NAME "BaseLib Unit Test Application" +#define UNIT_TEST_APP_VERSION "1.0" + +/** + RFC 4648 https://tools.ietf.org/html/rfc4648 test vectors + + BASE64("") = "" + BASE64("f") = "Zg==" + BASE64("fo") = "Zm8=" + BASE64("foo") = "Zm9v" + BASE64("foob") = "Zm9vYg==" + BASE64("fooba") = "Zm9vYmE=" + BASE64("foobar") = "Zm9vYmFy" + + The test vectors are using ascii strings for the binary data + */ + +typedef struct { + CHAR8 *TestInput; + CHAR8 *TestOutput; + EFI_STATUS ExpectedStatus; + VOID *BufferToFree; + UINTN ExpectedSize; +} BASIC_TEST_CONTEXT; + +#define B64_TEST_1 "" +#define BIN_TEST_1 "" + +#define B64_TEST_2 "Zg==" +#define BIN_TEST_2 "f" + +#define B64_TEST_3 "Zm8=" +#define BIN_TEST_3 "fo" + +#define B64_TEST_4 "Zm9v" +#define BIN_TEST_4 "foo" + +#define B64_TEST_5 "Zm9vYg==" +#define BIN_TEST_5 "foob" + +#define B64_TEST_6 "Zm9vYmE=" +#define BIN_TEST_6 "fooba" + +#define B64_TEST_7 "Zm9vYmFy" +#define BIN_TEST_7 "foobar" + +// Adds all white space - also ends the last quantum with only spaces afterwards +#define B64_TEST_8_IN " \t\v Zm9\r\nvYmFy \f " +#define BIN_TEST_8 "foobar" + +// Not a quantum multiple of 4 +#define B64_ERROR_1 "Zm9vymFy=" + +// Invalid characters in the string +#define B64_ERROR_2 "Zm$vymFy" + +// Too many '=' characters +#define B64_ERROR_3 "Z===" + +// Poorly placed '=' +#define B64_ERROR_4 "Zm=vYmFy" + +#define MAX_TEST_STRING_SIZE (200) + +// ------------------------------------------------ Input----------Output-----------Result-------Free--Expected Output Size +static BASIC_TEST_CONTEXT mBasicEncodeTest1 = {BIN_TEST_1, B64_TEST_1, EFI_SUCCESS, NULL, sizeof(B64_TEST_1)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest2 = {BIN_TEST_2, B64_TEST_2, EFI_SUCCESS, NULL, sizeof(B64_TEST_2)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest3 = {BIN_TEST_3, B64_TEST_3, EFI_SUCCESS, NULL, sizeof(B64_TEST_3)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest4 = {BIN_TEST_4, B64_TEST_4, EFI_SUCCESS, NULL, sizeof(B64_TEST_4)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest5 = {BIN_TEST_5, B64_TEST_5, EFI_SUCCESS, NULL, sizeof(B64_TEST_5)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest6 = {BIN_TEST_6, B64_TEST_6, EFI_SUCCESS, NULL, sizeof(B64_TEST_6)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest7 = {BIN_TEST_7, B64_TEST_7, EFI_SUCCESS, NULL, sizeof(B64_TEST_7)}; +static BASIC_TEST_CONTEXT mBasicEncodeError1 = {BIN_TEST_7, B64_TEST_1, EFI_BUFFER_TOO_SMALL, NULL, sizeof(B64_TEST_7)}; + +static BASIC_TEST_CONTEXT mBasicDecodeTest1 = {B64_TEST_1, BIN_TEST_1, EFI_SUCCESS, NULL, sizeof(BIN_TEST_1)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest2 = {B64_TEST_2, BIN_TEST_2, EFI_SUCCESS, NULL, sizeof(BIN_TEST_2)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest3 = {B64_TEST_3, BIN_TEST_3, EFI_SUCCESS, NULL, sizeof(BIN_TEST_3)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest4 = {B64_TEST_4, BIN_TEST_4, EFI_SUCCESS, NULL, sizeof(BIN_TEST_4)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest5 = {B64_TEST_5, BIN_TEST_5, EFI_SUCCESS, NULL, sizeof(BIN_TEST_5)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest6 = {B64_TEST_6, BIN_TEST_6, EFI_SUCCESS, NULL, sizeof(BIN_TEST_6)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest7 = {B64_TEST_7, BIN_TEST_7, EFI_SUCCESS, NULL, sizeof(BIN_TEST_7)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest8 = {B64_TEST_8_IN, BIN_TEST_8, EFI_SUCCESS, NULL, sizeof(BIN_TEST_8)-1}; + +static BASIC_TEST_CONTEXT mBasicDecodeError1 = {B64_ERROR_1, B64_ERROR_1, EFI_INVALID_PARAMETER, NULL, 0}; +static BASIC_TEST_CONTEXT mBasicDecodeError2 = {B64_ERROR_2, B64_ERROR_2, EFI_INVALID_PARAMETER, NULL, 0}; +static BASIC_TEST_CONTEXT mBasicDecodeError3 = {B64_ERROR_3, B64_ERROR_3, EFI_INVALID_PARAMETER, NULL, 0}; +static BASIC_TEST_CONTEXT mBasicDecodeError4 = {B64_ERROR_4, B64_ERROR_4, EFI_INVALID_PARAMETER, NULL, 0}; +static BASIC_TEST_CONTEXT mBasicDecodeError5 = {B64_TEST_7, BIN_TEST_1, EFI_BUFFER_TOO_SMALL, NULL, sizeof(BIN_TEST_7)-1}; + +/** + Simple clean up method to make sure tests clean up even if interrupted and fail + in the middle. +**/ +STATIC +VOID +EFIAPI +CleanUpB64TestContext ( + IN UNIT_TEST_CONTEXT Context + ) +{ + BASIC_TEST_CONTEXT *Btc; + + Btc = (BASIC_TEST_CONTEXT *)Context; + if (Btc != NULL) { + //free string if set + if (Btc->BufferToFree != NULL) { + FreePool (Btc->BufferToFree); + Btc->BufferToFree = NULL; + } + } +} + +/** + Unit test for Base64 encode APIs of BaseLib. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +STATIC +UNIT_TEST_STATUS +EFIAPI +RfcEncodeTest ( + IN UNIT_TEST_CONTEXT Context + ) +{ + BASIC_TEST_CONTEXT *Btc; + CHAR8 *b64String; + CHAR8 *binString; + UINTN b64StringSize; + EFI_STATUS Status; + UINT8 *BinData; + UINTN BinSize; + CHAR8 *b64WorkString; + UINTN ReturnSize; + INTN CompareStatus; + UINTN indx; + + Btc = (BASIC_TEST_CONTEXT *) Context; + binString = Btc->TestInput; + b64String = Btc->TestOutput; + + // + // Only testing the the translate functionality, so preallocate the proper + // string buffer. + // + + b64StringSize = AsciiStrnSizeS(b64String, MAX_TEST_STRING_SIZE); + BinSize = AsciiStrnLenS(binString, MAX_TEST_STRING_SIZE); + BinData = (UINT8 *) binString; + + b64WorkString = (CHAR8 *) AllocatePool(b64StringSize); + UT_ASSERT_NOT_NULL(b64WorkString); + + Btc->BufferToFree = b64WorkString; + ReturnSize = b64StringSize; + + Status = Base64Encode(BinData, BinSize, b64WorkString, &ReturnSize); + + UT_ASSERT_STATUS_EQUAL(Status, Btc->ExpectedStatus); + + UT_ASSERT_EQUAL(ReturnSize, Btc->ExpectedSize); + + if (!EFI_ERROR (Btc->ExpectedStatus)) { + if (ReturnSize != 0) { + CompareStatus = AsciiStrnCmp (b64String, b64WorkString, ReturnSize); + if (CompareStatus != 0) { + UT_LOG_ERROR ("b64 string compare error - size=%d\n", ReturnSize); + for (indx = 0; indx < ReturnSize; indx++) { + UT_LOG_ERROR (" %2.2x", 0xff & b64String[indx]); + } + UT_LOG_ERROR ("\n b64 work string:\n"); + for (indx = 0; indx < ReturnSize; indx++) { + UT_LOG_ERROR (" %2.2x", 0xff & b64WorkString[indx]); + } + UT_LOG_ERROR ("\n"); + } + UT_ASSERT_EQUAL (CompareStatus, 0); + } + } + + Btc->BufferToFree = NULL; + FreePool (b64WorkString); + return UNIT_TEST_PASSED; +} + +/** + Unit test for Base64 decode APIs of BaseLib. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +STATIC +UNIT_TEST_STATUS +EFIAPI +RfcDecodeTest( + IN UNIT_TEST_CONTEXT Context + ) +{ + BASIC_TEST_CONTEXT *Btc; + CHAR8 *b64String; + CHAR8 *binString; + EFI_STATUS Status; + UINTN b64StringLen; + UINTN ReturnSize; + UINT8 *BinData; + UINTN BinSize; + INTN CompareStatus; + UINTN indx; + + Btc = (BASIC_TEST_CONTEXT *)Context; + b64String = Btc->TestInput; + binString = Btc->TestOutput; + + // + // Only testing the the translate functionality + // + + b64StringLen = AsciiStrnLenS (b64String, MAX_TEST_STRING_SIZE); + BinSize = AsciiStrnLenS (binString, MAX_TEST_STRING_SIZE); + + BinData = AllocatePool (BinSize); + Btc->BufferToFree = BinData; + + ReturnSize = BinSize; + Status = Base64Decode (b64String, b64StringLen, BinData, &ReturnSize); + + UT_ASSERT_STATUS_EQUAL (Status, Btc->ExpectedStatus); + + // If an error is not expected, check the results + if (EFI_ERROR (Btc->ExpectedStatus)) { + if (Btc->ExpectedStatus == EFI_BUFFER_TOO_SMALL) { + UT_ASSERT_EQUAL (ReturnSize, Btc->ExpectedSize); + } + } else { + UT_ASSERT_EQUAL (ReturnSize, Btc->ExpectedSize); + if (ReturnSize != 0) { + CompareStatus = CompareMem (binString, BinData, ReturnSize); + if (CompareStatus != 0) { + UT_LOG_ERROR ("bin string compare error - size=%d\n", ReturnSize); + for (indx = 0; indx < ReturnSize; indx++) { + UT_LOG_ERROR (" %2.2x", 0xff & binString[indx]); + } + UT_LOG_ERROR ("\nBinData:\n"); + for (indx = 0; indx < ReturnSize; indx++) { + UT_LOG_ERROR (" %2.2x", 0xff & BinData[indx]); + } + UT_LOG_ERROR ("\n"); + } + UT_ASSERT_EQUAL (CompareStatus, 0); + } + } + + Btc->BufferToFree = NULL; + FreePool (BinData); + return UNIT_TEST_PASSED; +} + +/** + Initialze the unit test framework, suite, and unit tests for the + Base64 conversion APIs of BaseLib and run the unit tests. + + @retval EFI_SUCCESS All test cases were dispached. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + initialize the unit tests. +**/ +STATIC +EFI_STATUS +EFIAPI +UnitTestingEntry ( + VOID + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Fw; + UNIT_TEST_SUITE_HANDLE b64EncodeTests; + UNIT_TEST_SUITE_HANDLE b64DecodeTests; + + Fw = NULL; + + DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION)); + + // + // Start setting up the test framework for running the tests. + // + Status = InitUnitTestFramework (&Fw, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status)); + goto EXIT; + } + + // + // Populate the B64 Encode Unit Test Suite. + // + Status = CreateUnitTestSuite (&b64EncodeTests, Fw, "b64 Encode binary to Ascii string", "BaseLib.b64Encode", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for b64EncodeTests\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + // --------------Suite-----------Description--------------Class Name----------Function--------Pre---Post-------------------Context----------- + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - Empty", "Test1", RfcEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest1); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - f", "Test2", RfcEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest2); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - fo", "Test3", RfcEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest3); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - foo", "Test4", RfcEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest4); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - foob", "Test5", RfcEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest5); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - fooba", "Test6", RfcEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest6); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - foobar", "Test7", RfcEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest7); + AddTestCase (b64EncodeTests, "Too small of output buffer", "Error1", RfcEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeError1); + // + // Populate the B64 Decode Unit Test Suite. + // + Status = CreateUnitTestSuite (&b64DecodeTests, Fw, "b64 Decode Ascii string to binary", "BaseLib.b64Decode", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for b64Decode Tests\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - Empty", "Test1", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest1); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - f", "Test2", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest2); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - fo", "Test3", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest3); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - foo", "Test4", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest4); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - foob", "Test5", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest5); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - fooba", "Test6", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest6); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - foobar", "Test7", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest7); + AddTestCase (b64DecodeTests, "Ignore Whitespace test", "Test8", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest8); + + AddTestCase (b64DecodeTests, "Not a quantum multiple of 4", "Error1", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError1); + AddTestCase (b64DecodeTests, "Invalid characters in the string", "Error2", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError2); + AddTestCase (b64DecodeTests, "Too many padding characters", "Error3", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError3); + AddTestCase (b64DecodeTests, "Incorrectly placed padding character", "Error4", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError4); + AddTestCase (b64DecodeTests, "Too small of output buffer", "Error5", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError5); + + // + // Execute the tests. + // + Status = RunAllTestSuites (Fw); + +EXIT: + if (Fw) { + FreeUnitTestFramework (Fw); + } + + return Status; +} + +/** + Standard UEFI entry point for target based unit test execution from UEFI Shell. +**/ +EFI_STATUS +EFIAPI +BaseLibUnitTestAppEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return UnitTestingEntry (); +} + +/** + Standard POSIX C entry point for host based unit test execution. +**/ +int +main ( + int argc, + char *argv[] + ) +{ + return UnitTestingEntry (); +} diff --git a/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHost.inf b/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHost.inf new file mode 100644 index 00000000000..b31afae6332 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHost.inf @@ -0,0 +1,32 @@ +## @file +# Unit tests of Base64 conversion APIs in BaseLib that are run from host +# environment. +# +# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = BaseLibUnitTestsHost + FILE_GUID = 1d005f4c-4dfa-41b5-ab0c-be91fe121459 + MODULE_TYPE = HOST_APPLICATION + VERSION_STRING = 1.0 + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Base64UnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + UnitTestLib diff --git a/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsUefi.inf b/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsUefi.inf new file mode 100644 index 00000000000..907503898a6 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsUefi.inf @@ -0,0 +1,33 @@ +## @file +# Unit tests of Base64 conversion APIs in BaseLib that are run from UEFI Shell. +# +# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = BaseLibUnitTestsUefi + FILE_GUID = df5a6fed-8786-4a9d-9d02-eab39497b4a1 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = BaseLibUnitTestAppEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Base64UnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiApplicationEntryPoint + DebugLib + UnitTestLib diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/IA32/SafeIntLibUintnIntnUnitTests.c b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/IA32/SafeIntLibUintnIntnUnitTests.c new file mode 100644 index 00000000000..be5c0e15d30 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/IA32/SafeIntLibUintnIntnUnitTests.c @@ -0,0 +1,540 @@ +/** @file + IA32-specific functions for unit-testing INTN and UINTN functions in + SafeIntLib. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TestBaseSafeIntLib.h" + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeInt32ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (-1537977259); + Status = SafeInt32ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INTN Result; + + // + // If Operand is <= MAX_INTN, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeUint32ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabababab); + Status = SafeUint32ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + INT32 Result; + + // + // INTN is same as INT32 in IA32, so this is just a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeIntnToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT32 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeIntnToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (-1537977259); + Status = SafeIntnToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + UINT32 Result; + + // + // UINTN is same as UINT32 in IA32, so this is just a cast + // + Operand = 0xabababab; + Result = 0; + Status = SafeUintnToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INTN Result; + + // + // If Operand is <= MAX_INTN, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeUintnToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabababab); + Status = SafeUintnToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT64 Result; + + // + // UINTN is same as UINT32 in IA32, and UINT32 is a subset of + // INT64, so this is just a cast + // + Operand = 0xabababab; + Result = 0; + Status = SafeUintnToInt64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INTN Result; + + // + // If Operand is between MIN_INTN and MAX_INTN2 inclusive, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + Operand = (-1537977259); + Status = SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1537977259), Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINTN Result; + + // + // If Operand is between 0 and MAX_UINTN inclusive, then it's a cast + // + Operand = 0xabababab; + Result = 0; + Status = SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INTN Result; + + // + // If Operand is <= MAX_INTN, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeUint64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINTN Result; + + // + // If Operand is <= MAX_UINTN, then it's a cast + // + Operand = 0xabababab; + Result = 0; + Status = SafeUint64ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnAdd ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Augend; + UINTN Addend; + UINTN Result; + + // + // If the result of addition doesn't overflow MAX_UINTN, then it's addition + // + Augend = 0x3a3a3a3a; + Addend = 0x3a3a3a3a; + Result = 0; + Status = SafeUintnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74747474, Result); + + // + // Otherwise should result in an error status + // + Augend = 0xabababab; + Addend = 0xbcbcbcbc; + Status = SafeUintnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnAdd ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Augend; + INTN Addend; + INTN Result; + + // + // If the result of addition doesn't overflow MAX_INTN + // and doesn't underflow MIN_INTN, then it's addition + // + Augend = 0x3a3a3a3a; + Addend = 0x3a3a3a3a; + Result = 0; + Status = SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74747474, Result); + + Augend = (-976894522); + Addend = (-976894522); + Status = SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1953789044), Result); + + // + // Otherwise should result in an error status + // + Augend = 0x5a5a5a5a; + Addend = 0x5a5a5a5a; + Status = SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend = (-1515870810); + Addend = (-1515870810); + Status = SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnSub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Minuend; + UINTN Subtrahend; + UINTN Result; + + // + // If Minuend >= Subtrahend, then it's subtraction + // + Minuend = 0x5a5a5a5a; + Subtrahend = 0x3b3b3b3b; + Result = 0; + Status = SafeUintnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend = 0x5a5a5a5a; + Subtrahend = 0x6d6d6d6d; + Status = SafeUintnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnSub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Minuend; + INTN Subtrahend; + INTN Result; + + // + // If the result of subtractions doesn't overflow MAX_INTN or + // underflow MIN_INTN, then it's subtraction + // + Minuend = 0x5a5a5a5a; + Subtrahend = 0x3a3a3a3a; + Result = 0; + Status = SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x20202020, Result); + + Minuend = 0x3a3a3a3a; + Subtrahend = 0x5a5a5a5a; + Status = SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-538976288), Result); + + // + // Otherwise should result in an error status + // + Minuend = (-2054847098); + Subtrahend = 2054847098; + Status = SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend = (2054847098); + Subtrahend = (-2054847098); + Status = SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnMult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Multiplicand; + UINTN Multiplier; + UINTN Result; + + // + // If the result of multiplication doesn't overflow MAX_UINTN, it will succeed + // + Multiplicand = 0xa122a; + Multiplier = 0xd23; + Result = 0; + Status = SafeUintnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x844c9dbe, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0xa122a; + Multiplier = 0xed23; + Status = SafeUintnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnMult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Multiplicand; + INTN Multiplier; + INTN Result; + + // + // If the result of multiplication doesn't overflow MAX_INTN and doesn't + // underflow MIN_UINTN, it will succeed + // + Multiplicand = 0x123456; + Multiplier = 0x678; + Result = 0; + Status = SafeIntnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x75c28c50, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x123456; + Multiplier = 0xabc; + Status = SafeIntnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.c b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.c new file mode 100644 index 00000000000..2b1a2223a0d --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.c @@ -0,0 +1,3064 @@ +/** @file + UEFI OS based application for unit testing the SafeIntLib. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TestBaseSafeIntLib.h" + +#define UNIT_TEST_NAME "Int Safe Lib Unit Test Application" +#define UNIT_TEST_VERSION "0.1" + +// +// Conversion function tests: +// +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINT8 Result; + + // + // Positive UINT8 should result in just a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt8ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand = (-56); + Status = SafeInt8ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINT16 Result; + + // + // Positive UINT8 should result in just a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt8ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand = (-56); + Status = SafeInt8ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINT32 Result; + + // + // Positive UINT8 should result in just a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt8ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand = (-56); + Status = SafeInt8ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINTN Result; + + // + // Positive UINT8 should result in just a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt8ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand = (-56); + Status = SafeInt8ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINT64 Result; + + // + // Positive UINT8 should result in just a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt8ToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand = (-56); + Status = SafeInt8ToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Operand; + INT8 Result; + + // + // Operand <= 0x7F (MAX_INT8) should result in a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUint8ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Operand larger than 0x7f should result in an error status + // + Operand = 0xaf; + Status = SafeUint8ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + // + + // + // Operand <= 0x7F (MAX_INT8) should result in a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUint8ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Operand larger than 0x7f should result in an error status + // + Operand = 0xaf; + Status = SafeUint8ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + INT8 Result; + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt16ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand = (-35); + Status = SafeInt16ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-35), Result); + + // + // Otherwise should result in an error status + // + Operand = 0x1234; + Status = SafeInt16ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-17835); + Status = SafeInt16ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which may be signed or unsigned based + // on the compiler. Thus, for compatibility CHAR8 should be between 0 and MAX_INT8. + // + + // + // If Operand is between 0 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand = 0; + Result = 0; + Status = SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0, Result); + + Operand = MAX_INT8; + Result = 0; + Status = SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(MAX_INT8, Result); + + // + // Otherwise should result in an error status + // + Operand = (-35); + Status = SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = 0x1234; + Status = SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-17835); + Status = SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + UINT8 Result; + + // + // If Operand is between 0 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt16ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = 0x1234; + Status = SafeInt16ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-17835); + Status = SafeInt16ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand = 0x5b5b; + UINT16 Result = 0; + + // + // If Operand is non-negative, then it's a cast + // + Status = SafeInt16ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (-17835); + Status = SafeInt16ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + UINT32 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5b5b; + Result = 0; + Status = SafeInt16ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (-17835); + Status = SafeInt16ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5b5b; + Result = 0; + Status = SafeInt16ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (-17835); + Status = SafeInt16ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + UINT64 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5b5b; + Result = 0; + Status = SafeInt16ToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (-17835); + Status = SafeInt16ToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Operand; + INT8 Result; + + // + // If Operand is <= MAX_INT8, it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUint16ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5b5b); + Status = SafeUint16ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Operand; + CHAR8 Result; + + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + + // + // If Operand is <= MAX_INT8, it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUint16ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5b5b); + Status = SafeUint16ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Operand; + UINT8 Result; + + // + // If Operand is <= MAX_UINT8 (0xff), it's a cast + // + Operand = 0xab; + Result = 0; + Status = SafeUint16ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5b5b); + Status = SafeUint16ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Operand; + INT16 Result; + + // + // If Operand is <= MAX_INT16 (0x7fff), it's a cast + // + Operand = 0x5b5b; + Result = 0; + Status = SafeUint16ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabab); + Status = SafeUint16ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + INT8 Result; + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt32ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand = (-57); + Status = SafeInt32ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-57), Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5bababab); + Status = SafeInt32ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeInt32ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which may be signed or unsigned based + // on the compiler. Thus, for compatibility CHAR8 should be between 0 and MAX_INT8. + // + + // + // If Operand is between 0 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand = 0; + Result = 0; + Status = SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0, Result); + + Operand = MAX_INT8; + Result = 0; + Status = SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(MAX_INT8, Result); + + // + // Otherwise should result in an error status + // + Operand = (-57); + Status = SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (0x5bababab); + Status = SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINT8 Result; + + // + // If Operand is between 0 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt32ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (-57); + Status = SafeInt32ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (0x5bababab); + Status = SafeInt32ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeInt32ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + INT16 Result; + + // + // If Operand is between MIN_INT16 and MAX_INT16 inclusive, then it's a cast + // + Operand = 0x5b5b; + Result = 0; + Status = SafeInt32ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + Operand = (-17857); + Status = SafeInt32ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-17857), Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5bababab); + Status = SafeInt32ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeInt32ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINT16 Result; + + // + // If Operand is between 0 and MAX_UINT16 inclusive, then it's a cast + // + Operand = 0xabab; + Result = 0; + Status = SafeInt32ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand = (-17857); + Status = SafeInt32ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (0x5bababab); + Status = SafeInt32ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeInt32ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINT32 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeInt32ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (-1537977259); + Status = SafeInt32ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINT64 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeInt32ToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (-1537977259); + Status = SafeInt32ToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INT8 Result; + + // + // If Operand is <= MAX_INT8, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUint32ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5bababab); + Status = SafeUint32ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + CHAR8 Result; + + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + + // + // If Operand is <= MAX_INT8, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUint32ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5bababab); + Status = SafeUint32ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + UINT8 Result; + + // + // If Operand is <= MAX_UINT8, then it's a cast + // + Operand = 0xab; + Result = 0; + Status = SafeUint32ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabababab); + Status = SafeUint32ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INT16 Result; + + // + // If Operand is <= MAX_INT16, then it's a cast + // + Operand = 0x5bab; + Result = 0; + Status = SafeUint32ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabababab); + Status = SafeUint32ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + UINT16 Result; + + // + // If Operand is <= MAX_UINT16, then it's a cast + // + Operand = 0xabab; + Result = 0; + Status = SafeUint32ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabababab); + Status = SafeUint32ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INT32 Result; + + // + // If Operand is <= MAX_INT32, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeUint32ToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabababab); + Status = SafeUint32ToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + INT8 Result; + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeIntnToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand = (-53); + Status = SafeIntnToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-53), Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5bababab); + Status = SafeIntnToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeIntnToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which may be signed or unsigned based + // on the compiler. Thus, for compatibility CHAR8 should be between 0 and MAX_INT8. + // + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeIntnToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand = 0; + Result = 0; + Status = SafeIntnToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0, Result); + + Operand = MAX_INT8; + Result = 0; + Status = SafeIntnToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(MAX_INT8, Result); + + // + // Otherwise should result in an error status + // + Operand = (-53); + Status = SafeIntnToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (0x5bababab); + Status = SafeIntnToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeIntnToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT8 Result; + + // + // If Operand is between 0 and MAX_UINT8 inclusive, then it's a cast + // + Operand = 0xab; + Result = 0; + Status = SafeIntnToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5bababab); + Status = SafeIntnToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeIntnToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + INT16 Result; + + // + // If Operand is between MIN_INT16 and MAX_INT16 inclusive, then it's a cast + // + Operand = 0x5bab; + Result = 0; + Status = SafeIntnToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + Operand = (-23467); + Status = SafeIntnToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-23467), Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5bababab); + Status = SafeIntnToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeIntnToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT16 Result; + + // + // If Operand is between 0 and MAX_UINT16 inclusive, then it's a cast + // + Operand = 0xabab; + Result = 0; + Status = SafeIntnToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5bababab); + Status = SafeIntnToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-1537977259); + Status = SafeIntnToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeIntnToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (-1537977259); + Status = SafeIntnToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT64 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeIntnToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (-1537977259); + Status = SafeIntnToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT8 Result; + + // + // If Operand is <= MAX_INT8, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUintnToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabab); + Status = SafeUintnToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + CHAR8 Result; + + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + + // + // If Operand is <= MAX_INT8, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUintnToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabab); + Status = SafeUintnToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + UINT8 Result; + + // + // If Operand is <= MAX_UINT8, then it's a cast + // + Operand = 0xab; + Result = 0; + Status = SafeUintnToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabab); + Status = SafeUintnToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT16 Result; + + // + // If Operand is <= MAX_INT16, then it's a cast + // + Operand = 0x5bab; + Result = 0; + Status = SafeUintnToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabab); + Status = SafeUintnToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + UINT16 Result; + + // + // If Operand is <= MAX_UINT16, then it's a cast + // + Operand = 0xabab; + Result = 0; + Status = SafeUintnToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabababab); + Status = SafeUintnToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT32 Result; + + // + // If Operand is <= MAX_INT32, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeUintnToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xabababab); + Status = SafeUintnToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INT8 Result; + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt64ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand = (-37); + Status = SafeInt64ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-37), Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeInt64ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeInt64ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which may be signed or unsigned based + // on the compiler. Thus, for compatibility CHAR8 should be between 0 and MAX_INT8. + // + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand = 0; + Result = 0; + Status = SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0, Result); + + Operand = MAX_INT8; + Result = 0; + Status = SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(MAX_INT8, Result); + + // + // Otherwise should result in an error status + // + Operand = (-37); + Status = SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (0x5babababefefefef); + Status = SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINT8 Result; + + // + // If Operand is between 0 and MAX_UINT8 inclusive, then it's a cast + // + Operand = 0xab; + Result = 0; + Status = SafeInt64ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeInt64ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeInt64ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INT16 Result; + + // + // If Operand is between MIN_INT16 and MAX_INT16 inclusive, then it's a cast + // + Operand = 0x5bab; + Result = 0; + Status = SafeInt64ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + Operand = (-23467); + Status = SafeInt64ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-23467), Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeInt64ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeInt64ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINT16 Result; + + // + // If Operand is between 0 and MAX_UINT16 inclusive, then it's a cast + // + Operand = 0xabab; + Result = 0; + Status = SafeInt64ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeInt64ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeInt64ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INT32 Result; + + // + // If Operand is between MIN_INT32 and MAX_INT32 inclusive, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeInt64ToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + Operand = (-1537977259); + Status = SafeInt64ToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1537977259), Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeInt64ToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeInt64ToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINT32 Result; + + // + // If Operand is between 0 and MAX_UINT32 inclusive, then it's a cast + // + Operand = 0xabababab; + Result = 0; + Status = SafeInt64ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeInt64ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeInt64ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINT64 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5babababefefefef; + Result = 0; + Status = SafeInt64ToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand = (-6605562033422200815); + Status = SafeInt64ToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INT8 Result; + + // + // If Operand is <= MAX_INT8, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUint64ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + CHAR8 Result; + + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + + // + // If Operand is <= MAX_INT8, then it's a cast + // + Operand = 0x5b; + Result = 0; + Status = SafeUint64ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINT8 Result; + + // + // If Operand is <= MAX_UINT8, then it's a cast + // + Operand = 0xab; + Result = 0; + Status = SafeUint64ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INT16 Result; + + // + // If Operand is <= MAX_INT16, then it's a cast + // + Operand = 0x5bab; + Result = 0; + Status = SafeUint64ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINT16 Result; + + // + // If Operand is <= MAX_UINT16, then it's a cast + // + Operand = 0xabab; + Result = 0; + Status = SafeUint64ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INT32 Result; + + // + // If Operand is <= MAX_INT32, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeUint64ToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINT32 Result; + + // + // If Operand is <= MAX_UINT32, then it's a cast + // + Operand = 0xabababab; + Result = 0; + Status = SafeUint64ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToInt64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INT64 Result; + + // + // If Operand is <= MAX_INT64, then it's a cast + // + Operand = 0x5babababefefefef; + Result = 0; + Status = SafeUint64ToInt64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToInt64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +// +// Addition function tests: +// +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Augend; + UINT8 Addend; + UINT8 Result; + + // + // If the result of addition doesn't overflow MAX_UINT8, then it's addition + // + Augend = 0x3a; + Addend = 0x3a; + Result = 0; + Status = SafeUint8Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74, Result); + + // + // Otherwise should result in an error status + // + Augend = 0xab; + Addend = 0xbc; + Status = SafeUint8Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Augend = 0x3a3a; + UINT16 Addend = 0x3a3a; + UINT16 Result = 0; + + // + // If the result of addition doesn't overflow MAX_UINT16, then it's addition + // + Status = SafeUint16Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474, Result); + + // + // Otherwise should result in an error status + // + Augend = 0xabab; + Addend = 0xbcbc; + Status = SafeUint16Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Augend; + UINT32 Addend; + UINT32 Result; + + // + // If the result of addition doesn't overflow MAX_UINT32, then it's addition + // + Augend = 0x3a3a3a3a; + Addend = 0x3a3a3a3a; + Result = 0; + Status = SafeUint32Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74747474, Result); + + // + // Otherwise should result in an error status + // + Augend = 0xabababab; + Addend = 0xbcbcbcbc; + Status = SafeUint32Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Augend; + UINT64 Addend; + UINT64 Result; + + // + // If the result of addition doesn't overflow MAX_UINT64, then it's addition + // + Augend = 0x3a3a3a3a12121212; + Addend = 0x3a3a3a3a12121212; + Result = 0; + Status = SafeUint64Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474747424242424, Result); + + // + // Otherwise should result in an error status + // + Augend = 0xababababefefefef; + Addend = 0xbcbcbcbcdededede; + Status = SafeUint64Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Augend; + INT8 Addend; + INT8 Result; + + // + // If the result of addition doesn't overflow MAX_INT8 + // and doesn't underflow MIN_INT8, then it's addition + // + Augend = 0x3a; + Addend = 0x3a; + Result = 0; + Status = SafeInt8Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74, Result); + + Augend = (-58); + Addend = (-58); + Status = SafeInt8Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-116), Result); + + // + // Otherwise should result in an error status + // + Augend = 0x5a; + Addend = 0x5a; + Status = SafeInt8Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend = (-90); + Addend = (-90); + Status = SafeInt8Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; + +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Augend; + INT16 Addend; + INT16 Result; + + // + // If the result of addition doesn't overflow MAX_INT16 + // and doesn't underflow MIN_INT16, then it's addition + // + Augend = 0x3a3a; + Addend = 0x3a3a; + Result = 0; + Status = SafeInt16Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474, Result); + + Augend = (-14906); + Addend = (-14906); + Status = SafeInt16Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-29812), Result); + + // + // Otherwise should result in an error status + // + Augend = 0x5a5a; + Addend = 0x5a5a; + Status = SafeInt16Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend = (-23130); + Addend = (-23130); + Status = SafeInt16Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Augend; + INT32 Addend; + INT32 Result; + + // + // If the result of addition doesn't overflow MAX_INT32 + // and doesn't underflow MIN_INT32, then it's addition + // + Augend = 0x3a3a3a3a; + Addend = 0x3a3a3a3a; + Result = 0; + Status = SafeInt32Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74747474, Result); + + Augend = (-976894522); + Addend = (-976894522); + Status = SafeInt32Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1953789044), Result); + + // + // Otherwise should result in an error status + // + Augend = 0x5a5a5a5a; + Addend = 0x5a5a5a5a; + Status = SafeInt32Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend = (-1515870810); + Addend = (-1515870810); + Status = SafeInt32Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Augend; + INT64 Addend; + INT64 Result; + + // + // If the result of addition doesn't overflow MAX_INT64 + // and doesn't underflow MIN_INT64, then it's addition + // + Augend = 0x3a3a3a3a3a3a3a3a; + Addend = 0x3a3a3a3a3a3a3a3a; + Result = 0; + Status = SafeInt64Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474747474747474, Result); + + Augend = (-4195730024608447034); + Addend = (-4195730024608447034); + Status = SafeInt64Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-8391460049216894068), Result); + + // + // Otherwise should result in an error status + // + Augend = 0x5a5a5a5a5a5a5a5a; + Addend = 0x5a5a5a5a5a5a5a5a; + Status = SafeInt64Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend = (-6510615555426900570); + Addend = (-6510615555426900570); + Status = SafeInt64Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +// +// Subtraction function tests: +// +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Minuend; + UINT8 Subtrahend; + UINT8 Result; + + // + // If Minuend >= Subtrahend, then it's subtraction + // + Minuend = 0x5a; + Subtrahend = 0x3b; + Result = 0; + Status = SafeUint8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f, Result); + + // + // Otherwise should result in an error status + // + Minuend = 0x5a; + Subtrahend = 0x6d; + Status = SafeUint8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Minuend; + UINT16 Subtrahend; + UINT16 Result; + + // + // If Minuend >= Subtrahend, then it's subtraction + // + Minuend = 0x5a5a; + Subtrahend = 0x3b3b; + Result = 0; + Status = SafeUint16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend = 0x5a5a; + Subtrahend = 0x6d6d; + Status = SafeUint16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Minuend; + UINT32 Subtrahend; + UINT32 Result; + + // + // If Minuend >= Subtrahend, then it's subtraction + // + Minuend = 0x5a5a5a5a; + Subtrahend = 0x3b3b3b3b; + Result = 0; + Status = SafeUint32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend = 0x5a5a5a5a; + Subtrahend = 0x6d6d6d6d; + Status = SafeUint32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Minuend; + UINT64 Subtrahend; + UINT64 Result; + + // + // If Minuend >= Subtrahend, then it's subtraction + // + Minuend = 0x5a5a5a5a5a5a5a5a; + Subtrahend = 0x3b3b3b3b3b3b3b3b; + Result = 0; + Status = SafeUint64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f1f1f1f1f1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend = 0x5a5a5a5a5a5a5a5a; + Subtrahend = 0x6d6d6d6d6d6d6d6d; + Status = SafeUint64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Minuend; + INT8 Subtrahend; + INT8 Result; + + // + // If the result of subtractions doesn't overflow MAX_INT8 or + // underflow MIN_INT8, then it's subtraction + // + Minuend = 0x5a; + Subtrahend = 0x3a; + Result = 0; + Status = SafeInt8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x20, Result); + + Minuend = 58; + Subtrahend = 78; + Status = SafeInt8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-20), Result); + + // + // Otherwise should result in an error status + // + Minuend = (-80); + Subtrahend = 80; + Status = SafeInt8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend = (80); + Subtrahend = (-80); + Status = SafeInt8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Minuend; + INT16 Subtrahend; + INT16 Result; + + // + // If the result of subtractions doesn't overflow MAX_INT16 or + // underflow MIN_INT16, then it's subtraction + // + Minuend = 0x5a5a; + Subtrahend = 0x3a3a; + Result = 0; + Status = SafeInt16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x2020, Result); + + Minuend = 0x3a3a; + Subtrahend = 0x5a5a; + Status = SafeInt16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-8224), Result); + + // + // Otherwise should result in an error status + // + Minuend = (-31354); + Subtrahend = 31354; + Status = SafeInt16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend = (31354); + Subtrahend = (-31354); + Status = SafeInt16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Minuend; + INT32 Subtrahend; + INT32 Result; + + // + // If the result of subtractions doesn't overflow MAX_INT32 or + // underflow MIN_INT32, then it's subtraction + // + Minuend = 0x5a5a5a5a; + Subtrahend = 0x3a3a3a3a; + Result = 0; + Status = SafeInt32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x20202020, Result); + + Minuend = 0x3a3a3a3a; + Subtrahend = 0x5a5a5a5a; + Status = SafeInt32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-538976288), Result); + + // + // Otherwise should result in an error status + // + Minuend = (-2054847098); + Subtrahend = 2054847098; + Status = SafeInt32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend = (2054847098); + Subtrahend = (-2054847098); + Status = SafeInt32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Minuend; + INT64 Subtrahend; + INT64 Result; + + // + // If the result of subtractions doesn't overflow MAX_INT64 or + // underflow MIN_INT64, then it's subtraction + // + Minuend = 0x5a5a5a5a5a5a5a5a; + Subtrahend = 0x3a3a3a3a3a3a3a3a; + Result = 0; + Status = SafeInt64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x2020202020202020, Result); + + Minuend = 0x3a3a3a3a3a3a3a3a; + Subtrahend = 0x5a5a5a5a5a5a5a5a; + Status = SafeInt64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-2314885530818453536), Result); + + // + // Otherwise should result in an error status + // + Minuend = (-8825501086245354106); + Subtrahend = 8825501086245354106; + Status = SafeInt64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend = (8825501086245354106); + Subtrahend = (-8825501086245354106); + Status = SafeInt64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +// +// Multiplication function tests: +// +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Multiplicand; + UINT8 Multiplier; + UINT8 Result; + + // + // If the result of multiplication doesn't overflow MAX_UINT8, it will succeed + // + Multiplicand = 0x12; + Multiplier = 0xa; + Result = 0; + Status = SafeUint8Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xb4, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x12; + Multiplier = 0x23; + Status = SafeUint8Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Multiplicand; + UINT16 Multiplier; + UINT16 Result; + + // + // If the result of multiplication doesn't overflow MAX_UINT16, it will succeed + // + Multiplicand = 0x212; + Multiplier = 0x7a; + Result = 0; + Status = SafeUint16Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xfc94, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x1234; + Multiplier = 0x213; + Status = SafeUint16Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Multiplicand; + UINT32 Multiplier; + UINT32 Result; + + // + // If the result of multiplication doesn't overflow MAX_UINT32, it will succeed + // + Multiplicand = 0xa122a; + Multiplier = 0xd23; + Result = 0; + Status = SafeUint32Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x844c9dbe, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0xa122a; + Multiplier = 0xed23; + Status = SafeUint32Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Multiplicand; + UINT64 Multiplier; + UINT64 Result; + + // + // If the result of multiplication doesn't overflow MAX_UINT64, it will succeed + // + Multiplicand = 0x123456789a; + Multiplier = 0x1234567; + Result = 0; + Status = SafeUint64Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x14b66db9745a07f6, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x123456789a; + Multiplier = 0x12345678; + Status = SafeUint64Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Multiplicand; + INT8 Multiplier; + INT8 Result; + + // + // If the result of multiplication doesn't overflow MAX_INT8 and doesn't + // underflow MIN_UINT8, it will succeed + // + Multiplicand = 0x12; + Multiplier = 0x7; + Result = 0; + Status = SafeInt8Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7e, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x12; + Multiplier = 0xa; + Status = SafeInt8Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Multiplicand; + INT16 Multiplier; + INT16 Result; + + // + // If the result of multiplication doesn't overflow MAX_INT16 and doesn't + // underflow MIN_UINT16, it will succeed + // + Multiplicand = 0x123; + Multiplier = 0x67; + Result = 0; + Status = SafeInt16Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7515, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x123; + Multiplier = 0xab; + Status = SafeInt16Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Multiplicand; + INT32 Multiplier; + INT32 Result; + + // + // If the result of multiplication doesn't overflow MAX_INT32 and doesn't + // underflow MIN_UINT32, it will succeed + // + Multiplicand = 0x123456; + Multiplier = 0x678; + Result = 0; + Status = SafeInt32Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x75c28c50, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x123456; + Multiplier = 0xabc; + Status = SafeInt32Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Multiplicand; + INT64 Multiplier; + INT64 Result; + + // + // If the result of multiplication doesn't overflow MAX_INT64 and doesn't + // underflow MIN_UINT64, it will succeed + // + Multiplicand = 0x123456789; + Multiplier = 0x6789abcd; + Result = 0; + Status = SafeInt64Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x75cd9045220d6bb5, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x123456789; + Multiplier = 0xa789abcd; + Status = SafeInt64Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +/** + + Main fuction sets up the unit test environment + +**/ +EFI_STATUS +EFIAPI +UefiTestMain ( + VOID + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework; + UNIT_TEST_SUITE_HANDLE ConversionTestSuite; + UNIT_TEST_SUITE_HANDLE AdditionSubtractionTestSuite; + UNIT_TEST_SUITE_HANDLE MultiplicationTestSuite; + + Framework = NULL; + ConversionTestSuite = NULL; + AdditionSubtractionTestSuite = NULL; + MultiplicationTestSuite = NULL; + + DEBUG((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION)); + + // + // Start setting up the test framework for running the tests. + // + Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status)); + goto EXIT; + } + + /// + // Test the conversion functions + // + Status = CreateUnitTestSuite (&ConversionTestSuite, Framework, "Int Safe Conversions Test Suite", "Common.SafeInt.Convert", NULL, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for Conversions Test Suite\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUint8", "TestSafeInt8ToUint8", TestSafeInt8ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUint16", "TestSafeInt8ToUint16", TestSafeInt8ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUint32", "TestSafeInt8ToUint32", TestSafeInt8ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUintn", "TestSafeInt8ToUintn", TestSafeInt8ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUint64", "TestSafeInt8ToUint64", TestSafeInt8ToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint8ToInt8", "TestSafeUint8ToInt8", TestSafeUint8ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint8ToChar8", "TestSafeUint8ToChar8", TestSafeUint8ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToInt8", "TestSafeInt16ToInt8", TestSafeInt16ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToChar8", "TestSafeInt16ToChar8", TestSafeInt16ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUint8", "TestSafeInt16ToUint8", TestSafeInt16ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUint16", "TestSafeInt16ToUint16", TestSafeInt16ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUint32", "TestSafeInt16ToUint32", TestSafeInt16ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUintn", "TestSafeInt16ToUintn", TestSafeInt16ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUint64", "TestSafeInt16ToUint64", TestSafeInt16ToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint16ToInt8", "TestSafeUint16ToInt8", TestSafeUint16ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint16ToChar8", "TestSafeUint16ToChar8", TestSafeUint16ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint16ToUint8", "TestSafeUint16ToUint8", TestSafeUint16ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint16ToInt16", "TestSafeUint16ToInt16", TestSafeUint16ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToInt8", "TestSafeInt32ToInt8", TestSafeInt32ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToChar8", "TestSafeInt32ToChar8", TestSafeInt32ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUint8", "TestSafeInt32ToUint8", TestSafeInt32ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToInt16", "TestSafeInt32ToInt16", TestSafeInt32ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUint16", "TestSafeInt32ToUint16", TestSafeInt32ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUint32", "TestSafeInt32ToUint32", TestSafeInt32ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUintn", "TestSafeInt32ToUintn", TestSafeInt32ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUint64", "TestSafeInt32ToUint64", TestSafeInt32ToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToInt8", "TestSafeUint32ToInt8", TestSafeUint32ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToChar8", "TestSafeUint32ToChar8", TestSafeUint32ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToUint8", "TestSafeUint32ToUint8", TestSafeUint32ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToInt16", "TestSafeUint32ToInt16", TestSafeUint32ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToUint16", "TestSafeUint32ToUint16", TestSafeUint32ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToInt32", "TestSafeUint32ToInt32", TestSafeUint32ToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToIntn", "TestSafeUint32ToIntn", TestSafeUint32ToIntn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToInt8", "TestSafeIntnToInt8", TestSafeIntnToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToChar8", "TestSafeIntnToChar8", TestSafeIntnToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUint8", "TestSafeIntnToUint8", TestSafeIntnToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToInt16", "TestSafeIntnToInt16", TestSafeIntnToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUint16", "TestSafeIntnToUint16", TestSafeIntnToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToInt32", "TestSafeIntnToInt32", TestSafeIntnToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUint32", "TestSafeIntnToUint32", TestSafeIntnToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUintn", "TestSafeIntnToUintn", TestSafeIntnToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUint64", "TestSafeIntnToUint64", TestSafeIntnToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToInt8", "TestSafeUintnToInt8", TestSafeUintnToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToChar8", "TestSafeUintnToChar8", TestSafeUintnToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToUint8", "TestSafeUintnToUint8", TestSafeUintnToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToInt16", "TestSafeUintnToInt16", TestSafeUintnToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToUint16", "TestSafeUintnToUint16", TestSafeUintnToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToInt32", "TestSafeUintnToInt32", TestSafeUintnToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToUint32", "TestSafeUintnToUint32", TestSafeUintnToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToIntn", "TestSafeUintnToIntn", TestSafeUintnToIntn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToInt64", "TestSafeUintnToInt64", TestSafeUintnToInt64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToInt8", "TestSafeInt64ToInt8", TestSafeInt64ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToChar8", "TestSafeInt64ToChar8", TestSafeInt64ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUint8", "TestSafeInt64ToUint8", TestSafeInt64ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToInt16", "TestSafeInt64ToInt16", TestSafeInt64ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUint16", "TestSafeInt64ToUint16", TestSafeInt64ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToInt32", "TestSafeInt64ToInt32", TestSafeInt64ToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUint32", "TestSafeInt64ToUint32", TestSafeInt64ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToIntn", "TestSafeInt64ToIntn", TestSafeInt64ToIntn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUintn", "TestSafeInt64ToUintn", TestSafeInt64ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUint64", "TestSafeInt64ToUint64", TestSafeInt64ToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToInt8", "TestSafeUint64ToInt8", TestSafeUint64ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToChar8", "TestSafeUint64ToChar8", TestSafeUint64ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToUint8", "TestSafeUint64ToUint8", TestSafeUint64ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToInt16", "TestSafeUint64ToInt16", TestSafeUint64ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToUint16", "TestSafeUint64ToUint16", TestSafeUint64ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToInt32", "TestSafeUint64ToInt32", TestSafeUint64ToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToUint32", "TestSafeUint64ToUint32", TestSafeUint64ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToIntn", "TestSafeUint64ToIntn", TestSafeUint64ToIntn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToUintn", "TestSafeUint64ToUintn", TestSafeUint64ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToInt64", "TestSafeUint64ToInt64", TestSafeUint64ToInt64, NULL, NULL, NULL); + + // + // Test the addition and subtraction functions + // + Status = CreateUnitTestSuite(&AdditionSubtractionTestSuite, Framework, "Int Safe Add/Subtract Test Suite", "Common.SafeInt.AddSubtract", NULL, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for Int Safe Add/Subtract Test Suite\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint8Add", "TestSafeUint8Add", TestSafeUint8Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint16Add", "TestSafeUint16Add", TestSafeUint16Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint32Add", "TestSafeUint32Add", TestSafeUint32Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUintnAdd", "TestSafeUintnAdd", TestSafeUintnAdd, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint64Add", "TestSafeUint64Add", TestSafeUint64Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt8Add", "TestSafeInt8Add", TestSafeInt8Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt16Add", "TestSafeInt16Add", TestSafeInt16Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt32Add", "TestSafeInt32Add", TestSafeInt32Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeIntnAdd", "TestSafeIntnAdd", TestSafeIntnAdd, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt64Add", "TestSafeInt64Add", TestSafeInt64Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint8Sub", "TestSafeUint8Sub", TestSafeUint8Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint16Sub", "TestSafeUint16Sub", TestSafeUint16Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint32Sub", "TestSafeUint32Sub", TestSafeUint32Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUintnSub", "TestSafeUintnSub", TestSafeUintnSub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint64Sub", "TestSafeUint64Sub", TestSafeUint64Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt8Sub", "TestSafeInt8Sub", TestSafeInt8Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt16Sub", "TestSafeInt16Sub", TestSafeInt16Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt32Sub", "TestSafeInt32Sub", TestSafeInt32Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeIntnSub", "TestSafeIntnSub", TestSafeIntnSub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt64Sub", "TestSafeInt64Sub", TestSafeInt64Sub, NULL, NULL, NULL); + + // + // Test the multiplication functions + // + Status = CreateUnitTestSuite(&MultiplicationTestSuite, Framework, "Int Safe Multiply Test Suite", "Common.SafeInt.Multiply", NULL, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for Int Safe Multiply Test Suite\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase(MultiplicationTestSuite, "Test SafeUint8Mult", "TestSafeUint8Mult", TestSafeUint8Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeUint16Mult", "TestSafeUint16Mult", TestSafeUint16Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeUint32Mult", "TestSafeUint32Mult", TestSafeUint32Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeUintnMult", "TestSafeUintnMult", TestSafeUintnMult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeUint64Mult", "TestSafeUint64Mult", TestSafeUint64Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeInt8Mult", "TestSafeInt8Mult", TestSafeInt8Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeInt16Mult", "TestSafeInt16Mult", TestSafeInt16Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeInt32Mult", "TestSafeInt32Mult", TestSafeInt32Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeIntnMult", "TestSafeIntnMult", TestSafeIntnMult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeInt64Mult", "TestSafeInt64Mult", TestSafeInt64Mult, NULL, NULL, NULL); + + // + // Execute the tests. + // + Status = RunAllTestSuites(Framework); + +EXIT: + if (Framework != NULL) { + FreeUnitTestFramework(Framework); + } + + return Status; +} + +EFI_STATUS +EFIAPI +PeiEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + return UefiTestMain (); +} + +EFI_STATUS +EFIAPI +DxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return UefiTestMain (); +} + +int +main ( + int argc, + char *argv[] + ) +{ + return UefiTestMain (); +} diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.h b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.h new file mode 100644 index 00000000000..7957c99a85c --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.h @@ -0,0 +1,123 @@ +/** @file + UEFI OS based application for unit testing the SafeIntLib. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _TEST_BASE_SAFE_INT_LIB_H_ +#define _TEST_BASE_SAFE_INT_LIB_H_ + +#include +#include +#include +#include +#include +#include +#include + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUintn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToIntn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt32( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint32( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint32( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToIntn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt64( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToIntn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUintn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToIntn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUintn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnAdd( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnAdd( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnSub( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnSub( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnMult( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnMult( + IN UNIT_TEST_CONTEXT Context + ); + +#endif diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.uni b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.uni new file mode 100644 index 00000000000..956835c30d5 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.uni @@ -0,0 +1,13 @@ +// /** @file +// Application that Unit Tests the SafeIntLib +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Application that Unit Tests the SafeIntLib" + +#string STR_MODULE_DESCRIPTION #language en-US "Application that Unit Tests the SafeIntLib." + diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibDxe.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibDxe.inf new file mode 100644 index 00000000000..302af0aac3b --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibDxe.inf @@ -0,0 +1,45 @@ +## @file +# DXE Driver that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TestBaseSafeIntLibDxe + MODULE_UNI_FILE = TestBaseSafeIntLib.uni + FILE_GUID = 9729DB60-FB9D-4625-9EE1-93B21EC246B8 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32] + IA32/SafeIntLibUintnIntnUnitTests.c + +[Sources.X64] + X64/SafeIntLibUintnIntnUnitTests.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + SafeIntLib + UnitTestLib + +[Depex] + TRUE diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf new file mode 100644 index 00000000000..b490d838169 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf @@ -0,0 +1,40 @@ +## @file +# Host OS based Application that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TestBaseSafeIntLibHost + MODULE_UNI_FILE = TestBaseSafeIntLib.uni + FILE_GUID = 95487689-9E30-41AD-B773-3650C94BCBE2 + MODULE_TYPE = HOST_APPLICATION + VERSION_STRING = 1.0 + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32] + IA32/SafeIntLibUintnIntnUnitTests.c + +[Sources.X64] + X64/SafeIntLibUintnIntnUnitTests.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + SafeIntLib + UnitTestLib diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibPei.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibPei.inf new file mode 100644 index 00000000000..f3afcfa356e --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibPei.inf @@ -0,0 +1,45 @@ +## @file +# PEIM that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TestBaseSafeIntLibPei + MODULE_UNI_FILE = TestBaseSafeIntLib.uni + FILE_GUID = 7D910602-ED53-45E6-826E-8266705B9734 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeiEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32] + IA32/SafeIntLibUintnIntnUnitTests.c + +[Sources.X64] + X64/SafeIntLibUintnIntnUnitTests.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + PeimEntryPoint + BaseLib + DebugLib + SafeIntLib + UnitTestLib + +[Depex] + TRUE diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibSmm.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibSmm.inf new file mode 100644 index 00000000000..cac4e34d1c1 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibSmm.inf @@ -0,0 +1,45 @@ +## @file +# SMM Driver that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TestBaseSafeIntLibSmm + MODULE_UNI_FILE = TestBaseSafeIntLib.uni + FILE_GUID = 2F2A1907-B1B4-4E33-8B83-62A60AB4F0D4 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32] + IA32/SafeIntLibUintnIntnUnitTests.c + +[Sources.X64] + X64/SafeIntLibUintnIntnUnitTests.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + SafeIntLib + UnitTestLib + +[Depex] + TRUE diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibUefiShell.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibUefiShell.inf new file mode 100644 index 00000000000..bb428d248d1 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibUefiShell.inf @@ -0,0 +1,42 @@ +## @file +# UEFI Shell based Application that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TestBaseSafeIntLibUefiShell + MODULE_UNI_FILE = TestBaseSafeIntLib.uni + FILE_GUID = 1F91B73E-5B6A-4317-80E8-E7C36A3C7AF4 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = DxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32] + IA32/SafeIntLibUintnIntnUnitTests.c + +[Sources.X64] + X64/SafeIntLibUintnIntnUnitTests.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + BaseLib + DebugLib + SafeIntLib + UnitTestLib diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/X64/SafeIntLibUintnIntnUnitTests.c b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/X64/SafeIntLibUintnIntnUnitTests.c new file mode 100644 index 00000000000..0fee2981720 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/X64/SafeIntLibUintnIntnUnitTests.c @@ -0,0 +1,544 @@ +/** @file + x64-specific functions for unit-testing INTN and UINTN functions in + SafeIntLib. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TestBaseSafeIntLib.h" + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeInt32ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (-1537977259); + Status = SafeInt32ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INTN Result; + + // + // For x64, INTN is same as INT64 which is a superset of INT32 + // This is just a cast then, and it'll never fail + // + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0xabababab; + Result = 0; + Status = SafeUint32ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + INT32 Result; + + // + // If Operand is between MIN_INT32 and MAX_INT32 inclusive, then it's a cast + // + Operand = 0x5bababab; + Result = 0; + Status = SafeIntnToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + Operand = (-1537977259); + Status = SafeIntnToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1537977259), Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeIntnToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeIntnToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT32 Result; + + // + // If Operand is between 0 and MAX_UINT32 inclusive, then it's a cast + // + Operand = 0xabababab; + Result = 0; + Status = SafeIntnToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0x5babababefefefef); + Status = SafeIntnToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand = (-6605562033422200815); + Status = SafeIntnToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + UINT32 Result; + + // + // If Operand is <= MAX_UINT32, then it's a cast + // + Operand = 0xabababab; + Result = 0; + Status = SafeUintnToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUintnToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INTN Result; + + // + // If Operand is <= MAX_INTN (0x7fff_ffff_ffff_ffff), then it's a cast + // + Operand = 0x5babababefefefef; + Result = 0; + Status = SafeUintnToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUintnToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT64 Result; + + // + // If Operand is <= MAX_INT64, then it's a cast + // + Operand = 0x5babababefefefef; + Result = 0; + Status = SafeUintnToInt64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUintnToInt64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INTN Result; + + // + // INTN is same as INT64 in x64, so this is just a cast + // + Operand = 0x5babababefefefef; + Result = 0; + Status = SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand = 0x5babababefefefef; + Result = 0; + Status = SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand = (-6605562033422200815); + Status = SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INTN Result; + + // + // If Operand is <= MAX_INTN (0x7fff_ffff_ffff_ffff), then it's a cast + // + Operand = 0x5babababefefefef; + Result = 0; + Status = SafeUint64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand = (0xababababefefefef); + Status = SafeUint64ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINTN Result; + + // + // UINTN is same as UINT64 in x64, so this is just a cast + // + Operand = 0xababababefefefef; + Result = 0; + Status = SafeUint64ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xababababefefefef, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnAdd ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Augend; + UINTN Addend; + UINTN Result; + + // + // If the result of addition doesn't overflow MAX_UINTN, then it's addition + // + Augend = 0x3a3a3a3a12121212; + Addend = 0x3a3a3a3a12121212; + Result = 0; + Status = SafeUintnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474747424242424, Result); + + // + // Otherwise should result in an error status + // + Augend = 0xababababefefefef; + Addend = 0xbcbcbcbcdededede; + Status = SafeUintnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnAdd ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Augend; + INTN Addend; + INTN Result; + + // + // If the result of addition doesn't overflow MAX_INTN + // and doesn't underflow MIN_INTN, then it's addition + // + Augend = 0x3a3a3a3a3a3a3a3a; + Addend = 0x3a3a3a3a3a3a3a3a; + Result = 0; + Status = SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474747474747474, Result); + + Augend = (-4195730024608447034); + Addend = (-4195730024608447034); + Status = SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-8391460049216894068), Result); + + // + // Otherwise should result in an error status + // + Augend = 0x5a5a5a5a5a5a5a5a; + Addend = 0x5a5a5a5a5a5a5a5a; + Status = SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend = (-6510615555426900570); + Addend = (-6510615555426900570); + Status = SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnSub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Minuend; + UINTN Subtrahend; + UINTN Result; + + // + // If Minuend >= Subtrahend, then it's subtraction + // + Minuend = 0x5a5a5a5a5a5a5a5a; + Subtrahend = 0x3b3b3b3b3b3b3b3b; + Result = 0; + Status = SafeUintnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f1f1f1f1f1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend = 0x5a5a5a5a5a5a5a5a; + Subtrahend = 0x6d6d6d6d6d6d6d6d; + Status = SafeUintnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnSub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Minuend; + INTN Subtrahend; + INTN Result; + + // + // If the result of subtractions doesn't overflow MAX_INTN or + // underflow MIN_INTN, then it's subtraction + // + Minuend = 0x5a5a5a5a5a5a5a5a; + Subtrahend = 0x3a3a3a3a3a3a3a3a; + Result = 0; + Status = SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x2020202020202020, Result); + + Minuend = 0x3a3a3a3a3a3a3a3a; + Subtrahend = 0x5a5a5a5a5a5a5a5a; + Status = SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-2314885530818453536), Result); + + // + // Otherwise should result in an error status + // + Minuend = (-8825501086245354106); + Subtrahend = 8825501086245354106; + Status = SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend = (8825501086245354106); + Subtrahend = (-8825501086245354106); + Status = SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnMult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Multiplicand; + UINTN Multiplier; + UINTN Result; + + // + // If the result of multiplication doesn't overflow MAX_UINTN, it will succeed + // + Multiplicand = 0x123456789a; + Multiplier = 0x1234567; + Result = 0; + Status = SafeUintnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x14b66db9745a07f6, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x123456789a; + Multiplier = 0x12345678; + Status = SafeUintnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnMult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Multiplicand; + INTN Multiplier; + INTN Result; + + // + // If the result of multiplication doesn't overflow MAX_INTN and doesn't + // underflow MIN_UINTN, it will succeed + // + Multiplicand = 0x123456789; + Multiplier = 0x6789abcd; + Result = 0; + Status = SafeIntnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x75cd9045220d6bb5, Result); + + // + // Otherwise should result in an error status + // + Multiplicand = 0x123456789; + Multiplier = 0xa789abcd; + Status = SafeIntnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c index 4f8393cb36c..613b42149cc 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c @@ -203,6 +203,7 @@ Dhcp6EnqueueRetry ( // // Unexpected message type. // + FreePool(TxCb); return EFI_DEVICE_ERROR; } diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index 6b877314bd5..1acbb60d101 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -1348,7 +1348,7 @@ HttpResponseWorker ( // // Process the received the body packet. // - HttpMsg->BodyLength = MIN (Fragment.Len, (UINT32) HttpMsg->BodyLength); + HttpMsg->BodyLength = MIN ((UINTN) Fragment.Len, HttpMsg->BodyLength); CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength); diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h index 6e1f51748a7..34308e016d3 100644 --- a/NetworkPkg/HttpDxe/HttpProto.h +++ b/NetworkPkg/HttpDxe/HttpProto.h @@ -82,6 +82,7 @@ typedef struct { EFI_TLS_VERSION Version; EFI_TLS_CONNECTION_END ConnectionEnd; EFI_TLS_VERIFY VerifyMethod; + EFI_TLS_VERIFY_HOST VerifyHost; EFI_TLS_SESSION_STATE SessionState; } TLS_CONFIG_DATA; diff --git a/NetworkPkg/HttpDxe/HttpsSupport.c b/NetworkPkg/HttpDxe/HttpsSupport.c index 988bbcbce7d..5dfb13bd602 100644 --- a/NetworkPkg/HttpDxe/HttpsSupport.c +++ b/NetworkPkg/HttpDxe/HttpsSupport.c @@ -623,13 +623,16 @@ TlsConfigureSession ( // // TlsConfigData initialization // - HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient; - HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER; - HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted; + HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient; + HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER; + HttpInstance->TlsConfigData.VerifyHost.Flags = EFI_TLS_VERIFY_FLAG_NO_WILDCARDS; + HttpInstance->TlsConfigData.VerifyHost.HostName = HttpInstance->RemoteHost; + HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted; // // EfiTlsConnectionEnd, - // EfiTlsVerifyMethod + // EfiTlsVerifyMethod, + // EfiTlsVerifyHost, // EfiTlsSessionState // Status = HttpInstance->Tls->SetSessionData ( @@ -652,6 +655,16 @@ TlsConfigureSession ( return Status; } + Status = HttpInstance->Tls->SetSessionData ( + HttpInstance->Tls, + EfiTlsVerifyHost, + &HttpInstance->TlsConfigData.VerifyHost, + sizeof (EFI_TLS_VERIFY_HOST) + ); + if (EFI_ERROR (Status)) { + return Status; + } + Status = HttpInstance->Tls->SetSessionData ( HttpInstance->Tls, EfiTlsSessionState, diff --git a/NetworkPkg/Ip4Dxe/Ip4If.c b/NetworkPkg/Ip4Dxe/Ip4If.c index 53a333037f9..348f2e076ae 100644 --- a/NetworkPkg/Ip4Dxe/Ip4If.c +++ b/NetworkPkg/Ip4Dxe/Ip4If.c @@ -491,9 +491,13 @@ Ip4CreateInterface ( IP4_INTERFACE *Interface; EFI_SIMPLE_NETWORK_MODE SnpMode; + if (Mnp == NULL) { + return NULL; + } + Interface = AllocatePool (sizeof (IP4_INTERFACE)); - if ((Interface == NULL) || (Mnp == NULL)) { + if (Interface == NULL) { return NULL; } diff --git a/NetworkPkg/NetworkPkg.ci.yaml b/NetworkPkg/NetworkPkg.ci.yaml new file mode 100644 index 00000000000..70f2e101474 --- /dev/null +++ b/NetworkPkg/NetworkPkg.ci.yaml @@ -0,0 +1,62 @@ +## @file +# CI configuration for NetworkPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "CompilerPlugin": { + "DscPath": "NetworkPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "NetworkPkg/NetworkPkg.dec", + "CryptoPkg/CryptoPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[ + "ShellPkg/ShellPkg.dec" + ], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "NetworkPkg.dsc", + "IgnoreInf": [] + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined ci/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log + "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files + "ExtendWords": [], # words to extend to the dictionary for this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + }, + + "Defines": { + "BLD_*_CONTINUOUS_INTEGRATION": "TRUE", + "BLD_*_NETWORK_ENABLE": "TRUE", + "BLD_*_NETWORK_SNP_ENABLE": "TRUE", + "BLD_*_NETWORK_VLAN_ENABLE": "TRUE", + "BLD_*_NETWORK_IP4_ENABLE": "TRUE", + "BLD_*_NETWORK_IP6_ENABLE": "TRUE", + "BLD_*_NETWORK_TLS_ENABLE": "TRUE", + "BLD_*_NETWORK_HTTP_BOOT_ENABLE": "TRUE", + "BLD_*_NETWORK_ISCSI_ENABLE": "TRUE", + } +} diff --git a/NetworkPkg/NetworkPkg.dsc b/NetworkPkg/NetworkPkg.dsc index 11a29812614..b149453d26f 100644 --- a/NetworkPkg/NetworkPkg.dsc +++ b/NetworkPkg/NetworkPkg.dsc @@ -41,10 +41,15 @@ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf + TlsLib|CryptoPkg/Library/TlsLibNull/TlsLibNull.inf +!else BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf +!endif DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf diff --git a/NetworkPkg/NetworkPkg.uni b/NetworkPkg/NetworkPkg.uni index 19e57a4a60d..328d8cb54a6 100644 --- a/NetworkPkg/NetworkPkg.uni +++ b/NetworkPkg/NetworkPkg.uni @@ -61,6 +61,13 @@ "TRUE - Certificate Authentication feature is enabled.
\n" "FALSE - Does not support Certificate Authentication.
" +#string STR_gEfiNetworkPkgTokenSpaceGuid_PcdSnpCreateExitBootServicesEvent_PROMPT #language en-US "Indicates whether SnpDxe creates event for ExitBootServices() call." + +#string STR_gEfiNetworkPkgTokenSpaceGuid_PcdSnpCreateExitBootServicesEvent_HELP #language en-US "Indicates whether SnpDxe driver will create an event that will be notified

\n" + "upon gBS->ExitBootServices() call.
\n" + "TRUE - Event being triggered upon ExitBootServices call will be created
\n" + "FALSE - Event being triggered upon ExitBootServices call will NOT be created
" + #string STR_gEfiNetworkPkgTokenSpaceGuid_PcdDhcp6UidType_PROMPT #language en-US "Type Value of Dhcp6 Unique Identifier (DUID)." #string STR_gEfiNetworkPkgTokenSpaceGuid_PcdDhcp6UidType_HELP #language en-US "IPv6 DHCP Unique Identifier (DUID) Type configuration (From RFCs 3315 and 6355).\n" diff --git a/NetworkPkg/SnpDxe/Snp.c b/NetworkPkg/SnpDxe/Snp.c index 9fb007f7aec..1099dbfa6a2 100644 --- a/NetworkPkg/SnpDxe/Snp.c +++ b/NetworkPkg/SnpDxe/Snp.c @@ -647,7 +647,7 @@ SimpleNetworkDriverStart ( PxeShutdown (Snp); PxeStop (Snp); - if (FixedPcdGetBool (PcdSnpCreateExitBootServicesEvent)) { + if (PcdGetBool (PcdSnpCreateExitBootServicesEvent)) { // // Create EXIT_BOOT_SERIVES Event // @@ -780,7 +780,7 @@ SimpleNetworkDriverStop ( return Status; } - if (FixedPcdGetBool (PcdSnpCreateExitBootServicesEvent)) { + if (PcdGetBool (PcdSnpCreateExitBootServicesEvent)) { // // Close EXIT_BOOT_SERIVES Event // diff --git a/NetworkPkg/TcpDxe/TcpDispatcher.c b/NetworkPkg/TcpDxe/TcpDispatcher.c index 86beaf8cc51..9ae08ccc1c5 100644 --- a/NetworkPkg/TcpDxe/TcpDispatcher.c +++ b/NetworkPkg/TcpDxe/TcpDispatcher.c @@ -390,6 +390,7 @@ TcpAttachPcb ( ); if (EFI_ERROR (Status)) { IpIoRemoveIp (IpIo, Tcb->IpInfo); + FreePool (Tcb); return Status; } diff --git a/NetworkPkg/TlsDxe/TlsProtocol.c b/NetworkPkg/TlsDxe/TlsProtocol.c index a7a993fc6fc..001e5400d00 100644 --- a/NetworkPkg/TlsDxe/TlsProtocol.c +++ b/NetworkPkg/TlsDxe/TlsProtocol.c @@ -1,7 +1,7 @@ /** @file Implementation of EFI TLS Protocol Interfaces. - Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -56,12 +56,16 @@ TlsSetSessionData ( UINT16 *CipherId; CONST EFI_TLS_CIPHER *TlsCipherList; UINTN CipherCount; + CONST EFI_TLS_VERIFY_HOST *TlsVerifyHost; + EFI_TLS_VERIFY VerifyMethod; + UINTN VerifyMethodSize; UINTN Index; EFI_TPL OldTpl; - Status = EFI_SUCCESS; - CipherId = NULL; + Status = EFI_SUCCESS; + CipherId = NULL; + VerifyMethodSize = sizeof (EFI_TLS_VERIFY); if (This == NULL || Data == NULL || DataSize == 0) { return EFI_INVALID_PARAMETER; @@ -148,6 +152,40 @@ TlsSetSessionData ( } TlsSetVerify (Instance->TlsConn, *((UINT32 *) Data)); + break; + case EfiTlsVerifyHost: + if (DataSize != sizeof (EFI_TLS_VERIFY_HOST)) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + TlsVerifyHost = (CONST EFI_TLS_VERIFY_HOST *) Data; + + if ((TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_ALWAYS_CHECK_SUBJECT) != 0 && + (TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_NEVER_CHECK_SUBJECT) != 0) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + if ((TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_NO_WILDCARDS) != 0 && + ((TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_NO_PARTIAL_WILDCARDS) != 0 || + (TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_MULTI_LABEL_WILDCARDS) != 0)) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Status = This->GetSessionData (This, EfiTlsVerifyMethod, &VerifyMethod, &VerifyMethodSize); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if ((VerifyMethod & EFI_TLS_VERIFY_PEER) == 0) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Status = TlsSetVerifyHost (Instance->TlsConn, TlsVerifyHost->Flags, TlsVerifyHost->HostName); + break; case EfiTlsSessionID: if (DataSize != sizeof (EFI_TLS_SESSION_ID)) { diff --git a/OvmfPkg/Library/ResetSystemLib/ResetSystemLib.c b/OvmfPkg/Library/ResetSystemLib/ResetSystemLib.c index 98dd80e33c0..2f2e1293a3e 100644 --- a/OvmfPkg/Library/ResetSystemLib/ResetSystemLib.c +++ b/OvmfPkg/Library/ResetSystemLib/ResetSystemLib.c @@ -101,24 +101,6 @@ ResetShutdown ( } -/** - Calling this function causes the system to enter a power state for capsule - update. - - Reset update should not return, if it returns, it means the system does - not support capsule update. - -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ) -{ - AcpiPmControl (1); - ASSERT (FALSE); -} - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 05bb6ae136b..1da6cc7f234 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -67,7 +67,7 @@ GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG -!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(TOOL_CHAIN_TAG) != "CLANG9" +!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(TOOL_CHAIN_TAG) != "CLANGPDB" GCC:*_*_*_CC_FLAGS = -mno-mmx -mno-sse !endif @@ -81,14 +81,14 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER] GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 XCODE:*_*_*_DLINK_FLAGS = - CLANGPE: *_*_*_DLINK_FLAGS = /ALIGN:4096 + CLANGPDB:*_*_*_DLINK_FLAGS = /ALIGN:4096 # Force PE/COFF sections to be aligned at 4KB boundaries to support page level # protection of DXE_SMM_DRIVER/SMM_CORE modules [BuildOptions.common.EDKII.DXE_SMM_DRIVER, BuildOptions.common.EDKII.SMM_CORE] GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 XCODE:*_*_*_DLINK_FLAGS = - CLANGPE: *_*_*_DLINK_FLAGS = /ALIGN:4096 + CLANGPDB:*_*_*_DLINK_FLAGS = /ALIGN:4096 ################################################################################ # @@ -431,6 +431,7 @@ !if $(SMM_REQUIRE) == TRUE gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE + gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE !endif [PcdsFixedAtBuild] @@ -574,6 +575,12 @@ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid|{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} !endif +[PcdsDynamicHii] +!if $(TPM2_ENABLE) == TRUE && $(TPM2_CONFIG_ENABLE) == TRUE + gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x0|"1.3"|NV,BS + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x8|3|NV,BS +!endif + ################################################################################ # # Components Section - list of all EDK II Modules needed by this Platform. @@ -631,9 +638,6 @@ NULL|SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.inf NULL|SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf } -!if $(TPM2_CONFIG_ENABLE) == TRUE - SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf -!endif !endif # @@ -901,6 +905,9 @@ } !endif + # + # TPM2 support + # !if $(TPM2_ENABLE) == TRUE SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf { @@ -913,4 +920,7 @@ NULL|SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.inf NULL|SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf } +!if $(TPM2_CONFIG_ENABLE) == TRUE + SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf +!endif !endif diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf index 586bbff0858..63607551ed7 100644 --- a/OvmfPkg/OvmfPkgIa32.fdf +++ b/OvmfPkg/OvmfPkgIa32.fdf @@ -343,6 +343,9 @@ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf !endif +# +# TPM2 support +# !if $(TPM2_ENABLE) == TRUE INF SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf !if $(TPM2_CONFIG_ENABLE) == TRUE diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 4a75a0332e0..213e70345fb 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -67,7 +67,7 @@ GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG -!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(TOOL_CHAIN_TAG) != "CLANG9" +!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(TOOL_CHAIN_TAG) != "CLANGPDB" GCC:*_*_*_CC_FLAGS = -mno-mmx -mno-sse !endif !if $(SOURCE_DEBUG_ENABLE) == TRUE @@ -86,14 +86,14 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER] GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 XCODE:*_*_*_DLINK_FLAGS = - CLANGPE: *_*_*_DLINK_FLAGS = /ALIGN:4096 + CLANGPDB:*_*_*_DLINK_FLAGS = /ALIGN:4096 # Force PE/COFF sections to be aligned at 4KB boundaries to support page level # protection of DXE_SMM_DRIVER/SMM_CORE modules [BuildOptions.common.EDKII.DXE_SMM_DRIVER, BuildOptions.common.EDKII.SMM_CORE] GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 XCODE:*_*_*_DLINK_FLAGS = - CLANGPE: *_*_*_DLINK_FLAGS = /ALIGN:4096 + CLANGPDB:*_*_*_DLINK_FLAGS = /ALIGN:4096 ################################################################################ # @@ -436,6 +436,7 @@ !if $(SMM_REQUIRE) == TRUE gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE + gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE !endif [PcdsFixedAtBuild] @@ -586,6 +587,12 @@ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid|{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} !endif +[PcdsDynamicHii] +!if $(TPM2_ENABLE) == TRUE && $(TPM2_CONFIG_ENABLE) == TRUE + gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x0|"1.3"|NV,BS + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x8|3|NV,BS +!endif + ################################################################################ # # Components Section - list of all EDK II Modules needed by this Platform. @@ -643,9 +650,6 @@ NULL|SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.inf NULL|SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf } -!if $(TPM2_CONFIG_ENABLE) == TRUE - SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf -!endif !endif [Components.X64] @@ -915,6 +919,9 @@ } !endif + # + # TPM2 support + # !if $(TPM2_ENABLE) == TRUE SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf { @@ -927,4 +934,7 @@ NULL|SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.inf NULL|SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf } +!if $(TPM2_CONFIG_ENABLE) == TRUE + SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf +!endif !endif diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf index e49adc425fc..0488e5d95ff 100644 --- a/OvmfPkg/OvmfPkgIa32X64.fdf +++ b/OvmfPkg/OvmfPkgIa32X64.fdf @@ -350,6 +350,9 @@ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf !endif +# +# TPM2 support +# !if $(TPM2_ENABLE) == TRUE INF SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf !if $(TPM2_CONFIG_ENABLE) == TRUE diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index ed54181180f..4d0173dfd29 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -67,7 +67,7 @@ GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG -!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(TOOL_CHAIN_TAG) != "CLANG9" +!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(TOOL_CHAIN_TAG) != "CLANGPDB" GCC:*_*_*_CC_FLAGS = -mno-mmx -mno-sse !endif !if $(SOURCE_DEBUG_ENABLE) == TRUE @@ -86,14 +86,14 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER] GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 XCODE:*_*_*_DLINK_FLAGS = - CLANGPE: *_*_*_DLINK_FLAGS = /ALIGN:4096 + CLANGPDB:*_*_*_DLINK_FLAGS = /ALIGN:4096 # Force PE/COFF sections to be aligned at 4KB boundaries to support page level # protection of DXE_SMM_DRIVER/SMM_CORE modules [BuildOptions.common.EDKII.DXE_SMM_DRIVER, BuildOptions.common.EDKII.SMM_CORE] GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 XCODE:*_*_*_DLINK_FLAGS = - CLANGPE: *_*_*_DLINK_FLAGS = /ALIGN:4096 + CLANGPDB:*_*_*_DLINK_FLAGS = /ALIGN:4096 ################################################################################ # @@ -436,6 +436,7 @@ !if $(SMM_REQUIRE) == TRUE gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire|TRUE gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE + gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE !endif [PcdsFixedAtBuild] @@ -585,6 +586,12 @@ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid|{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} !endif +[PcdsDynamicHii] +!if $(TPM2_ENABLE) == TRUE && $(TPM2_CONFIG_ENABLE) == TRUE + gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x0|"1.3"|NV,BS + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x8|3|NV,BS +!endif + ################################################################################ # # Components Section - list of all EDK II Modules needed by this Platform. @@ -642,9 +649,6 @@ NULL|SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.inf NULL|SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf } -!if $(TPM2_CONFIG_ENABLE) == TRUE - SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf -!endif !endif # @@ -913,6 +917,9 @@ } !endif + # + # TPM2 support + # !if $(TPM2_ENABLE) == TRUE SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf { @@ -925,4 +932,7 @@ NULL|SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.inf NULL|SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf } +!if $(TPM2_CONFIG_ENABLE) == TRUE + SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf +!endif !endif diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf index e49adc425fc..0488e5d95ff 100644 --- a/OvmfPkg/OvmfPkgX64.fdf +++ b/OvmfPkg/OvmfPkgX64.fdf @@ -350,6 +350,9 @@ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf !endif +# +# TPM2 support +# !if $(TPM2_ENABLE) == TRUE INF SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf !if $(TPM2_CONFIG_ENABLE) == TRUE diff --git a/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.c b/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.c index 7fe1663c97d..e42c41c48e1 100644 --- a/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.c +++ b/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.c @@ -65,23 +65,6 @@ ResetShutdown ( } -/** - Calling this function causes the system to enter a power state for capsule - update. - - Reset update should not return, if it returns, it means the system does - not support capsule update. - -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ) -{ - ASSERT (FALSE); -} - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/PcAtChipsetPkg/PcAtChipsetPkg.ci.yaml b/PcAtChipsetPkg/PcAtChipsetPkg.ci.yaml new file mode 100644 index 00000000000..be470807bd9 --- /dev/null +++ b/PcAtChipsetPkg/PcAtChipsetPkg.ci.yaml @@ -0,0 +1,46 @@ +## @file +# CI configuration for PcAtChipsetPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "CompilerPlugin": { + "DscPath": "PcAtChipsetPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "PcAtChipsetPkg/PcAtChipsetPkg.dec", + "UefiCpuPkg/UefiCpuPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "PcAtChipsetPkg.dsc", + "IgnoreInf": [] + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + "SpellCheck": { + "ExtendWords": [ + "ENUMER", # this is part of an IDE enum + "PCATCHIPSET", + "TXRDY" + ] + } +} diff --git a/Readme-RFC.md b/Readme-RFC.md new file mode 100644 index 00000000000..54edb0298f1 --- /dev/null +++ b/Readme-RFC.md @@ -0,0 +1,87 @@ +# Testing + +UEFI FW Testing Infrastructure supports a few types of testing and this page will help provide some high level info and links for more information. + +_Note:_ This document only covers the host-based unit test component, and will grow as more testing features are added. + +## Testing Infrastructure - Definitions and Descriptions + +### Host-Based Unit Tests + +Host-based unit tests let you compile your unit tests to run as an application in the host. This method can also leverage "mocking" objects/functions so that unit tests can validate functionality in isolation and force unexpected edge cases. These unit tests call C functions directly with known parameter sets to force good and bad conditions. They are linked directly against C code in either a library instance or module. These tests leverage a UnitTest Library. + + +#### Library/Protocol/Ppi/Guid Interface + +An interface unit test should be written such that it would be valid against any implementation of the library or protocol. For example, an interface test of DxeImageVerification lib should produce valid results for both an OpenSSL implementation and an implementation using another crypto provider. This is not going to always be true for proprietary implementations of certain libraries, such as libraries that intentionally remove some defined functionality, but it should be the ultimate goal of all interface tests. + +*Note:* This assertion may not hold true for Null library implementations, which will usually return fixed values. + +#### Library/Driver(PEI/DXE/SMM) Implementation + +These tests expect a particular implementation of a library or a driver(PEI/DXE/SMM) and may have far more detailed test cases. For example, an implementation test could be written for both a Null instance and/or a proprietary implementation of a given library. + +### Host-Based Functionality Tests + +#### Tests for a functionality or feature + +These tests are written against larger chunks of business logic and may not have obvious divisions along a single library or protocol/ppi/guid interface. Test targets come from multiple folders or packages. Most of these will likely be UEFI-based tests, rather than host-based tests, but it's conceivable that some host-based examples may exist. + +### Shared Artifacts + +Some testing formats -- especially the host-based unit tests, the fuzzing tests, and the shell-based functional tests -- may find it convenient to share logic in the form of libraries and helpers. These helpers may include mocks and stubs. + +#### Shared Mocks (proposed definition) + +A true mock is a functional interface that has almost no internal logic and is entirely scripted by the testing engine. An example of this might be a mocked version of GetVariable. When this mocked function is called by the business logic (the logic under test), all it does is ask the test what values it should return. Each test can script the order and content of the return values. As such, this is not an actual variable store, but can easily be used to force certain code paths. + +#### Shared Stubs and Other Host Libs (proposed definition) + +Stubs are a little more complicated than mocks. Rather than blindly returning values, stubs might have shorthand implementations behind them. In the example above, instead of GetVariable being entirely scripted, you might have an entire VariableServices interface (GetVariable, SetVariable, GetNextVariableName) that is backed by a simple array or other data structure. This stubbed version would behave very similarly to a real variable store, but can be pre-populated with specific contents prior to each test to demonstrate and excercise desired behaviors. Stubs and Mocks can also be combined in some instances to produce intricate behaviors. + +## Where Should Things Live? + +### Test cases for a library/protocol/ppi/guid interface + +If what's being tested is an interface (e.g. a library with a public header file, like DebugLib), the test should be scoped to the parent package. + +``` +MdePkg/Test/UnitTest/[Library|Protocol|Ppi|Guid]/ +``` + +### Test cases for a library/driver (PEI/DXE/SMM) implementation + +If what's being tested is a specific implementation (e.g. BaseDebugLibSerialPort for DebugLib), the test should be scoped to the implementation directory itself. + +``` +MdePkg/Library/BaseDebugLibSerialPort/UnitTest/ +``` + +### Test cases for a feature under one package + +``` +Pkg/Test/HostFuncTest/ +``` + +### Test cases for a feature that spans multiple packages. + +``` +UefiTestPkg/HostFuncTest/ +``` + +Code/Test | Location +--------- | -------- +`1)` Host-Based Unit Tests for a library/protocol/ppi/guid interface | In the package that declares the library, protocol, ppi or guid interface in its .DEC file. Should be located in the *Pkg/Test/UnitTest/[Library|Protocol|Ppi|Guid] directory. +`2)` Host-Based Unit Tests for a library/driver(PEI/DXE/SMM) implementation | In the directory that contains the library/driver implementation, in a UnitTest subdirectory.

=============
Module Example: *Pkg/Universal/EsrtFmpDxe/UnitTest/
Library Example: *Pkg/Library/BaseMemoryLib/UnitTest/
=============

+`3)` Host-Based Fuzz Tests for a library/protocol/ppi/guid interface | In the package that declares the library, protocol, ppi or guid interface in its .DEC file. Should be located in the *Pkg/Test/FuzzTest/[Library|Protocol|Ppi|Guid] directory. +`4)` Host-Based Fuzz Tests for a library/driver(PEI/DXE/SMM) implementation | In the directory that contains the library/driver implementation, in a FuzzTest subdirectory.

=============
Module Example: *Pkg/Universal/EsrtFmpDxe/FuzzTest/
Library Example: *Pkg/Library/BaseMemoryLib/FuzzTest/
=============

+`5)` Host-Based Tests for a functionality or feature | If the feature is in one package, should be located in the*Pkg/Test/HostFuncTest directory.
(or)
If the feature spans multiple packages, should be located in the
(or)
UefiTestPkg/HostFuncTest directory. +`6)` Non-Host-Based (PEI/DXE/SMM/Shell) Tests for a functionality or feature | If the feature is in one package, should be located in the *Pkg/Test/[Shell|Dxe|Smm|Pei]Test directory.

(Or)

if the feature spans multiple packages, should be located in UefiTestPkg/Feature/Functional/[Shell|Dxe|Smm|Pei]Test

=============
* PEI Example: MP_SERVICE_PPI. Or check MTRR configuration in a notification function.
* SMM Example: a test in a protocol callback function. (It is different with the solution that SmmAgent+ShellApp)
* DXE Example: a test in a UEFI event call back to check SPI/SMRAM status.
* Shell Example: the SMM handler audit test has a shell-based app that interacts with an SMM handler to get information. The SMM paging audit test gathers information about both DXE and SMM. And the SMM paging functional test actually forces errors into SMM via a DXE driver.
=============

+`7)` Host-Based Library Implementations | Host-Based Implementations of common libraries (eg. MemoryAllocationLibHost) should live in the same package that declares the library interface in its .DEC file in the `*Pkg/HostLibrary` directory. Should have 'Host' in the name. +`8)` Host-Based Mocks and Stubs | Mock and Stub libraries should live in the `UefiHostTestPkg/Helpers` with either 'Mock' or 'Stub' in the library name. + +## Copyright + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + diff --git a/Readme.md b/Readme.md index 27e4ce07719..594f16b2075 100644 --- a/Readme.md +++ b/Readme.md @@ -3,6 +3,57 @@ A modern, feature-rich, cross-platform firmware development environment for the UEFI and PI specifications from www.uefi.org. +# Build Status + + + + + + + + + + + + + + + + + + + + + + + + + + +
Host TypeToolchainBranchBuild StatusTest StatusCode Coverage
WindowsVS2019master + + + + + + + + +
UbuntuGCCmaster + + + + + + + + +
+ +[More CI Build information](.pytool/Readme.md) + +# License Details + The majority of the content in the EDK II open source project uses a [BSD-2-Clause Plus Patent License](License.txt). The EDK II open source project contains the following components that are covered by additional licenses: @@ -144,12 +195,12 @@ Signed-off-by: Contributor Name # Submodules Submodule in EDK II is allowed but submodule chain should be avoided -as possible as we can. Currently EDK II contains two submodules +as possible as we can. Currently EDK II contains the following submodules - CryptoPkg/Library/OpensslLib/openssl - ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3 -The latter one is actually required by previous one. It's inevitable +ArmSoftFloatLib is actually required by OpensslLib. It's inevitable in openssl-1.1.1 (since stable201905) for floating point parameter conversion, but should be dropped once there's no such need in future release of openssl. diff --git a/SecurityPkg/Include/Guid/TcgEventHob.h b/SecurityPkg/Include/Guid/TcgEventHob.h index eef3f92abdb..97e40b47d0b 100644 --- a/SecurityPkg/Include/Guid/TcgEventHob.h +++ b/SecurityPkg/Include/Guid/TcgEventHob.h @@ -49,4 +49,15 @@ extern EFI_GUID gTpmErrorHobGuid; extern EFI_GUID gTpm2StartupLocalityHobGuid; +/// +/// The Global ID of a GUIDed HOB used to record TCG 800-155 PlatformId Event. +/// HOB payload is the whole TCG_Sp800_155_PlatformId_Event2 according to TCG 800-155 PlatformId Event. +/// +#define EFI_TCG_800_155_PLATFORM_ID_EVENT_HOB_GUID \ + { \ + 0xe2c3bc69, 0x615c, 0x4b5b, { 0x8e, 0x5c, 0xa0, 0x33, 0xa9, 0xc2, 0x5e, 0xd6 } \ + } + +extern EFI_GUID gTcg800155PlatformIdEventHobGuid; + #endif diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml new file mode 100644 index 00000000000..95321905331 --- /dev/null +++ b/SecurityPkg/SecurityPkg.ci.yaml @@ -0,0 +1,80 @@ +## @file +# CI configuration for SecurityPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "CompilerPlugin": { + "DscPath": "SecurityPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "SecurityPkg/SecurityPkg.dec", + "CryptoPkg/CryptoPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "SecurityPkg.dsc", + "IgnoreInf": [] + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": ["00000000-0000-0000-0000-000000000000"], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [ + "Tpm2InstanceLibDTpm=gEfiTpmDeviceInstanceTpm20DtpmGuid", # by design + ] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined ci/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log + "ExtendWords": [ # words to extend to the dictionary for this package + "shortformed", # tpm acpi + "autodetect", + "blocksid", + "comid", + "cpinsidpin", #OpalSScV2 + "ecdsa", # TPM + "ecschnorr", # TPM + "eisaid", # ACPI + "harddisk", + "hashall", + "hashto", + "kek's", + "lfanew", # PE/COFF + "pcrindex", + "pkglength", + "ppuser", + "preos", + "stclear", + "toctou", + "tpm's", + "tpmcmdbuflength", + "tpmcommlib", + "tpmnvvaluelength", + "wrlocked", + "xored" + ], + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + }, + + "Defines": { + "BLD_*_CONTINUOUS_INTEGRATION": "TRUE", + } +} diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index cac36caf0a0..5335cc53973 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -121,6 +121,10 @@ ## Include/Guid/TcgEventHob.h gTpm2StartupLocalityHobGuid = { 0x397b0c9, 0x22e8, 0x459e, { 0xa4, 0xff, 0x99, 0xbc, 0x65, 0x27, 0x9, 0x29 }} + ## HOB GUID used to record TCG 800-155 PlatformId Event + ## Include/Guid/TcgEventHob.h + gTcg800155PlatformIdEventHobGuid = { 0xe2c3bc69, 0x615c, 0x4b5b, { 0x8e, 0x5c, 0xa0, 0x33, 0xa9, 0xc2, 0x5e, 0xd6 }} + ## HOB GUID used to pass all PEI measured FV info to DXE Driver. # Include/Guid/MeasuredFvHob.h gMeasuredFvHobGuid = { 0xb2360b42, 0x7173, 0x420a, { 0x86, 0x96, 0x46, 0xca, 0x6b, 0xab, 0x10, 0x60 }} diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index 9a254087a34..a2eeadda7a7 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -44,8 +44,6 @@ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf - IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf - OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf TpmCommLib|SecurityPkg/Library/TpmCommLib/TpmCommLib.inf PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf @@ -84,7 +82,13 @@ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf +!endif HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf @@ -95,7 +99,13 @@ [LibraryClasses.common.DXE_DRIVER] HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf +!endif HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf @@ -110,13 +120,25 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER] ReportStatusCodeLib|MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf +!endif HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf [LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.UEFI_APPLICATION] +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf +!endif HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf @@ -127,7 +149,13 @@ MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf +!endif Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf Tcg2PhysicalPresenceLib|SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c index 77905d2bf9e..6bec54b9321 100644 --- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c @@ -2667,7 +2667,6 @@ OpalEfiDriverBindingSupported( { EFI_STATUS Status; EFI_STORAGE_SECURITY_COMMAND_PROTOCOL* SecurityCommand; - EFI_BLOCK_IO_PROTOCOL* BlkIo; if (mOpalEndOfDxe) { return EFI_UNSUPPORTED; @@ -2703,33 +2702,6 @@ OpalEfiDriverBindingSupported( Controller ); - // - // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL - // function APIs - // - Status = gBS->OpenProtocol( - Controller, - &gEfiBlockIoProtocolGuid, - (VOID **)&BlkIo, - This->DriverBindingHandle, - Controller, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - - if (EFI_ERROR(Status)) { - DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n")); - return Status; - } - - // - // Close protocol and reopen in Start call - // - gBS->CloseProtocol( - Controller, - &gEfiBlockIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); return EFI_SUCCESS; } @@ -2827,30 +2799,42 @@ OpalEfiDriverBindingStart( ); if (EFI_ERROR(Status)) { // - // Close storage security that was opened + // Block_IO not supported on handle // - gBS->CloseProtocol( - Controller, - &gEfiStorageSecurityCommandProtocolGuid, - This->DriverBindingHandle, - Controller - ); + if(Status == EFI_UNSUPPORTED) { + BlkIo = NULL; + } else { + // + // Close storage security that was opened + // + gBS->CloseProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + This->DriverBindingHandle, + Controller + ); - FreePool(Dev); - return Status; + FreePool(Dev); + return Status; + } } // // Save mediaId // - Dev->MediaId = BlkIo->Media->MediaId; + if(BlkIo == NULL) { + // If no Block IO present, use defined MediaId value. + Dev->MediaId = 0x0; + } else { + Dev->MediaId = BlkIo->Media->MediaId; - gBS->CloseProtocol( - Controller, - &gEfiBlockIoProtocolGuid, - This->DriverBindingHandle, - Controller + gBS->CloseProtocol( + Controller, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + Controller ); + } // // Acquire Ascii printable name of child, if not found, then ignore device diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index 3cd16c2fa33..1fe1955cab8 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -75,6 +75,7 @@ typedef struct { UINT8 *LastEvent; BOOLEAN EventLogStarted; BOOLEAN EventLogTruncated; + UINTN Next800155EventOffset; } TCG_EVENT_LOG_AREA_STRUCT; typedef struct _TCG_DXE_DATA { @@ -771,16 +772,43 @@ Tcg2GetEventLog ( return EFI_SUCCESS; } +/* + Return if this is a Tcg800155PlatformIdEvent. + + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. + @param[in] NewEventHdrSize New event header size. + @param[in] NewEventData Pointer to the new event data. + @param[in] NewEventSize New event data size. + + @retval TRUE This is a Tcg800155PlatformIdEvent. + @retval FALSE This is NOT a Tcg800155PlatformIdEvent. + +*/ +BOOLEAN +Is800155Event ( + IN VOID *NewEventHdr, + IN UINT32 NewEventHdrSize, + IN UINT8 *NewEventData, + IN UINT32 NewEventSize + ) +{ + if ((((TCG_PCR_EVENT2_HDR *)NewEventHdr)->EventType == EV_NO_ACTION) && + (NewEventSize >= sizeof(TCG_Sp800_155_PlatformId_Event2)) && + (CompareMem (NewEventData, TCG_Sp800_155_PlatformId_Event2_SIGNATURE, + sizeof(TCG_Sp800_155_PlatformId_Event2_SIGNATURE) - 1) == 0)) { + return TRUE; + } + return FALSE; +} + /** Add a new entry to the Event Log. - @param[in, out] EventLogPtr Pointer to the Event Log data. - @param[in, out] LogSize Size of the Event Log. - @param[in] MaxSize Maximum size of the Event Log. - @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. - @param[in] NewEventHdrSize New event header size. - @param[in] NewEventData Pointer to the new event data. - @param[in] NewEventSize New event data size. + @param[in, out] EventLogAreaStruct The event log area data structure + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. + @param[in] NewEventHdrSize New event header size. + @param[in] NewEventData Pointer to the new event data. + @param[in] NewEventSize New event data size. @retval EFI_SUCCESS The new event log entry was added. @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. @@ -788,9 +816,7 @@ Tcg2GetEventLog ( **/ EFI_STATUS TcgCommLogEvent ( - IN OUT UINT8 **EventLogPtr, - IN OUT UINTN *LogSize, - IN UINTN MaxSize, + IN OUT TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct, IN VOID *NewEventHdr, IN UINT32 NewEventHdrSize, IN UINT8 *NewEventData, @@ -798,6 +824,7 @@ TcgCommLogEvent ( ) { UINTN NewLogSize; + BOOLEAN Record800155Event; if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { return EFI_OUT_OF_RESOURCES; @@ -805,23 +832,55 @@ TcgCommLogEvent ( NewLogSize = NewEventHdrSize + NewEventSize; - if (NewLogSize > MAX_ADDRESS - *LogSize) { + if (NewLogSize > MAX_ADDRESS - EventLogAreaStruct->EventLogSize) { return EFI_OUT_OF_RESOURCES; } - if (NewLogSize + *LogSize > MaxSize) { - DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", MaxSize)); - DEBUG ((EFI_D_INFO, " NewLogSize - 0x%x\n", NewLogSize)); - DEBUG ((EFI_D_INFO, " LogSize - 0x%x\n", *LogSize)); - DEBUG ((EFI_D_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); + if (NewLogSize + EventLogAreaStruct->EventLogSize > EventLogAreaStruct->Laml) { + DEBUG ((DEBUG_INFO, " Laml - 0x%x\n", EventLogAreaStruct->Laml)); + DEBUG ((DEBUG_INFO, " NewLogSize - 0x%x\n", NewLogSize)); + DEBUG ((DEBUG_INFO, " LogSize - 0x%x\n", EventLogAreaStruct->EventLogSize)); + DEBUG ((DEBUG_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); return EFI_OUT_OF_RESOURCES; } - *EventLogPtr += *LogSize; - *LogSize += NewLogSize; - CopyMem (*EventLogPtr, NewEventHdr, NewEventHdrSize); + // + // Check 800-155 event + // Record to 800-155 event offset only. + // If the offset is 0, no need to record. + // + Record800155Event = Is800155Event (NewEventHdr, NewEventHdrSize, NewEventData, NewEventSize); + if (Record800155Event) { + if (EventLogAreaStruct->Next800155EventOffset != 0) { + CopyMem ( + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewLogSize, + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, + EventLogAreaStruct->EventLogSize - EventLogAreaStruct->Next800155EventOffset + ); + + CopyMem ( + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, + NewEventHdr, + NewEventHdrSize + ); + CopyMem ( + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewEventHdrSize, + NewEventData, + NewEventSize + ); + + EventLogAreaStruct->Next800155EventOffset += NewLogSize; + EventLogAreaStruct->LastEvent += NewLogSize; + EventLogAreaStruct->EventLogSize += NewLogSize; + } + return EFI_SUCCESS; + } + + EventLogAreaStruct->LastEvent = (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->EventLogSize; + EventLogAreaStruct->EventLogSize += NewLogSize; + CopyMem (EventLogAreaStruct->LastEvent, NewEventHdr, NewEventHdrSize); CopyMem ( - *EventLogPtr + NewEventHdrSize, + EventLogAreaStruct->LastEvent + NewEventHdrSize, NewEventData, NewEventSize ); @@ -873,11 +932,8 @@ TcgDxeLogEvent ( return EFI_VOLUME_FULL; } - EventLogAreaStruct->LastEvent = (UINT8*)(UINTN)EventLogAreaStruct->Lasa; Status = TcgCommLogEvent ( - &EventLogAreaStruct->LastEvent, - &EventLogAreaStruct->EventLogSize, - (UINTN)EventLogAreaStruct->Laml, + EventLogAreaStruct, NewEventHdr, NewEventHdrSize, NewEventData, @@ -907,11 +963,8 @@ TcgDxeLogEvent ( return EFI_VOLUME_FULL; } - EventLogAreaStruct->LastEvent = (UINT8*)(UINTN)EventLogAreaStruct->Lasa; Status = TcgCommLogEvent ( - &EventLogAreaStruct->LastEvent, - &EventLogAreaStruct->EventLogSize, - (UINTN)EventLogAreaStruct->Laml, + EventLogAreaStruct, NewEventHdr, NewEventHdrSize, NewEventData, @@ -1138,11 +1191,25 @@ TcgDxeHashLogExtendEvent ( { EFI_STATUS Status; TPML_DIGEST_VALUES DigestList; + TCG_PCR_EVENT2_HDR NoActionEvent; if (!mTcgDxeData.BsCap.TPMPresentFlag) { return EFI_DEVICE_ERROR; } + if (NewEventHdr->EventType == EV_NO_ACTION) { + // + // Do not do TPM extend for EV_NO_ACTION + // + Status = EFI_SUCCESS; + InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize); + if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) { + Status = TcgDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData); + } + + return Status; + } + Status = HashAndExtend ( NewEventHdr->PCRIndex, HashData, @@ -1202,7 +1269,13 @@ Tcg2HashLogExtendEvent ( DEBUG ((DEBUG_VERBOSE, "Tcg2HashLogExtendEvent ...\n")); - if ((This == NULL) || (DataToHash == 0) || (Event == NULL)) { + if ((This == NULL) || (Event == NULL)) { + return EFI_INVALID_PARAMETER; + } + // + // Do not check hash data size for EV_NO_ACTION event. + // + if ((Event->Header.EventType != EV_NO_ACTION) && (DataToHash == 0)) { return EFI_INVALID_PARAMETER; } @@ -1487,6 +1560,7 @@ SetupEventLog ( } mTcgDxeData.EventLogAreaStruct[Index].Lasa = Lasa; mTcgDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen); + mTcgDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0; if ((PcdGet8(PcdTpm2AcpiTableRev) >= 4) || (mTcg2EventInfo[Index].LogFormat == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)) { @@ -1577,6 +1651,31 @@ SetupEventLog ( (UINT8 *)TcgEfiSpecIdEventStruct, SpecIdEvent.EventSize ); + // + // record the offset at the end of 800-155 event. + // the future 800-155 event can be inserted here. + // + mTcgDxeData.EventLogAreaStruct[Index].Next800155EventOffset = \ + mTcgDxeData.EventLogAreaStruct[Index].EventLogSize; + + // + // Tcg800155PlatformIdEvent. Event format is TCG_PCR_EVENT2 + // + GuidHob.Guid = GetFirstGuidHob (&gTcg800155PlatformIdEventHobGuid); + while (GuidHob.Guid != NULL) { + InitNoActionEvent(&NoActionEvent, GET_GUID_HOB_DATA_SIZE (GuidHob.Guid)); + + Status = TcgDxeLogEvent ( + mTcg2EventInfo[Index].LogFormat, + &NoActionEvent, + sizeof(NoActionEvent.PCRIndex) + sizeof(NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof(NoActionEvent.EventSize), + GET_GUID_HOB_DATA (GuidHob.Guid), + GET_GUID_HOB_DATA_SIZE (GuidHob.Guid) + ); + + GuidHob.Guid = GET_NEXT_HOB (GuidHob); + GuidHob.Guid = GetNextGuidHob (&gTcg800155PlatformIdEventHobGuid, GuidHob.Guid); + } // // EfiStartupLocalityEvent. Event format is TCG_PCR_EVENT2 @@ -1643,6 +1742,7 @@ SetupEventLog ( mTcgDxeData.FinalEventLogAreaStruct[Index].LastEvent = (VOID *)(UINTN)mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa; mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; + mTcgDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; // // Install to configuration table for EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 @@ -1663,6 +1763,7 @@ SetupEventLog ( mTcgDxeData.FinalEventLogAreaStruct[Index].LastEvent = 0; mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; + mTcgDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; } } } diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf index 0127a31e970..576cf80d06d 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf @@ -85,6 +85,7 @@ gTcgEvent2EntryHobGuid ## SOMETIMES_CONSUMES ## HOB gTpm2StartupLocalityHobGuid ## SOMETIMES_CONSUMES ## HOB + gTcg800155PlatformIdEventHobGuid ## SOMETIMES_CONSUMES ## HOB [Protocols] gEfiTcg2ProtocolGuid ## PRODUCES diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c index 1565d4e4021..3788063cc9e 100644 --- a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c +++ b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c @@ -37,6 +37,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #define PERF_ID_TCG2_PEI 0x3080 @@ -78,6 +79,18 @@ EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo; UINT32 mMeasuredMaxChildFvIndex = 0; UINT32 mMeasuredChildFvIndex = 0; +#pragma pack (1) + +#define FV_HANDOFF_TABLE_DESC "Fv(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)" +typedef struct { + UINT8 BlobDescriptionSize; + UINT8 BlobDescription[sizeof(FV_HANDOFF_TABLE_DESC)]; + EFI_PHYSICAL_ADDRESS BlobBase; + UINT64 BlobLength; +} FV_HANDOFF_TABLE_POINTERS2; + +#pragma pack () + /** Measure and record the Firmware Volume Information once FvInfoPPI install. @@ -447,6 +460,48 @@ MeasureCRTMVersion ( ); } +/* + Get the FvName from the FV header. + + Causion: The FV is untrusted input. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + + @return FvName pointer + @retval NULL FvName is NOT found +*/ +VOID * +GetFvName ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; + + if (FvBase >= MAX_ADDRESS) { + return NULL; + } + if (FvLength >= MAX_ADDRESS - FvBase) { + return NULL; + } + if (FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) { + return NULL; + } + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase; + if (FvHeader->ExtHeaderOffset < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) { + return NULL; + } + if (FvHeader->ExtHeaderOffset + sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER) > FvLength) { + return NULL; + } + FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(UINTN)(FvBase + FvHeader->ExtHeaderOffset); + + return &FvExtHeader->FvName; +} + /** Measure FV image. Add it into the measured FV list after the FV is measured successfully. @@ -469,6 +524,9 @@ MeasureFvImage ( UINT32 Index; EFI_STATUS Status; EFI_PLATFORM_FIRMWARE_BLOB FvBlob; + FV_HANDOFF_TABLE_POINTERS2 FvBlob2; + VOID *EventData; + VOID *FvName; TCG_PCR_EVENT_HDR TcgEventHdr; UINT32 Instance; UINT32 Tpm2HashMask; @@ -566,11 +624,26 @@ MeasureFvImage ( // // Init the log event for FV measurement // - FvBlob.BlobBase = FvBase; - FvBlob.BlobLength = FvLength; - TcgEventHdr.PCRIndex = 0; - TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; - TcgEventHdr.EventSize = sizeof (FvBlob); + if (PcdGet32(PcdTcgPfpMeasurementRevision) >= TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2_REV_105) { + FvBlob2.BlobDescriptionSize = sizeof(FvBlob2.BlobDescription); + CopyMem (FvBlob2.BlobDescription, FV_HANDOFF_TABLE_DESC, sizeof(FvBlob2.BlobDescription)); + FvName = GetFvName (FvBase, FvLength); + if (FvName != NULL) { + AsciiSPrint ((CHAR8 *)FvBlob2.BlobDescription, sizeof(FvBlob2.BlobDescription), "Fv(%g)", FvName); + } + FvBlob2.BlobBase = FvBase; + FvBlob2.BlobLength = FvLength; + TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB2; + TcgEventHdr.EventSize = sizeof (FvBlob2); + EventData = &FvBlob2; + } else { + FvBlob.BlobBase = FvBase; + FvBlob.BlobLength = FvLength; + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; + TcgEventHdr.EventSize = sizeof (FvBlob); + EventData = &FvBlob; + } if (Tpm2HashMask == 0) { // @@ -583,9 +656,9 @@ MeasureFvImage ( ); if (!EFI_ERROR(Status)) { - Status = LogHashEvent (&DigestList, &TcgEventHdr, (UINT8*) &FvBlob); - DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase)); - DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength)); + Status = LogHashEvent (&DigestList, &TcgEventHdr, EventData); + DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei has the size: 0x%x\n", FvLength)); } else if (Status == EFI_DEVICE_ERROR) { BuildGuidHob (&gTpmErrorHobGuid,0); REPORT_STATUS_CODE ( @@ -599,13 +672,13 @@ MeasureFvImage ( // Status = HashLogExtendEvent ( 0, - (UINT8*) (UINTN) FvBlob.BlobBase, - (UINTN) FvBlob.BlobLength, - &TcgEventHdr, - (UINT8*) &FvBlob + (UINT8*) (UINTN) FvBase, // HashData + (UINTN) FvLength, // HashDataLen + &TcgEventHdr, // EventHdr + EventData // EventData ); - DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase)); - DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength)); + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvLength)); } if (EFI_ERROR(Status)) { diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf index 30f985b6eac..3d361e8859e 100644 --- a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf +++ b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf @@ -54,6 +54,7 @@ MemoryAllocationLib ReportStatusCodeLib ResetSystemLib + PrintLib [Guids] gTcgEventEntryHobGuid ## PRODUCES ## HOB @@ -74,6 +75,7 @@ [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdTpm2InitializationPolicy ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdTpm2SelfTestPolicy ## SOMETIMES_CONSUMES diff --git a/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c b/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c index bd786bf4791..91aebb62b8b 100644 --- a/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c +++ b/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c @@ -651,6 +651,21 @@ PublishAcpiTable ( ); ASSERT_EFI_ERROR (Status); + // + // Measure to PCR[0] with event EV_POST_CODE ACPI DATA. + // The measurement has to be done before any update. + // Otherwise, the PCR record would be different after TPM FW update + // or the PCD configuration change. + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + Table, + TableSize + ); + // // Update Table version before measuring it to PCR // @@ -664,7 +679,7 @@ PublishAcpiTable ( )); // - // Update TPM2 HID before measuring it to PCR + // Update TPM2 HID after measuring it to PCR // Status = UpdateHID(Table); if (EFI_ERROR(Status)) { @@ -694,19 +709,6 @@ PublishAcpiTable ( } } - // - // Measure to PCR[0] with event EV_POST_CODE ACPI DATA - // - TpmMeasureAndLogData( - 0, - EV_POST_CODE, - EV_POSTCODE_INFO_ACPI_DATA, - ACPI_DATA_LEN, - Table, - TableSize - ); - - ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l')); CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) ); mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS)); @@ -751,6 +753,21 @@ PublishTpm2 ( EFI_TPM2_ACPI_CONTROL_AREA *ControlArea; TPM2_PTP_INTERFACE_TYPE InterfaceType; + // + // Measure to PCR[0] with event EV_POST_CODE ACPI DATA. + // The measurement has to be done before any update. + // Otherwise, the PCR record would be different after event log update + // or the PCD configuration change. + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + &mTpm2AcpiTemplate, + mTpm2AcpiTemplate.Header.Length + ); + mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev); DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision)); @@ -774,18 +791,6 @@ PublishTpm2 ( mTpm2AcpiTemplate.Header.Length = sizeof(EFI_TPM2_ACPI_TABLE); } - // - // Measure to PCR[0] with event EV_POST_CODE ACPI DATA - // - TpmMeasureAndLogData( - 0, - EV_POST_CODE, - EV_POSTCODE_INFO_ACPI_DATA, - ACPI_DATA_LEN, - &mTpm2AcpiTemplate, - mTpm2AcpiTemplate.Header.Length - ); - InterfaceType = PcdGet8(PcdActiveTpmInterfaceType); switch (InterfaceType) { case Tpm2PtpInterfaceCrb: diff --git a/ShellPkg/Application/Shell/FileHandleWrappers.c b/ShellPkg/Application/Shell/FileHandleWrappers.c index 587556c4249..2d7bd7bec67 100644 --- a/ShellPkg/Application/Shell/FileHandleWrappers.c +++ b/ShellPkg/Application/Shell/FileHandleWrappers.c @@ -1644,6 +1644,9 @@ FileInterfaceMemWrite( // if ((UINTN)(MemFile->Position + (*BufferSize)) > (UINTN)(MemFile->BufferSize)) { MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer); + if (MemFile->Buffer == NULL){ + return EFI_OUT_OF_RESOURCES; + } MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD; } CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize); @@ -1661,6 +1664,10 @@ FileInterfaceMemWrite( AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer); if ((UINTN)(MemFile->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(MemFile->BufferSize)) { MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer); + if (MemFile->Buffer == NULL){ + FreePool(AsciiBuffer); + return EFI_OUT_OF_RESOURCES; + } MemFile->BufferSize += AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD; } CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer)); diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c index 5e529b6568a..f0362a42d89 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.c +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -1497,7 +1497,10 @@ InternalShellExecuteDevicePath( ShellParamsProtocol.StdOut = ShellInfoObject.NewShellParametersProtocol->StdOut; ShellParamsProtocol.StdErr = ShellInfoObject.NewShellParametersProtocol->StdErr; Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, Efi_Application, NULL, NULL); - ASSERT_EFI_ERROR(Status); + if (EFI_ERROR (Status)) { + goto UnloadImage; + } + // // Replace Argv[0] with the full path of the binary we're executing: // If the command line was "foo", the binary might be called "foo.efi". diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c index f62d30ef677..500a95a89a8 100644 --- a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c @@ -2462,17 +2462,21 @@ InsertNewGuidNameMapping( IN CONST DUMP_PROTOCOL_INFO DumpFunc OPTIONAL ) { - ASSERT(Guid != NULL); - ASSERT(NameID != 0); + ASSERT (Guid != NULL); + ASSERT (NameID != 0); - mGuidList = ReallocatePool(mGuidListCount * sizeof(GUID_INFO_BLOCK), mGuidListCount+1 * sizeof(GUID_INFO_BLOCK), mGuidList); + mGuidList = ReallocatePool ( + mGuidListCount * sizeof (GUID_INFO_BLOCK), + (mGuidListCount + 1) * sizeof (GUID_INFO_BLOCK), + mGuidList + ); if (mGuidList == NULL) { mGuidListCount = 0; return (EFI_OUT_OF_RESOURCES); } mGuidListCount++; - mGuidList[mGuidListCount - 1].GuidId = AllocateCopyPool(sizeof(EFI_GUID), Guid); + mGuidList[mGuidListCount - 1].GuidId = AllocateCopyPool (sizeof (EFI_GUID), Guid); mGuidList[mGuidListCount - 1].StringId = NameID; mGuidList[mGuidListCount - 1].DumpInfo = DumpFunc; diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c index a569c3c5540..2b2ecb93cef 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c @@ -405,6 +405,39 @@ Dump8Chars ( ); } +/** + This function traces 12 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump12Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ) +{ + Print ( + (Format != NULL) ? Format : L"%c%c%c%c%c%c%c%c%c%c%c%c", + Ptr[0], + Ptr[1], + Ptr[2], + Ptr[3], + Ptr[4], + Ptr[5], + Ptr[6], + Ptr[7], + Ptr[8], + Ptr[9], + Ptr[10], + Ptr[11] + ); +} + /** This function indents and prints the ACPI table Field Name. diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h index 20ca358bddf..6deee3542e0 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h @@ -184,6 +184,22 @@ Dump8Chars ( IN UINT8* Ptr ); +/** + This function traces 12 characters which can be optionally + formated using the format string if specified. + + If no format string is specified the Format must be NULL. + + @param [in] Format Optional format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +VOID +EFIAPI +Dump12Chars ( + IN CONST CHAR16* Format OPTIONAL, + IN UINT8* Ptr + ); + /** This function indents and prints the ACPI table Field Name. @@ -528,6 +544,27 @@ ParseAcpiDsdt ( IN UINT8 AcpiTableRevision ); +/** + This function parses the ACPI FACS table. + When trace is enabled this function parses the FACS table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiFacs ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ); + /** This function parses the ACPI FADT table. This function parses the FADT table and optionally traces the ACPI diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Facs/FacsParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Facs/FacsParser.c new file mode 100644 index 00000000000..d6bea86bdba --- /dev/null +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Facs/FacsParser.c @@ -0,0 +1,71 @@ +/** @file + FACS table parser + + Copyright (c) 2019, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification - January 2019 +**/ + +#include +#include +#include "AcpiParser.h" +#include "AcpiTableParser.h" + +/** + An ACPI_PARSER array describing the ACPI FACS Table. +**/ +STATIC CONST ACPI_PARSER FacsParser[] = { + {L"Signature", 4, 0, L"%c%c%c%c", Dump4Chars, NULL, NULL, NULL}, + {L"Length", 4, 4, L"%d", NULL, NULL, NULL, NULL}, + {L"Hardware Signature", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Firmware Waking Vector", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Global Lock", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 20, L"0x%x", NULL, NULL, NULL, NULL}, + {L"X Firmware Walking Vector", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Version", 1, 32, L"%d", NULL, NULL, NULL, NULL}, + {L"Reserved", 3, 33, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}, + {L"OSPM Flags", 4, 36, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 8, 40, L"%x %x %x %x %x %x %x %x", Dump8Chars, NULL, NULL, + NULL}, + {L"Reserved", 8, 48, L"%x %x %x %x %x %x %x %x", Dump8Chars, NULL, NULL, + NULL}, + {L"Reserved", 8, 56, L"%x %x %x %x %x %x %x %x", Dump8Chars, NULL, NULL, + NULL} +}; + +/** + This function parses the ACPI FACS table. + When trace is enabled this function parses the FACS table and + traces the ACPI table fields. + + This function also performs validation of the ACPI table fields. + + @param [in] Trace If TRUE, trace the ACPI fields. + @param [in] Ptr Pointer to the start of the buffer. + @param [in] AcpiTableLength Length of the ACPI table. + @param [in] AcpiTableRevision Revision of the ACPI table. +**/ +VOID +EFIAPI +ParseAcpiFacs ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + if (!Trace) { + return; + } + + ParseAcpi ( + Trace, + 0, + "FACS", + Ptr, + AcpiTableLength, + PARSER_PARAMS (FacsParser) + ); +} diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c index e40c9ef8ee4..5b8cc174f16 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Fadt/FadtParser.c @@ -5,17 +5,21 @@ SPDX-License-Identifier: BSD-2-Clause-Patent @par Reference(s): - - ACPI 6.2 Specification - Errata A, September 2017 + - ACPI 6.3 Specification - January 2019 **/ #include #include #include "AcpiParser.h" #include "AcpiTableParser.h" +#include "AcpiView.h" // Local variables STATIC CONST UINT32* DsdtAddress; STATIC CONST UINT64* X_DsdtAddress; +STATIC CONST UINT32* Flags; +STATIC CONST UINT32* FirmwareCtrl; +STATIC CONST UINT64* X_FirmwareCtrl; STATIC CONST UINT8* FadtMinorRevision; STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; @@ -24,6 +28,21 @@ STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; **/ #define HW_REDUCED_ACPI BIT20 +/** + Offset to the FACS signature from the start of the FACS. +**/ +#define FACS_SIGNATURE_OFFSET 0 + +/** + Offset to the FACS revision from the start of the FACS. +**/ +#define FACS_VERSION_OFFSET 32 + +/** + Offset to the FACS length from the start of the FACS. +**/ +#define FACS_LENGTH_OFFSET 4 + /** Get the ACPI XSDT header info. **/ @@ -113,7 +132,8 @@ ValidateFlags ( **/ STATIC CONST ACPI_PARSER FadtParser[] = { PARSE_ACPI_HEADER (&AcpiHdrInfo), - {L"FIRMWARE_CTRL", 4, 36, L"0x%x", NULL, NULL, ValidateFirmwareCtrl, NULL}, + {L"FIRMWARE_CTRL", 4, 36, L"0x%x", NULL, (VOID**)&FirmwareCtrl, + ValidateFirmwareCtrl, NULL}, {L"DSDT", 4, 40, L"0x%x", NULL, (VOID**)&DsdtAddress, NULL, NULL}, {L"Reserved", 1, 44, L"%x", NULL, NULL, NULL, NULL}, {L"Preferred_PM_Profile", 1, 45, L"0x%x", NULL, NULL, NULL, NULL}, @@ -150,13 +170,13 @@ STATIC CONST ACPI_PARSER FadtParser[] = { {L"CENTURY", 1, 108, L"0x%x", NULL, NULL, NULL, NULL}, {L"IAPC_BOOT_ARCH", 2, 109, L"0x%x", NULL, NULL, NULL, NULL}, {L"Reserved", 1, 111, L"0x%x", NULL, NULL, NULL, NULL}, - {L"Flags", 4, 112, L"0x%x", NULL, NULL, ValidateFlags, NULL}, + {L"Flags", 4, 112, L"0x%x", NULL, (VOID**)&Flags, ValidateFlags, NULL}, {L"RESET_REG", 12, 116, NULL, DumpGas, NULL, NULL, NULL}, {L"RESET_VALUE", 1, 128, L"0x%x", NULL, NULL, NULL, NULL}, {L"ARM_BOOT_ARCH", 2, 129, L"0x%x", NULL, NULL, NULL, NULL}, {L"FADT Minor Version", 1, 131, L"0x%x", NULL, (VOID**)&FadtMinorRevision, NULL, NULL}, - {L"X_FIRMWARE_CTRL", 8, 132, L"0x%lx", NULL, NULL, + {L"X_FIRMWARE_CTRL", 8, 132, L"0x%lx", NULL, (VOID**)&X_FirmwareCtrl, ValidateXFirmwareCtrl, NULL}, {L"X_DSDT", 8, 140, L"0x%lx", NULL, (VOID**)&X_DsdtAddress, NULL, NULL}, {L"X_PM1a_EVT_BLK", 12, 148, NULL, DumpGas, NULL, NULL, NULL}, @@ -192,7 +212,13 @@ ParseAcpiFadt ( IN UINT8 AcpiTableRevision ) { - UINT8* DsdtPtr; + EFI_STATUS Status; + UINT8* DsdtPtr; + UINT8* FirmwareCtrlPtr; + UINT32 FacsSignature; + UINT32 FacsLength; + UINT8 FacsRevision; + PARSE_ACPI_TABLE_PROC FacsParserProc; ParseAcpi ( Trace, @@ -214,6 +240,60 @@ ParseAcpiFadt ( } } + // If X_FIRMWARE_CTRL is not zero then use X_FIRMWARE_CTRL and ignore + // FIRMWARE_CTRL, else use FIRMWARE_CTRL. + if ((X_FirmwareCtrl != NULL) && (*X_FirmwareCtrl != 0)) { + FirmwareCtrlPtr = (UINT8*)(UINTN)(*X_FirmwareCtrl); + } else if ((FirmwareCtrl != NULL) && (*FirmwareCtrl != 0)) { + FirmwareCtrlPtr = (UINT8*)(UINTN)(*FirmwareCtrl); + } else { + FirmwareCtrlPtr = NULL; + // if HW_REDUCED_ACPI flag is not set, both FIRMWARE_CTRL and + // X_FIRMWARE_CTRL cannot be zero, and the FACS Table must be + // present. + if ((Trace) && + (Flags != NULL) && + ((*Flags & EFI_ACPI_6_3_HW_REDUCED_ACPI) != 0)) { + IncrementErrorCount (); + Print (L"ERROR: No FACS table found, " + L"both X_FIRMWARE_CTRL and FIRMWARE_CTRL are zero.\n"); + } + } + + if (FirmwareCtrlPtr != NULL) { + // The FACS table does not have a standard ACPI table header. Therefore, + // the signature, length and version needs to be initially parsed. + // The FACS signature is 4 bytes starting at offset 0. + FacsSignature = *(UINT32*)(FirmwareCtrlPtr + FACS_SIGNATURE_OFFSET); + + // The FACS length is 4 bytes starting at offset 4. + FacsLength = *(UINT32*)(FirmwareCtrlPtr + FACS_LENGTH_OFFSET); + + // The FACS version is 1 byte starting at offset 32. + FacsRevision = *(UINT8*)(FirmwareCtrlPtr + FACS_VERSION_OFFSET); + + Trace = ProcessTableReportOptions ( + FacsSignature, + FirmwareCtrlPtr, + FacsLength + ); + + Status = GetParser (FacsSignature, &FacsParserProc); + if (EFI_ERROR (Status)) { + Print ( + L"ERROR: No registered parser found for FACS.\n" + ); + return; + } + + FacsParserProc ( + Trace, + FirmwareCtrlPtr, + FacsLength, + FacsRevision + ); + } + // If X_DSDT is not zero then use X_DSDT and ignore DSDT, // else use DSDT. if (*X_DsdtAddress != 0) { diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c index f1cdb9ac01d..72289c7680b 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent @par Reference(s): - - IO Remapping Table, Platform Design Document, Revision C, 15 May 2017 + - IO Remapping Table, Platform Design Document, Revision D, March 2018 **/ #include @@ -193,7 +193,9 @@ STATIC CONST ACPI_PARSER IortNodeSmmuV3Parser[] = { {L"Event", 4, 44, L"0x%x", NULL, NULL, NULL, NULL}, {L"PRI", 4, 48, L"0x%x", NULL, NULL, NULL, NULL}, {L"GERR", 4, 52, L"0x%x", NULL, NULL, NULL, NULL}, - {L"Sync", 4, 56, L"0x%x", NULL, NULL, NULL, NULL} + {L"Sync", 4, 56, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Proximity domain", 4, 60, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Device ID mapping index", 4, 64, L"%d", NULL, NULL, NULL, NULL} }; /** @@ -231,7 +233,9 @@ STATIC CONST ACPI_PARSER IortNodeRootComplexParser[] = { PARSE_IORT_NODE_HEADER (NULL, NULL), {L"Memory access properties", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, {L"ATS Attribute", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, - {L"PCI Segment number", 4, 28, L"0x%x", NULL, NULL, NULL, NULL} + {L"PCI Segment number", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Memory access size limit", 1, 32, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 3, 33, L"%x %x %x", Dump3Chars, NULL, NULL, NULL} }; /** @@ -239,9 +243,10 @@ STATIC CONST ACPI_PARSER IortNodeRootComplexParser[] = { **/ STATIC CONST ACPI_PARSER IortNodePmcgParser[] = { PARSE_IORT_NODE_HEADER (ValidatePmcgIdMappingCount, NULL), - {L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Page 0 Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, {L"Overflow interrupt GSIV", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, {L"Node reference", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Page 1 Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL} }; /** diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Srat/SratParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Srat/SratParser.c index a8aa420487b..6fe7bf68113 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Srat/SratParser.c +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Srat/SratParser.c @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent @par Reference(s): - - ACPI 6.2 Specification - Errata A, September 2017 + - ACPI 6.3 Specification - January 2019 **/ #include @@ -17,6 +17,7 @@ // Local Variables STATIC CONST UINT8* SratRAType; STATIC CONST UINT8* SratRALength; +STATIC CONST UINT8* SratDeviceHandleType; STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; /** @@ -40,6 +41,167 @@ ValidateSratReserved ( } } +/** + This function validates the Device Handle Type field in the Generic Initiator + Affinity Structure. + + @param [in] Ptr Pointer to the start of the field data. + @param [in] Context Pointer to context specific information e.g. this + could be a pointer to the ACPI table header. +**/ +STATIC +VOID +EFIAPI +ValidateSratDeviceHandleType ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + UINT8 DeviceHandleType; + + DeviceHandleType = *Ptr; + + if (DeviceHandleType > EFI_ACPI_6_3_PCI_DEVICE_HANDLE) { + IncrementErrorCount (); + Print ( + L"\nERROR: Invalid Device Handle Type: %d. Must be between 0 and %d.", + DeviceHandleType, + EFI_ACPI_6_3_PCI_DEVICE_HANDLE + ); + } +} + +/** + This function traces the PCI BDF Number field inside Device Handle - PCI + + @param [in] Format Format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +STATIC +VOID +EFIAPI +DumpSratPciBdfNumber ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ) +{ + CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH]; + + Print (L"\n"); + + /* + The PCI BDF Number subfields are printed in the order specified in the ACPI + specification. The format of the 16-bit PCI BDF Number field is as follows: + + +-----+------+------+ + |DEV | FUNC | BUS | + +-----+------+------+ + |15:11| 10:8 | 7:0 | + +-----+------+------+ + */ + + // Print PCI Bus Number (Bits 7:0 of Byte 2) + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"PCI Bus Number" + ); + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + *Ptr + ); + + Ptr++; + + // Print PCI Device Number (Bits 7:3 of Byte 3) + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"PCI Device Number" + ); + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + (*Ptr & (BIT7 | BIT6 | BIT5 | BIT4 | BIT3)) >> 3 + ); + + // PCI Function Number (Bits 2:0 of Byte 3) + UnicodeSPrint ( + Buffer, + sizeof (Buffer), + L"PCI Function Number" + ); + PrintFieldName (4, Buffer); + Print ( + L"0x%x\n", + *Ptr & (BIT2 | BIT1 | BIT0) + ); +} + +/** + An ACPI_PARSER array describing the Device Handle - ACPI +**/ +STATIC CONST ACPI_PARSER SratDeviceHandleAcpiParser[] = { + {L"ACPI_HID", 8, 0, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"ACPI_UID", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 12, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the Device Handle - PCI +**/ +STATIC CONST ACPI_PARSER SratDeviceHandlePciParser[] = { + {L"PCI Segment", 2, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI BDF Number", 2, 2, NULL, DumpSratPciBdfNumber, NULL, NULL, NULL}, + {L"Reserved", 12, 4, L"%x %x %x %x - %x %x %x %x - %x %x %x %x", Dump12Chars, + NULL, NULL, NULL} +}; + +/** + This function traces the Device Handle field inside Generic Initiator + Affinity Structure. + + @param [in] Format Format string for tracing the data. + @param [in] Ptr Pointer to the start of the buffer. +**/ +STATIC +VOID +EFIAPI +DumpSratDeviceHandle ( + IN CONST CHAR16* Format, + IN UINT8* Ptr + ) +{ + if (SratDeviceHandleType == NULL) { + IncrementErrorCount (); + Print (L"\nERROR: Device Handle Type read incorrectly.\n"); + return; + } + + Print (L"\n"); + + if (*SratDeviceHandleType == EFI_ACPI_6_3_ACPI_DEVICE_HANDLE) { + ParseAcpi ( + TRUE, + 2, + NULL, + Ptr, + sizeof (EFI_ACPI_6_3_DEVICE_HANDLE_ACPI), + PARSER_PARAMS (SratDeviceHandleAcpiParser) + ); + } else if (*SratDeviceHandleType == EFI_ACPI_6_3_PCI_DEVICE_HANDLE) { + ParseAcpi ( + TRUE, + 2, + NULL, + Ptr, + sizeof (EFI_ACPI_6_3_DEVICE_HANDLE_PCI), + PARSER_PARAMS (SratDeviceHandlePciParser) + ); + } +} + /** This function traces the APIC Proximity Domain field. @@ -103,6 +265,22 @@ STATIC CONST ACPI_PARSER SratGicITSAffinityParser[] = { {L"ITS Id", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, }; +/** + An ACPI_PARSER array describing the Generic Initiator Affinity Structure +**/ +STATIC CONST ACPI_PARSER SratGenericInitiatorAffinityParser[] = { + {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Length", 1, 1, L"0x%x", NULL, NULL, NULL, NULL}, + + {L"Reserved", 1, 2, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Device Handle Type", 1, 3, L"%d", NULL, (VOID**)&SratDeviceHandleType, + ValidateSratDeviceHandleType, NULL}, + {L"Proximity Domain", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Device Handle", 16, 8, L"%s", DumpSratDeviceHandle, NULL, NULL, NULL}, + {L"Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 28, L"0x%x", NULL, NULL, NULL, NULL} +}; + /** An ACPI_PARSER array describing the Memory Affinity structure. **/ @@ -183,6 +361,7 @@ ParseAcpiSrat ( UINT8* ResourcePtr; UINT32 GicCAffinityIndex; UINT32 GicITSAffinityIndex; + UINT32 GenericInitiatorAffinityIndex; UINT32 MemoryAffinityIndex; UINT32 ApicSapicAffinityIndex; UINT32 X2ApicAffinityIndex; @@ -190,6 +369,7 @@ ParseAcpiSrat ( GicCAffinityIndex = 0; GicITSAffinityIndex = 0; + GenericInitiatorAffinityIndex = 0; MemoryAffinityIndex = 0; ApicSapicAffinityIndex = 0; X2ApicAffinityIndex = 0; @@ -232,7 +412,7 @@ ParseAcpiSrat ( } switch (*SratRAType) { - case EFI_ACPI_6_2_GICC_AFFINITY: + case EFI_ACPI_6_3_GICC_AFFINITY: AsciiSPrint ( Buffer, sizeof (Buffer), @@ -249,7 +429,7 @@ ParseAcpiSrat ( ); break; - case EFI_ACPI_6_2_GIC_ITS_AFFINITY: + case EFI_ACPI_6_3_GIC_ITS_AFFINITY: AsciiSPrint ( Buffer, sizeof (Buffer), @@ -266,7 +446,24 @@ ParseAcpiSrat ( ); break; - case EFI_ACPI_6_2_MEMORY_AFFINITY: + case EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY: + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "Generic Initiator Affinity Structure [%d]", + GenericInitiatorAffinityIndex++ + ); + ParseAcpi ( + TRUE, + 2, + Buffer, + ResourcePtr, + *SratRALength, + PARSER_PARAMS (SratGenericInitiatorAffinityParser) + ); + break; + + case EFI_ACPI_6_3_MEMORY_AFFINITY: AsciiSPrint ( Buffer, sizeof (Buffer), @@ -283,7 +480,7 @@ ParseAcpiSrat ( ); break; - case EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY: + case EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY: AsciiSPrint ( Buffer, sizeof (Buffer), @@ -300,7 +497,7 @@ ParseAcpiSrat ( ); break; - case EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY: + case EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_AFFINITY: AsciiSPrint ( Buffer, sizeof (Buffer), diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c index 3ee0f0fe421..e0d5a810855 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c @@ -29,6 +29,7 @@ ACPI_TABLE_PARSER ParserList[] = { {EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE, ParseAcpiDbg2}, {EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, ParseAcpiDsdt}, + {EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE, ParseAcpiFacs}, {EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, ParseAcpiFadt}, {EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE, ParseAcpiGtdt}, {EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE, ParseAcpiIort}, diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf index 1e2fa52b00a..ea504c934ae 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf @@ -31,6 +31,7 @@ Parsers/Bgrt/BgrtParser.c Parsers/Dbg2/Dbg2Parser.c Parsers/Dsdt/DsdtParser.c + Parsers/Facs/FacsParser.c Parsers/Fadt/FadtParser.c Parsers/Gtdt/GtdtParser.c Parsers/Iort/IortParser.c diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c index 4c48b65fbc1..345808a1eac 100644 --- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c @@ -107,9 +107,13 @@ CommandInit( // // Without clue provided use the first Unicode Collation2 protocol. + // This may happen when PlatformLang is NULL or when no installed Unicode + // Collation2 protocol instance supports PlatformLang. // - if (PlatformLang == NULL) { + if (gUnicodeCollation == NULL) { gUnicodeCollation = Uc; + } + if (PlatformLang == NULL) { break; } diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c index fd324cc4a86..c9814e400c1 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c @@ -1602,7 +1602,7 @@ FileBufferSave ( // // set status string // - Str = CatSPrint (NULL, L"%d Lines Wrote", NumLines); + Str = CatSPrint (NULL, L"%d Lines Written", NumLines); if (Str == NULL) { return EFI_OUT_OF_RESOURCES; } diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c index b393f2a4233..bb324ceafcc 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c @@ -368,7 +368,7 @@ HFileImageSave ( // // set status string // - Str = CatSPrint(NULL, L"%d Lines Wrote", NumLines); + Str = CatSPrint(NULL, L"%d Lines Written", NumLines); StatusBarSetStatusString (Str); FreePool (Str); diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.c index fdb7a47d332..b80e16d56a6 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.c @@ -2,7 +2,7 @@ Build a table, each item is (Key, Info) pair. And give a interface of query a string out of a table. - Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.
(C) Copyright 2016-2019 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -1432,6 +1432,10 @@ TABLE_ITEM SystemSlotTypeTable[] = { 0x23, L"PCI Express Mini 76-pin (CEM spec. 2.0) Corresponds to Display-Mini card" }, + { + SlotTypeCXLFlexbus10, + L"CXL Flexbus 1.0" + }, { 0xA0, L"PC-98/C20 " @@ -1523,6 +1527,30 @@ TABLE_ITEM SystemSlotTypeTable[] = { { 0xB6, L"PCI Express Gen 3 X16" + }, + { + SlotTypePciExpressGen4, + L"PCI Express Gen 4" + }, + { + SlotTypePciExpressGen4X1, + L"PCI Express Gen 4 X1" + }, + { + SlotTypePciExpressGen4X2, + L"PCI Express Gen 4 X2" + }, + { + SlotTypePciExpressGen4X4, + L"PCI Express Gen 4 X4" + }, + { + SlotTypePciExpressGen4X8, + L"PCI Express Gen 4 X8" + }, + { + SlotTypePciExpressGen4X16, + L"PCI Express Gen 4 X16" } }; @@ -2266,6 +2294,10 @@ TABLE_ITEM PMALocationTable[] = { { 0xA3, L" PC-98/Local bus add-on card" + }, + { + MemoryArrayLocationCXLFlexbus10AddonCard, + L" CXL Flexbus 1.0 add-on card" } }; @@ -2391,6 +2423,10 @@ TABLE_ITEM MemoryDeviceFormFactorTable[] = { { 0x0F, L" FB-DIMM" + }, + { + MemoryFormFactorDie, + L" Die" } }; @@ -2506,6 +2542,14 @@ TABLE_ITEM MemoryDeviceTypeTable[] = { { 0x1F, L" Logical non-volatile device" + }, + { + MemoryTypeHBM, + L" HBM (High Bandwidth Memory)" + }, + { + MemoryTypeHBM2, + L" HBM2 (High Bandwidth Memory Generation 2)" } }; @@ -2594,8 +2638,8 @@ TABLE_ITEM MemoryDeviceMemoryTechnologyTable[] = { L" NVDIMM-P" }, { - 0x07, - L" Intel persistent memory" + MemoryTechnologyIntelPersistentMemory, + L" Intel Optane DC Persistent Memory" } }; diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.h index 60fb42c59c3..756009b2f2a 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.h +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView/QueryTable.h @@ -2,7 +2,7 @@ Build a table, each item is (key, info) pair. and give a interface of query a string out of a table. - Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -10,6 +10,8 @@ #ifndef _SMBIOS_QUERY_TABLE_H_ #define _SMBIOS_QUERY_TABLE_H_ +#include + #define QUERY_TABLE_UNFOUND 0xFF typedef struct TABLE_ITEM { diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c index adeb987e6ec..da2b1acab47 100644 --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c @@ -417,6 +417,8 @@ FileTimeToLocalTime ( @param[in] Found Set to TRUE, if anyone were found. @param[in] Count The count of bits enabled in Attribs. @param[in] TimeZone The current time zone offset. + @param[in] ListUnfiltered TRUE to request listing the directory contents + unfiltered. @retval SHELL_SUCCESS the printing was sucessful. **/ @@ -429,7 +431,8 @@ PrintLsOutput( IN CONST CHAR16 *SearchString, IN BOOLEAN *Found, IN CONST UINTN Count, - IN CONST INT16 TimeZone + IN CONST INT16 TimeZone, + IN CONST BOOLEAN ListUnfiltered ) { EFI_STATUS Status; @@ -500,7 +503,7 @@ PrintLsOutput( // Change the file time to local time. // Status = gRT->GetTime(&LocalTime, NULL); - if (!EFI_ERROR (Status)) { + if (!EFI_ERROR (Status) && (LocalTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE)) { if ((Node->Info->CreateTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) && (Node->Info->CreateTime.Month >= 1 && Node->Info->CreateTime.Month <= 12)) { // @@ -555,7 +558,7 @@ PrintLsOutput( HeaderPrinted = TRUE; } - if (!Sfo && ShellStatus != SHELL_ABORTED) { + if (!Sfo && ShellStatus != SHELL_ABORTED && HeaderPrinted) { PrintNonSfoFooter(FileCount, FileSize, DirCount); } } @@ -602,7 +605,8 @@ PrintLsOutput( SearchString, &FoundOne, Count, - TimeZone); + TimeZone, + FALSE); // // Since it's running recursively, we have to break immediately when returned SHELL_ABORTED @@ -619,7 +623,21 @@ PrintLsOutput( ShellCloseFileMetaArg(&ListHead); if (Found == NULL && !FoundOne) { - return (SHELL_NOT_FOUND); + if (ListUnfiltered) { + // + // When running "ls" without any filtering request, avoid outputing + // "File not found" when the directory is entirely empty, but print + // header and footer stating "0 File(s), 0 Dir(s)". + // + if (!Sfo) { + PrintNonSfoHeader (RootPath); + if (ShellStatus != SHELL_ABORTED) { + PrintNonSfoFooter (FileCount, FileSize, DirCount); + } + } + } else { + return (SHELL_NOT_FOUND); + } } if (Found != NULL) { @@ -662,6 +680,7 @@ ShellCommandRunLs ( UINTN Size; EFI_TIME TheTime; CHAR16 *SearchString; + BOOLEAN ListUnfiltered; Size = 0; FullPath = NULL; @@ -673,6 +692,7 @@ ShellCommandRunLs ( SearchString = NULL; CurDir = NULL; Count = 0; + ListUnfiltered = FALSE; // // initialize the shell lib (we must be in non-auto-init...) @@ -768,6 +788,7 @@ ShellCommandRunLs ( ShellStatus = SHELL_NOT_FOUND; ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls"); } + ListUnfiltered = TRUE; // // Copy to the 2 strings for starting path and file search string // @@ -808,6 +829,7 @@ ShellCommandRunLs ( // // is listing ends with a directory, then we list all files in that directory // + ListUnfiltered = TRUE; StrnCatGrow(&SearchString, NULL, L"*", 0); } else { // @@ -839,7 +861,8 @@ ShellCommandRunLs ( SearchString, NULL, Count, - TheTime.TimeZone + TheTime.TimeZone, + ListUnfiltered ); if (ShellStatus == SHELL_NOT_FOUND) { ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LS_FILE_NOT_FOUND), gShellLevel2HiiHandle, L"ls", FullPath); diff --git a/ShellPkg/ShellPkg.ci.yaml b/ShellPkg/ShellPkg.ci.yaml new file mode 100644 index 00000000000..67de34a2556 --- /dev/null +++ b/ShellPkg/ShellPkg.ci.yaml @@ -0,0 +1,55 @@ +## @file +# CI configuration for ShellPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "CompilerPlugin": { + "DscPath": "ShellPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "ShellPkg/ShellPkg.dec", + "NetworkPkg/NetworkPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "ShellPkg.dsc", + "IgnoreInf": [ + "ShellPkg/Application/ShellCTestApp/ShellCTestApp.inf", + "ShellPkg/Application/ShellExecTestApp/SA.inf", + "ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.inf" + ] + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [ + "Shell=gUefiShellFileGuid", # by design + ] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined ci/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log + "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files + "ExtendWords": [], # words to extend to the dictionary for this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + } +} diff --git a/SignedCapsulePkg/SignedCapsulePkg.dsc b/SignedCapsulePkg/SignedCapsulePkg.dsc index 03f714f9a79..c5080ec1dd4 100644 --- a/SignedCapsulePkg/SignedCapsulePkg.dsc +++ b/SignedCapsulePkg/SignedCapsulePkg.dsc @@ -87,8 +87,6 @@ AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf - IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf - OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf EdkiiSystemCapsuleLib|SignedCapsulePkg/Library/EdkiiSystemCapsuleLib/EdkiiSystemCapsuleLib.inf IniParsingLib|SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.inf @@ -116,7 +114,13 @@ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf +!endif [LibraryClasses.common.DXE_CORE] HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf @@ -125,7 +129,13 @@ [LibraryClasses.common.DXE_DRIVER] HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf +!endif CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf @@ -133,7 +143,13 @@ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf +!endif CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf @@ -150,19 +166,37 @@ MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf +!endif [LibraryClasses.common.UEFI_DRIVER] HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf +!endif [LibraryClasses.common.UEFI_APPLICATION] HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf +!else + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf +!endif [PcdsFixedAtBuild] gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0f diff --git a/StandaloneMmPkg/StandaloneMmPkg.dsc b/StandaloneMmPkg/StandaloneMmPkg.dsc index 8a68d397469..f9546e182e2 100644 --- a/StandaloneMmPkg/StandaloneMmPkg.dsc +++ b/StandaloneMmPkg/StandaloneMmPkg.dsc @@ -2,7 +2,7 @@ # Standalone MM Platform. # # Copyright (c) 2015, Intel Corporation. All rights reserved.
-# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+# Copyright (c) 2016 - 2019, ARM Limited. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -19,7 +19,7 @@ PLATFORM_VERSION = 1.0 DSC_SPECIFICATION = 0x00010011 OUTPUT_DIRECTORY = Build/StandaloneMm - SUPPORTED_ARCHITECTURES = IA32|X64|AARCH64 + SUPPORTED_ARCHITECTURES = AARCH64 BUILD_TARGETS = DEBUG|RELEASE SKUID_IDENTIFIER = DEFAULT diff --git a/UefiCpuPkg/Include/Guid/MicrocodePatchHob.h b/UefiCpuPkg/Include/Guid/MicrocodePatchHob.h new file mode 100644 index 00000000000..2d307fbffbf --- /dev/null +++ b/UefiCpuPkg/Include/Guid/MicrocodePatchHob.h @@ -0,0 +1,44 @@ +/** @file + The microcode patch HOB is used to store the information of: + A. Base address and size of the loaded microcode patches data; + B. Detected microcode patch for each processor within system. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _MICROCODE_PATCH_HOB_H_ +#define _MICROCODE_PATCH_HOB_H_ + +extern EFI_GUID gEdkiiMicrocodePatchHobGuid; + +// +// The EDKII microcode patch HOB will be produced by MpInitLib and it can be +// consumed by modules that want to detect/apply microcode patches. +// +typedef struct { + // + // The base address of the microcode patches data after being loaded into + // memory. + // + UINT64 MicrocodePatchAddress; + // + // The total size of the loaded microcode patches. + // + UINT64 MicrocodePatchRegionSize; + // + // The number of processors within the system. + // + UINT32 ProcessorCount; + // + // An array with 'ProcessorCount' elements that stores the offset (with + // regard to 'MicrocodePatchAddress') of the detected microcode patch + // (including the CPU_MICROCODE_HEADER data structure) for each processor. + // If no microcode patch is detected for certain processor, the relating + // element will be set to MAX_UINT64. + // + UINT64 ProcessorSpecificPatchOffset[0]; +} EDKII_MICROCODE_PATCH_HOB; + +#endif diff --git a/UefiCpuPkg/Include/Library/RegisterCpuFeaturesLib.h b/UefiCpuPkg/Include/Library/RegisterCpuFeaturesLib.h index 5bd464b32e2..f370373d630 100644 --- a/UefiCpuPkg/Include/Library/RegisterCpuFeaturesLib.h +++ b/UefiCpuPkg/Include/Library/RegisterCpuFeaturesLib.h @@ -25,7 +25,7 @@ #define CPU_FEATURE_MWAIT 2 #define CPU_FEATURE_ACPI 3 #define CPU_FEATURE_EIST 4 -#define CPU_FEATURE_XD 5 +#define CPU_FEATURE_RESERVED_5 5 #define CPU_FEATURE_FASTSTRINGS 6 #define CPU_FEATURE_VMX 7 #define CPU_FEATURE_SMX 8 diff --git a/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.c b/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.c index 238632f88af..3ebd9392a9e 100644 --- a/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.c +++ b/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.c @@ -66,17 +66,6 @@ CpuCommonFeaturesLibConstructor ( ); ASSERT_EFI_ERROR (Status); } - if (IsCpuFeatureSupported (CPU_FEATURE_XD)) { - Status = RegisterCpuFeature ( - "Execute Disable", - NULL, - ExecuteDisableSupport, - ExecuteDisableInitialize, - CPU_FEATURE_XD, - CPU_FEATURE_END - ); - ASSERT_EFI_ERROR (Status); - } if (IsCpuFeatureSupported (CPU_FEATURE_FASTSTRINGS)) { Status = RegisterCpuFeature ( "FastStrings", diff --git a/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.inf b/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.inf index 6347c8997d5..7fbcd8da0e5 100644 --- a/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.inf +++ b/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.inf @@ -4,7 +4,7 @@ # This library registers CPU features defined in Intel(R) 64 and IA-32 # Architectures Software Developer's Manual. # -# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -34,7 +34,6 @@ C1e.c ClockModulation.c Eist.c - ExecuteDisable.c FastStrings.c FeatureControl.c LimitCpuIdMaxval.c diff --git a/UefiCpuPkg/Library/CpuCommonFeaturesLib/ExecuteDisable.c b/UefiCpuPkg/Library/CpuCommonFeaturesLib/ExecuteDisable.c deleted file mode 100644 index 75ea16309d6..00000000000 --- a/UefiCpuPkg/Library/CpuCommonFeaturesLib/ExecuteDisable.c +++ /dev/null @@ -1,95 +0,0 @@ -/** @file - Execute Disable feature. - - Copyright (c) 2017, Intel Corporation. All rights reserved.
- SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include "CpuCommonFeatures.h" - -/** - Detects if Execute Disable feature supported on current processor. - - @param[in] ProcessorNumber The index of the CPU executing this function. - @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION - structure for the CPU executing this function. - @param[in] ConfigData A pointer to the configuration buffer returned - by CPU_FEATURE_GET_CONFIG_DATA. NULL if - CPU_FEATURE_GET_CONFIG_DATA was not provided in - RegisterCpuFeature(). - - @retval TRUE Execute Disable feature is supported. - @retval FALSE Execute Disable feature is not supported. - - @note This service could be called by BSP/APs. -**/ -BOOLEAN -EFIAPI -ExecuteDisableSupport ( - IN UINTN ProcessorNumber, - IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo, - IN VOID *ConfigData OPTIONAL - ) -{ - UINT32 Eax; - CPUID_EXTENDED_CPU_SIG_EDX Edx; - - AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL); - if (Eax <= CPUID_EXTENDED_FUNCTION) { - // - // Extended CPUID functions are not supported on this processor. - // - return FALSE; - } - - AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32); - return (Edx.Bits.NX != 0); -} - -/** - Initializes Execute Disable feature to specific state. - - @param[in] ProcessorNumber The index of the CPU executing this function. - @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION - structure for the CPU executing this function. - @param[in] ConfigData A pointer to the configuration buffer returned - by CPU_FEATURE_GET_CONFIG_DATA. NULL if - CPU_FEATURE_GET_CONFIG_DATA was not provided in - RegisterCpuFeature(). - @param[in] State If TRUE, then the Execute Disable feature must be enabled. - If FALSE, then the Execute Disable feature must be disabled. - - @retval RETURN_SUCCESS Execute Disable feature is initialized. - - @note This service could be called by BSP only. -**/ -RETURN_STATUS -EFIAPI -ExecuteDisableInitialize ( - IN UINTN ProcessorNumber, - IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo, - IN VOID *ConfigData, OPTIONAL - IN BOOLEAN State - ) -{ - // - // The scope of the MSR_IA32_EFER is core for below processor type, only program - // MSR_IA32_EFER for thread 0 in each core. - // - if (IS_SILVERMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) { - if (CpuInfo->ProcessorInfo.Location.Thread != 0) { - return RETURN_SUCCESS; - } - } - - CPU_REGISTER_TABLE_WRITE_FIELD ( - ProcessorNumber, - Msr, - MSR_IA32_EFER, - MSR_IA32_EFER_REGISTER, - Bits.NXE, - (State) ? 1 : 0 - ); - return RETURN_SUCCESS; -} diff --git a/UefiCpuPkg/Library/CpuCommonFeaturesLib/FeatureControl.c b/UefiCpuPkg/Library/CpuCommonFeaturesLib/FeatureControl.c index 38d3f53f564..b4474d2fab4 100644 --- a/UefiCpuPkg/Library/CpuCommonFeaturesLib/FeatureControl.c +++ b/UefiCpuPkg/Library/CpuCommonFeaturesLib/FeatureControl.c @@ -240,6 +240,15 @@ SmxInitialize ( Status = RETURN_UNSUPPORTED; } + CPU_REGISTER_TABLE_WRITE_FIELD ( + ProcessorNumber, + ControlRegister, + 4, + IA32_CR4, + Bits.SMXE, + (State) ? 1 : 0 + ) + CPU_REGISTER_TABLE_TEST_THEN_WRITE_FIELD ( ProcessorNumber, Msr, diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf index cd912ab0c5e..bf5d18d521e 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf @@ -68,5 +68,6 @@ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuShadowMicrocodeByFit ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES diff --git a/UefiCpuPkg/Library/MpInitLib/Microcode.c b/UefiCpuPkg/Library/MpInitLib/Microcode.c index 199b1f23ce3..9389e52ae51 100644 --- a/UefiCpuPkg/Library/MpInitLib/Microcode.c +++ b/UefiCpuPkg/Library/MpInitLib/Microcode.c @@ -1,7 +1,7 @@ /** @file Implementation of loading microcode on processors. - Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -65,13 +65,15 @@ GetCurrentMicrocodeSignature ( It does not guarantee that the data has not been modified. CPU has its own mechanism to verify Microcode Binary part. - @param[in] CpuMpData The pointer to CPU MP Data structure. - @param[in] IsBspCallIn Indicate whether the caller is BSP or not. + @param[in] CpuMpData The pointer to CPU MP Data structure. + @param[in] ProcessorNumber The handle number of the processor. The range is + from 0 to the total number of logical processors + minus 1. **/ VOID MicrocodeDetect ( IN CPU_MP_DATA *CpuMpData, - IN BOOLEAN IsBspCallIn + IN UINTN ProcessorNumber ) { UINT32 ExtendedTableLength; @@ -83,6 +85,7 @@ MicrocodeDetect ( UINTN Index; UINT8 PlatformId; CPUID_VERSION_INFO_EAX Eax; + CPU_AP_DATA *CpuData; UINT32 CurrentRevision; UINT32 LatestRevision; UINTN TotalSize; @@ -90,14 +93,8 @@ MicrocodeDetect ( UINT32 InCompleteCheckSum32; BOOLEAN CorrectMicrocode; VOID *MicrocodeData; - MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr; - UINT32 ProcessorFlags; UINT32 ThreadId; - - // - // set ProcessorFlags to suppress incorrect compiler/analyzer warnings - // - ProcessorFlags = 0; + BOOLEAN IsBspCallIn; if (CpuMpData->MicrocodePatchRegionSize == 0) { // @@ -107,12 +104,7 @@ MicrocodeDetect ( } CurrentRevision = GetCurrentMicrocodeSignature (); - if (CurrentRevision != 0 && !IsBspCallIn) { - // - // Skip loading microcode if it has been loaded successfully - // - return; - } + IsBspCallIn = (ProcessorNumber == (UINTN)CpuMpData->BspNumber) ? TRUE : FALSE; GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId); if (ThreadId != 0) { @@ -123,28 +115,25 @@ MicrocodeDetect ( } ExtendedTableLength = 0; - // - // Here data of CPUID leafs have not been collected into context buffer, so - // GetProcessorCpuid() cannot be used here to retrieve CPUID data. - // - AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL); - - // - // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID - // - PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID); - PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId; + Eax.Uint32 = CpuMpData->CpuData[ProcessorNumber].ProcessorSignature; + PlatformId = CpuMpData->CpuData[ProcessorNumber].PlatformId; // // Check whether AP has same processor with BSP. // If yes, direct use microcode info saved by BSP. // if (!IsBspCallIn) { - if ((CpuMpData->ProcessorSignature == Eax.Uint32) && - (CpuMpData->ProcessorFlags & (1 << PlatformId)) != 0) { - MicrocodeData = (VOID *)(UINTN) CpuMpData->MicrocodeDataAddress; - LatestRevision = CpuMpData->MicrocodeRevision; - goto Done; + // + // Get the CPU data for BSP + // + CpuData = &(CpuMpData->CpuData[CpuMpData->BspNumber]); + if ((CpuData->ProcessorSignature == Eax.Uint32) && + (CpuData->PlatformId == PlatformId) && + (CpuData->MicrocodeEntryAddr != 0)) { + MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN) CpuData->MicrocodeEntryAddr; + MicrocodeData = (VOID *) (MicrocodeEntryPoint + 1); + LatestRevision = MicrocodeEntryPoint->UpdateRevision; + goto Done; } } @@ -212,7 +201,6 @@ MicrocodeDetect ( CheckSum32 += MicrocodeEntryPoint->Checksum; if (CheckSum32 == 0) { CorrectMicrocode = TRUE; - ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags; } } else if ((MicrocodeEntryPoint->DataSize != 0) && (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) { @@ -256,7 +244,6 @@ MicrocodeDetect ( // Find one // CorrectMicrocode = TRUE; - ProcessorFlags = ExtendedTable->ProcessorFlag; break; } } @@ -295,6 +282,16 @@ MicrocodeDetect ( } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd)); Done: + if (LatestRevision != 0) { + // + // Save the detected microcode patch entry address (including the + // microcode patch header) for each processor. + // It will be used when building the microcode patch cache HOB. + // + CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr = + (UINTN) MicrocodeData - sizeof (CPU_MICROCODE_HEADER); + } + if (LatestRevision > CurrentRevision) { // // BIOS only authenticate updates that contain a numerically larger revision @@ -318,16 +315,416 @@ MicrocodeDetect ( ReleaseSpinLock(&CpuMpData->MpLock); } } +} + +/** + Determine if a microcode patch matchs the specific processor signature and flag. - if (IsBspCallIn && (LatestRevision != 0)) { + @param[in] CpuMpData The pointer to CPU MP Data structure. + @param[in] ProcessorSignature The processor signature field value + supported by a microcode patch. + @param[in] ProcessorFlags The prcessor flags field value supported by + a microcode patch. + + @retval TRUE The specified microcode patch will be loaded. + @retval FALSE The specified microcode patch will not be loaded. +**/ +BOOLEAN +IsProcessorMatchedMicrocodePatch ( + IN CPU_MP_DATA *CpuMpData, + IN UINT32 ProcessorSignature, + IN UINT32 ProcessorFlags + ) +{ + UINTN Index; + CPU_AP_DATA *CpuData; + + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { + CpuData = &CpuMpData->CpuData[Index]; + if ((ProcessorSignature == CpuData->ProcessorSignature) && + (ProcessorFlags & (1 << CpuData->PlatformId)) != 0) { + return TRUE; + } + } + + return FALSE; +} + +/** + Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode + patch header with the CPUID and PlatformID of the processors within + system to decide if it will be copied into memory. + + @param[in] CpuMpData The pointer to CPU MP Data structure. + @param[in] MicrocodeEntryPoint The pointer to the microcode patch header. + + @retval TRUE The specified microcode patch need to be loaded. + @retval FALSE The specified microcode patch dosen't need to be loaded. +**/ +BOOLEAN +IsMicrocodePatchNeedLoad ( + IN CPU_MP_DATA *CpuMpData, + CPU_MICROCODE_HEADER *MicrocodeEntryPoint + ) +{ + BOOLEAN NeedLoad; + UINTN DataSize; + UINTN TotalSize; + CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader; + UINT32 ExtendedTableCount; + CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable; + UINTN Index; + + // + // Check the 'ProcessorSignature' and 'ProcessorFlags' in microcode patch header. + // + NeedLoad = IsProcessorMatchedMicrocodePatch ( + CpuMpData, + MicrocodeEntryPoint->ProcessorSignature.Uint32, + MicrocodeEntryPoint->ProcessorFlags + ); + + // + // If the Extended Signature Table exists, check if the processor is in the + // support list + // + DataSize = MicrocodeEntryPoint->DataSize; + TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize; + if ((!NeedLoad) && (DataSize != 0) && + (TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) + + sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) { + ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint) + + DataSize + sizeof (CPU_MICROCODE_HEADER)); + ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount; + ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1); + + for (Index = 0; Index < ExtendedTableCount; Index ++) { + // + // Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended + // Signature Table entry with the CPUID and PlatformID of the processors + // within system to decide if it will be copied into memory + // + NeedLoad = IsProcessorMatchedMicrocodePatch ( + CpuMpData, + ExtendedTable->ProcessorSignature.Uint32, + ExtendedTable->ProcessorFlag + ); + if (NeedLoad) { + break; + } + ExtendedTable ++; + } + } + + return NeedLoad; +} + + +/** + Actual worker function that shadows the required microcode patches into memory. + + @param[in, out] CpuMpData The pointer to CPU MP Data structure. + @param[in] Patches The pointer to an array of information on + the microcode patches that will be loaded + into memory. + @param[in] PatchCount The number of microcode patches that will + be loaded into memory. + @param[in] TotalLoadSize The total size of all the microcode patches + to be loaded. +**/ +VOID +ShadowMicrocodePatchWorker ( + IN OUT CPU_MP_DATA *CpuMpData, + IN MICROCODE_PATCH_INFO *Patches, + IN UINTN PatchCount, + IN UINTN TotalLoadSize + ) +{ + UINTN Index; + VOID *MicrocodePatchInRam; + UINT8 *Walker; + + ASSERT ((Patches != NULL) && (PatchCount != 0)); + + MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize)); + if (MicrocodePatchInRam == NULL) { + return; + } + + // + // Load all the required microcode patches into memory + // + for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) { + CopyMem ( + Walker, + (VOID *) Patches[Index].Address, + Patches[Index].Size + ); + Walker += Patches[Index].Size; + } + + // + // Update the microcode patch related fields in CpuMpData + // + CpuMpData->MicrocodePatchAddress = (UINTN) MicrocodePatchInRam; + CpuMpData->MicrocodePatchRegionSize = TotalLoadSize; + + DEBUG (( + DEBUG_INFO, + "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n", + __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize + )); + + return; +} + +/** + Shadow the required microcode patches data into memory according to PCD + PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize. + + @param[in, out] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +ShadowMicrocodePatchByPcd ( + IN OUT CPU_MP_DATA *CpuMpData + ) +{ + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN DataSize; + UINTN TotalSize; + MICROCODE_PATCH_INFO *PatchInfoBuffer; + UINTN MaxPatchNumber; + UINTN PatchCount; + UINTN TotalLoadSize; + + // + // Initialize the microcode patch related fields in CpuMpData as the values + // specified by the PCD pair. If the microcode patches are loaded into memory, + // these fields will be updated. + // + CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress); + CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize); + + MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress; + MicrocodeEnd = (UINTN) MicrocodeEntryPoint + + (UINTN) CpuMpData->MicrocodePatchRegionSize; + if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) { // - // Save BSP processor info and microcode info for later AP use. + // There is no microcode patches // - CpuMpData->ProcessorSignature = Eax.Uint32; - CpuMpData->ProcessorFlags = ProcessorFlags; - CpuMpData->MicrocodeDataAddress = (UINTN) MicrocodeData; - CpuMpData->MicrocodeRevision = LatestRevision; - DEBUG ((DEBUG_INFO, "BSP Microcode:: signature [0x%08x], ProcessorFlags [0x%08x], \ - MicroData [0x%08x], Revision [0x%08x]\n", Eax.Uint32, ProcessorFlags, (UINTN) MicrocodeData, LatestRevision)); + return; + } + + PatchCount = 0; + MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM; + TotalLoadSize = 0; + PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO)); + if (PatchInfoBuffer == NULL) { + return; + } + + // + // Process the header of each microcode patch within the region. + // The purpose is to decide which microcode patch(es) will be loaded into memory. + // + do { + if (MicrocodeEntryPoint->HeaderVersion != 0x1) { + // + // Padding data between the microcode patches, skip 1KB to check next entry. + // + MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB); + continue; + } + + DataSize = MicrocodeEntryPoint->DataSize; + TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize; + if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) || + ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd || + (DataSize & 0x3) != 0 || + (TotalSize & (SIZE_1KB - 1)) != 0 || + TotalSize < DataSize + ) { + // + // Not a valid microcode header, skip 1KB to check next entry. + // + MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB); + continue; + } + + if (IsMicrocodePatchNeedLoad (CpuMpData, MicrocodeEntryPoint)) { + PatchCount++; + if (PatchCount > MaxPatchNumber) { + // + // Current 'PatchInfoBuffer' cannot hold the information, double the size + // and allocate a new buffer. + // + if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) { + // + // Overflow check for MaxPatchNumber + // + goto OnExit; + } + + PatchInfoBuffer = ReallocatePool ( + MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO), + 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO), + PatchInfoBuffer + ); + if (PatchInfoBuffer == NULL) { + goto OnExit; + } + MaxPatchNumber = MaxPatchNumber * 2; + } + + // + // Store the information of this microcode patch + // + PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint; + PatchInfoBuffer[PatchCount - 1].Size = TotalSize; + TotalLoadSize += TotalSize; + } + + // + // Process the next microcode patch + // + MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize); + } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd)); + + if (PatchCount != 0) { + DEBUG (( + DEBUG_INFO, + "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n", + __FUNCTION__, PatchCount, TotalLoadSize + )); + + ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize); + } + +OnExit: + if (PatchInfoBuffer != NULL) { + FreePool (PatchInfoBuffer); + } + return; +} + +/** + Shadow the required microcode patches data into memory according to FIT microcode entry. + + @param[in, out] CpuMpData The pointer to CPU MP Data structure. + + @return EFI_SUCCESS Microcode patch is shadowed into memory. + @return EFI_UNSUPPORTED FIT based microcode shadowing is not supported. + @return EFI_OUT_OF_RESOURCES No enough memory resource. + @return EFI_NOT_FOUND There is something wrong in FIT microcode entry. + +**/ +EFI_STATUS +ShadowMicrocodePatchByFit ( + IN OUT CPU_MP_DATA *CpuMpData + ) +{ + UINT64 FitPointer; + FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry; + UINT32 EntryNum; + UINT32 Index; + MICROCODE_PATCH_INFO *PatchInfoBuffer; + UINTN MaxPatchNumber; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN PatchCount; + UINTN TotalSize; + UINTN TotalLoadSize; + + if (!FeaturePcdGet (PcdCpuShadowMicrocodeByFit)) { + return EFI_UNSUPPORTED; + } + + FitPointer = *(UINT64 *) (UINTN) FIT_POINTER_ADDRESS; + if ((FitPointer == 0) || + (FitPointer == 0xFFFFFFFFFFFFFFFF) || + (FitPointer == 0xEEEEEEEEEEEEEEEE)) { + // + // No FIT table. + // + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *) (UINTN) FitPointer; + if ((FitEntry[0].Type != FIT_TYPE_00_HEADER) || + (FitEntry[0].Address != FIT_TYPE_00_SIGNATURE)) { + // + // Invalid FIT table, treat it as no FIT table. + // + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + + EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF; + + // + // Calculate microcode entry number + // + MaxPatchNumber = 0; + for (Index = 0; Index < EntryNum; Index++) { + if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) { + MaxPatchNumber++; + } + } + if (MaxPatchNumber == 0) { + return EFI_NOT_FOUND; + } + + PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO)); + if (PatchInfoBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Fill up microcode patch info buffer according to FIT table. + // + PatchCount = 0; + TotalLoadSize = 0; + for (Index = 0; Index < EntryNum; Index++) { + if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) { + MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) FitEntry[Index].Address; + TotalSize = (MicrocodeEntryPoint->DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize; + if (IsMicrocodePatchNeedLoad (CpuMpData, MicrocodeEntryPoint)) { + PatchInfoBuffer[PatchCount].Address = (UINTN) MicrocodeEntryPoint; + PatchInfoBuffer[PatchCount].Size = TotalSize; + TotalLoadSize += TotalSize; + PatchCount++; + } + } + } + + if (PatchCount != 0) { + DEBUG (( + DEBUG_INFO, + "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n", + __FUNCTION__, PatchCount, TotalLoadSize + )); + + ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize); + } + + FreePool (PatchInfoBuffer); + return EFI_SUCCESS; +} + +/** + Shadow the required microcode patches data into memory. + + @param[in, out] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +ShadowMicrocodeUpdatePatch ( + IN OUT CPU_MP_DATA *CpuMpData + ) +{ + EFI_STATUS Status; + + Status = ShadowMicrocodePatchByFit (CpuMpData); + if (EFI_ERROR (Status)) { + ShadowMicrocodePatchByPcd (CpuMpData); } } diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index 622b70ca3c4..6ec9b172b86 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -1,7 +1,7 @@ /** @file CPU MP Initialize Library common functions. - Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -399,12 +399,16 @@ ApInitializeSync ( ) { CPU_MP_DATA *CpuMpData; + UINTN ProcessorNumber; + EFI_STATUS Status; CpuMpData = (CPU_MP_DATA *) Buffer; + Status = GetProcessorNumber (CpuMpData, &ProcessorNumber); + ASSERT_EFI_ERROR (Status); // // Load microcode on AP // - MicrocodeDetect (CpuMpData, FALSE); + MicrocodeDetect (CpuMpData, ProcessorNumber); // // Sync BSP's MTRR table to AP // @@ -458,12 +462,13 @@ CollectProcessorCount ( ) { UINTN Index; + CPU_INFO_IN_HOB *CpuInfoInHob; + BOOLEAN X2Apic; // // Send 1st broadcast IPI to APs to wakeup APs // - CpuMpData->InitFlag = ApInitConfig; - CpuMpData->X2ApicEnable = FALSE; + CpuMpData->InitFlag = ApInitConfig; WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE); CpuMpData->InitFlag = ApInitDone; ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); @@ -474,13 +479,29 @@ CollectProcessorCount ( CpuPause (); } + + // + // Enable x2APIC mode if + // 1. Number of CPU is greater than 255; or + // 2. There are any logical processors reporting an Initial APIC ID of 255 or greater. + // + X2Apic = FALSE; if (CpuMpData->CpuCount > 255) { // // If there are more than 255 processor found, force to enable X2APIC // - CpuMpData->X2ApicEnable = TRUE; + X2Apic = TRUE; + } else { + CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob; + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { + if (CpuInfoInHob[Index].InitialApicId >= 0xFF) { + X2Apic = TRUE; + break; + } + } } - if (CpuMpData->X2ApicEnable) { + + if (X2Apic) { DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n")); // // Wakeup all APs to enable x2APIC mode @@ -531,7 +552,8 @@ InitializeApData ( IN UINT64 ApTopOfStack ) { - CPU_INFO_IN_HOB *CpuInfoInHob; + CPU_INFO_IN_HOB *CpuInfoInHob; + MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr; CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob; CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId (); @@ -541,15 +563,17 @@ InitializeApData ( CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE; CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE; - if (CpuInfoInHob[ProcessorNumber].InitialApicId >= 0xFF) { - // - // Set x2APIC mode if there are any logical processor reporting - // an Initial APIC ID of 255 or greater. - // - AcquireSpinLock(&CpuMpData->MpLock); - CpuMpData->X2ApicEnable = TRUE; - ReleaseSpinLock(&CpuMpData->MpLock); - } + + PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID); + CpuMpData->CpuData[ProcessorNumber].PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId; + + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuMpData->CpuData[ProcessorNumber].ProcessorSignature, + NULL, + NULL, + NULL + ); InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock); SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle); @@ -608,10 +632,6 @@ ApWakeupFunction ( ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize; BistData = *(UINT32 *) ((UINTN) ApTopOfStack - sizeof (UINTN)); // - // Do some AP initialize sync - // - ApInitializeSync (CpuMpData); - // // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment, // to initialize AP in InitConfig path. // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs. @@ -1595,7 +1615,6 @@ MpInitLibInitialize ( UINTN ApResetVectorSize; UINTN BackupBufferAddr; UINTN ApIdtBase; - VOID *MicrocodePatchInRam; OldCpuMpData = GetCpuMpDataFromGuidedHob (); if (OldCpuMpData == NULL) { @@ -1663,39 +1682,7 @@ MpInitLibInitialize ( CpuMpData->SwitchBspFlag = FALSE; CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1); CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber); - if (OldCpuMpData == NULL) { - CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize); - // - // If platform has more than one CPU, relocate microcode to memory to reduce - // loading microcode time. - // - MicrocodePatchInRam = NULL; - if (MaxLogicalProcessorNumber > 1) { - MicrocodePatchInRam = AllocatePages ( - EFI_SIZE_TO_PAGES ( - (UINTN)CpuMpData->MicrocodePatchRegionSize - ) - ); - } - if (MicrocodePatchInRam == NULL) { - // - // there is only one processor, or no microcode patch is available, or - // memory allocation failed - // - CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress); - } else { - // - // there are multiple processors, and a microcode patch is available, and - // memory allocation succeeded - // - CopyMem ( - MicrocodePatchInRam, - (VOID *)(UINTN)PcdGet64 (PcdCpuMicrocodePatchAddress), - (UINTN)CpuMpData->MicrocodePatchRegionSize - ); - CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam; - } - }else { + if (OldCpuMpData != NULL) { CpuMpData->MicrocodePatchRegionSize = OldCpuMpData->MicrocodePatchRegionSize; CpuMpData->MicrocodePatchAddress = OldCpuMpData->MicrocodePatchAddress; } @@ -1742,14 +1729,6 @@ MpInitLibInitialize ( (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index); } // - // Load Microcode on BSP - // - MicrocodeDetect (CpuMpData, TRUE); - // - // Store BSP's MTRR setting - // - MtrrGetAllMtrrs (&CpuMpData->MtrrTable); - // // Enable the local APIC for Virtual Wire Mode. // ProgramVirtualWireMode (); @@ -1761,6 +1740,11 @@ MpInitLibInitialize ( // CollectProcessorCount (CpuMpData); } + + // + // Load required microcode patches data into memory + // + ShadowMicrocodeUpdatePatch (CpuMpData); } else { // // APs have been wakeup before, just get the CPU Information @@ -1768,33 +1752,36 @@ MpInitLibInitialize ( // CpuMpData->CpuCount = OldCpuMpData->CpuCount; CpuMpData->BspNumber = OldCpuMpData->BspNumber; - CpuMpData->InitFlag = ApInitReconfig; CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob; CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob; for (Index = 0; Index < CpuMpData->CpuCount; Index++) { InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock); - if (CpuInfoInHob[Index].InitialApicId >= 255 || Index > 254) { - CpuMpData->X2ApicEnable = TRUE; - } CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE; CpuMpData->CpuData[Index].ApFunction = 0; CopyMem (&CpuMpData->CpuData[Index].VolatileRegisters, &VolatileRegisters, sizeof (CPU_VOLATILE_REGISTERS)); } - if (MaxLogicalProcessorNumber > 1) { - // - // Wakeup APs to do some AP initialize sync - // - WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE); - // - // Wait for all APs finished initialization - // - while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { - CpuPause (); - } - CpuMpData->InitFlag = ApInitDone; - for (Index = 0; Index < CpuMpData->CpuCount; Index++) { - SetApState (&CpuMpData->CpuData[Index], CpuStateIdle); - } + } + + // + // Detect and apply Microcode on BSP + // + MicrocodeDetect (CpuMpData, CpuMpData->BspNumber); + // + // Store BSP's MTRR setting + // + MtrrGetAllMtrrs (&CpuMpData->MtrrTable); + + // + // Wakeup APs to do some AP initialize sync (Microcode & MTRR) + // + if (CpuMpData->CpuCount > 1) { + WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE); + while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { + CpuPause (); + } + + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { + SetApState (&CpuMpData->CpuData[Index], CpuStateIdle); } } diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h index 107872b3679..7c62d75accf 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -1,7 +1,7 @@ /** @file Common header file for MP Initialize Library. - Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -29,6 +29,9 @@ #include #include +#include + + #define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P') #define CPU_INIT_MP_LIB_HOB_GUID \ @@ -43,6 +46,19 @@ #define CPU_SWITCH_STATE_STORED 1 #define CPU_SWITCH_STATE_LOADED 2 +// +// Default maximum number of entries to store the microcode patches information +// +#define DEFAULT_MAX_MICROCODE_PATCH_NUM 8 + +// +// Data structure for microcode patch information +// +typedef struct { + UINTN Address; + UINTN Size; +} MICROCODE_PATCH_INFO; + // // CPU exchange information for switch BSP // @@ -122,6 +138,9 @@ typedef struct { UINT64 CurrentTime; UINT64 TotalTime; EFI_EVENT WaitEvent; + UINT32 ProcessorSignature; + UINT8 PlatformId; + UINT64 MicrocodeEntryAddr; } CPU_AP_DATA; // @@ -200,6 +219,8 @@ struct _CPU_MP_DATA { UINT64 CpuInfoInHob; UINT32 CpuCount; UINT32 BspNumber; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; // // The above fields data will be passed from PEI to DXE // Please make sure the fields offset same in the different @@ -227,7 +248,6 @@ struct _CPU_MP_DATA { UINTN **FailedCpuList; AP_INIT_STATE InitFlag; - BOOLEAN X2ApicEnable; BOOLEAN SwitchBspFlag; UINTN NewBspNumber; CPU_EXCHANGE_ROLE_INFO BSPInfo; @@ -244,13 +264,6 @@ struct _CPU_MP_DATA { UINT8 Vector; BOOLEAN PeriodicMode; BOOLEAN TimerInterruptState; - UINT64 MicrocodePatchAddress; - UINT64 MicrocodePatchRegionSize; - - UINT32 ProcessorSignature; - UINT32 ProcessorFlags; - UINT64 MicrocodeDataAddress; - UINT32 MicrocodeRevision; // // Whether need to use Init-Sipi-Sipi to wake up the APs. @@ -565,13 +578,25 @@ CheckAndUpdateApsStatus ( /** Detect whether specified processor can find matching microcode patch and load it. - @param[in] CpuMpData The pointer to CPU MP Data structure. - @param[in] IsBspCallIn Indicate whether the caller is BSP or not. + @param[in] CpuMpData The pointer to CPU MP Data structure. + @param[in] ProcessorNumber The handle number of the processor. The range is + from 0 to the total number of logical processors + minus 1. **/ VOID MicrocodeDetect ( IN CPU_MP_DATA *CpuMpData, - IN BOOLEAN IsBspCallIn + IN UINTN ProcessorNumber + ); + +/** + Shadow the required microcode patches data into memory. + + @param[in, out] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +ShadowMicrocodeUpdatePatch ( + IN OUT CPU_MP_DATA *CpuMpData ); /** @@ -594,5 +619,20 @@ EnableDebugAgent ( VOID ); +/** + Find the current Processor number by APIC ID. + + @param[in] CpuMpData Pointer to PEI CPU MP Data + @param[out] ProcessorNumber Return the pocessor number found + + @retval EFI_SUCCESS ProcessorNumber is found and returned. + @retval EFI_NOT_FOUND ProcessorNumber is not found. +**/ +EFI_STATUS +GetProcessorNumber ( + IN CPU_MP_DATA *CpuMpData, + OUT UINTN *ProcessorNumber + ); + #endif diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf index 1538185ef99..555125a7c57 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf @@ -1,7 +1,7 @@ ## @file # MP Initialize Library instance for PEI driver. # -# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
+# Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -60,6 +60,8 @@ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuShadowMicrocodeByFit ## CONSUMES [Guids] gEdkiiS3SmmInitDoneGuid + gEdkiiMicrocodePatchHobGuid diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c index 3999603c3ef..06e3f5d0d3d 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c @@ -9,6 +9,7 @@ #include "MpLib.h" #include #include +#include /** S3 SMM Init Done notification function. @@ -290,6 +291,59 @@ CheckAndUpdateApsStatus ( { } +/** + Build the microcode patch HOB that contains the base address and size of the + microcode patch stored in the memory. + + @param[in] CpuMpData Pointer to the CPU_MP_DATA structure. + +**/ +VOID +BuildMicrocodeCacheHob ( + IN CPU_MP_DATA *CpuMpData + ) +{ + EDKII_MICROCODE_PATCH_HOB *MicrocodeHob; + UINTN HobDataLength; + UINT32 Index; + + HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) + + sizeof (UINT64) * CpuMpData->CpuCount; + + MicrocodeHob = AllocatePool (HobDataLength); + if (MicrocodeHob == NULL) { + ASSERT (FALSE); + return; + } + + // + // Store the information of the memory region that holds the microcode patches. + // + MicrocodeHob->MicrocodePatchAddress = CpuMpData->MicrocodePatchAddress; + MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize; + + // + // Store the detected microcode patch for each processor as well. + // + MicrocodeHob->ProcessorCount = CpuMpData->CpuCount; + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { + if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) { + MicrocodeHob->ProcessorSpecificPatchOffset[Index] = + CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress; + } else { + MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64; + } + } + + BuildGuidDataHob ( + &gEdkiiMicrocodePatchHobGuid, + MicrocodeHob, + HobDataLength + ); + + return; +} + /** Initialize global data for MP support. @@ -302,6 +356,7 @@ InitMpGlobalData ( { EFI_STATUS Status; + BuildMicrocodeCacheHob (CpuMpData); SaveCpuMpData (CpuMpData); /// diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c index f891a811126..2483f2ea849 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c @@ -342,7 +342,7 @@ RestoreCr2 ( @retval TRUE Access to non-SMRAM is restricted. @retval FALSE Access to non-SMRAM is not restricted. -*/ +**/ BOOLEAN IsRestrictedMemoryAccess ( VOID diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c index 0685637c2b5..c285a70ebb9 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c @@ -1,7 +1,7 @@ /** @file SMM MP service implementation -Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.
Copyright (c) 2017, AMD Incorporated. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -137,7 +137,7 @@ ReleaseAllAPs ( { UINTN Index; - for (Index = mMaxNumberOfCpus; Index-- > 0;) { + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { if (IsPresentAp (Index)) { ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run); } @@ -170,7 +170,7 @@ AllCpusInSmmWithExceptions ( CpuData = mSmmMpSyncData->CpuData; ProcessorInfo = gSmmCpuPrivate->ProcessorInfo; - for (Index = mMaxNumberOfCpus; Index-- > 0;) { + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { if (!(*(CpuData[Index].Present)) && ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) { if (((Exceptions & ARRIVAL_EXCEPTION_DELAYED) != 0) && SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmDelayed) != 0) { continue; @@ -305,7 +305,7 @@ SmmWaitForApArrival ( // // Send SMI IPIs to bring outside processors in // - for (Index = mMaxNumberOfCpus; Index-- > 0;) { + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { if (!(*(mSmmMpSyncData->CpuData[Index].Present)) && gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) { SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId); } @@ -361,7 +361,7 @@ WaitForAllAPsNotBusy ( { UINTN Index; - for (Index = mMaxNumberOfCpus; Index-- > 0;) { + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { // // Ignore BSP and APs which not call in SMM. // @@ -402,38 +402,6 @@ IsPresentAp ( *(mSmmMpSyncData->CpuData[CpuIndex].Present)); } -/** - Check whether execute in single AP or all APs. - - Compare two Tokens used by different APs to know whether in StartAllAps call. - - Whether is an valid AP base on AP's Present flag. - - @retval TRUE IN StartAllAps call. - @retval FALSE Not in StartAllAps call. - -**/ -BOOLEAN -InStartAllApsCall ( - VOID - ) -{ - UINTN ApIndex; - UINTN ApIndex2; - - for (ApIndex = mMaxNumberOfCpus; ApIndex-- > 0;) { - if (IsPresentAp (ApIndex) && (mSmmMpSyncData->CpuData[ApIndex].Token != NULL)) { - for (ApIndex2 = ApIndex; ApIndex2-- > 0;) { - if (IsPresentAp (ApIndex2) && (mSmmMpSyncData->CpuData[ApIndex2].Token != NULL)) { - return mSmmMpSyncData->CpuData[ApIndex2].Token == mSmmMpSyncData->CpuData[ApIndex].Token; - } - } - } - } - - return FALSE; -} - /** Clean up the status flags used during executing the procedure. @@ -445,40 +413,15 @@ ReleaseToken ( IN UINTN CpuIndex ) { - UINTN Index; - BOOLEAN Released; + PROCEDURE_TOKEN *Token; - if (InStartAllApsCall ()) { - // - // In Start All APs mode, make sure all APs have finished task. - // - if (WaitForAllAPsNotBusy (FALSE)) { - // - // Clean the flags update in the function call. - // - Released = FALSE; - for (Index = mMaxNumberOfCpus; Index-- > 0;) { - // - // Only In SMM APs need to be clean up. - // - if (mSmmMpSyncData->CpuData[Index].Present && mSmmMpSyncData->CpuData[Index].Token != NULL) { - if (!Released) { - ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Token); - Released = TRUE; - } - mSmmMpSyncData->CpuData[Index].Token = NULL; - } - } - } - } else { - // - // In single AP mode. - // - if (mSmmMpSyncData->CpuData[CpuIndex].Token != NULL) { - ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Token); - mSmmMpSyncData->CpuData[CpuIndex].Token = NULL; - } + Token = mSmmMpSyncData->CpuData[CpuIndex].Token; + + if (InterlockedDecrement (&Token->RunningApCount) == 0) { + ReleaseSpinLock (Token->SpinLock); } + + mSmmMpSyncData->CpuData[CpuIndex].Token = NULL; } /** @@ -486,21 +429,29 @@ ReleaseToken ( **/ VOID -FreeTokens ( +ResetTokens ( VOID ) { LIST_ENTRY *Link; PROCEDURE_TOKEN *ProcToken; - while (!IsListEmpty (&gSmmCpuPrivate->TokenList)) { - Link = GetFirstNode (&gSmmCpuPrivate->TokenList); + Link = GetFirstNode (&gSmmCpuPrivate->TokenList); + while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) { ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link); - RemoveEntryList (&ProcToken->Link); + ProcToken->RunningApCount = 0; + ProcToken->Used = FALSE; - FreePool ((VOID *)ProcToken->ProcedureToken); - FreePool (ProcToken); + // + // Check the spinlock status and release it if not released yet. + // + if (!AcquireSpinLockOrFail(ProcToken->SpinLock)) { + DEBUG((DEBUG_ERROR, "Risk::SpinLock still not released!")); + } + ReleaseSpinLock (ProcToken->SpinLock); + + Link = GetNextNode (&gSmmCpuPrivate->TokenList, Link); } } @@ -657,7 +608,7 @@ BSPHandler ( // while (TRUE) { PresentCount = 0; - for (Index = mMaxNumberOfCpus; Index-- > 0;) { + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { if (*(mSmmMpSyncData->CpuData[Index].Present)) { PresentCount ++; } @@ -725,9 +676,9 @@ BSPHandler ( WaitForAllAPs (ApCount); // - // Clean the tokens buffer. + // Reset the tokens buffer. // - FreeTokens (); + ResetTokens (); // // Reset BspIndex to -1, meaning BSP has not been elected. @@ -895,12 +846,14 @@ APHandler ( *mSmmMpSyncData->CpuData[CpuIndex].Status = ProcedureStatus; } + if (mSmmMpSyncData->CpuData[CpuIndex].Token != NULL) { + ReleaseToken (CpuIndex); + } + // // Release BUSY // ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); - - ReleaseToken (CpuIndex); } if (SmmCpuFeaturesNeedConfigureMtrrs()) { @@ -1094,7 +1047,7 @@ IsTokenInUse ( while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) { ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link); - if (ProcToken->ProcedureToken == Token) { + if (ProcToken->Used && ProcToken->SpinLock == Token) { return TRUE; } @@ -1105,34 +1058,114 @@ IsTokenInUse ( } /** - create token and save it to the maintain list. - - @retval return the spin lock used as token. + Allocate buffer for the SPIN_LOCK and PROCEDURE_TOKEN. **/ -SPIN_LOCK * -CreateToken ( +VOID +AllocateTokenBuffer ( VOID ) { - PROCEDURE_TOKEN *ProcToken; - SPIN_LOCK *CpuToken; UINTN SpinLockSize; + UINT32 TokenCountPerChunk; + UINTN ProcTokenSize; + UINTN Index; + PROCEDURE_TOKEN *ProcToken; + SPIN_LOCK *SpinLock; + UINT8 *SpinLockBuffer; + UINT8 *ProcTokenBuffer; SpinLockSize = GetSpinLockProperties (); - CpuToken = AllocatePool (SpinLockSize); - ASSERT (CpuToken != NULL); - InitializeSpinLock (CpuToken); - AcquireSpinLock (CpuToken); + ProcTokenSize = sizeof (PROCEDURE_TOKEN); + + TokenCountPerChunk = FixedPcdGet32 (PcdCpuSmmMpTokenCountPerChunk); + ASSERT (TokenCountPerChunk != 0); + if (TokenCountPerChunk == 0) { + DEBUG ((DEBUG_ERROR, "PcdCpuSmmMpTokenCountPerChunk should not be Zero!\n")); + CpuDeadLoop (); + } + DEBUG ((DEBUG_INFO, "CpuSmm: SpinLock Size = 0x%x, PcdCpuSmmMpTokenCountPerChunk = 0x%x\n", SpinLockSize, TokenCountPerChunk)); + + // + // Separate the Spin_lock and Proc_token because the alignment requires by Spin_Lock. + // + SpinLockBuffer = AllocatePool (SpinLockSize * TokenCountPerChunk); + ASSERT (SpinLockBuffer != NULL); + + ProcTokenBuffer = AllocatePool (ProcTokenSize * TokenCountPerChunk); + ASSERT (ProcTokenBuffer != NULL); + + for (Index = 0; Index < TokenCountPerChunk; Index++) { + SpinLock = (SPIN_LOCK *)(SpinLockBuffer + SpinLockSize * Index); + InitializeSpinLock (SpinLock); + + ProcToken = (PROCEDURE_TOKEN *)(ProcTokenBuffer + ProcTokenSize * Index); + ProcToken->Signature = PROCEDURE_TOKEN_SIGNATURE; + ProcToken->SpinLock = SpinLock; + ProcToken->Used = FALSE; + ProcToken->RunningApCount = 0; + + InsertTailList (&gSmmCpuPrivate->TokenList, &ProcToken->Link); + } +} + +/** + Find first free token in the allocated token list. + + @retval return the first free PROCEDURE_TOKEN. + +**/ +PROCEDURE_TOKEN * +FindFirstFreeToken ( + VOID + ) +{ + LIST_ENTRY *Link; + PROCEDURE_TOKEN *ProcToken; + + Link = GetFirstNode (&gSmmCpuPrivate->TokenList); + while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) { + ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link); - ProcToken = AllocatePool (sizeof (PROCEDURE_TOKEN)); - ASSERT (ProcToken != NULL); - ProcToken->Signature = PROCEDURE_TOKEN_SIGNATURE; - ProcToken->ProcedureToken = CpuToken; + if (!ProcToken->Used) { + return ProcToken; + } - InsertTailList (&gSmmCpuPrivate->TokenList, &ProcToken->Link); + Link = GetNextNode (&gSmmCpuPrivate->TokenList, Link); + } - return CpuToken; + return NULL; +} + +/** + Get the free token. + + If no free token, allocate new tokens then return the free one. + + @param RunningApsCount The Running Aps count for this token. + + @retval return the first free PROCEDURE_TOKEN. + +**/ +PROCEDURE_TOKEN * +GetFreeToken ( + IN UINT32 RunningApsCount + ) +{ + PROCEDURE_TOKEN *NewToken; + + NewToken = FindFirstFreeToken (); + if (NewToken == NULL) { + AllocateTokenBuffer (); + NewToken = FindFirstFreeToken (); + } + ASSERT (NewToken != NULL); + + NewToken->Used = TRUE; + NewToken->RunningApCount = RunningApsCount; + AcquireSpinLock (NewToken->SpinLock); + + return NewToken; } /** @@ -1205,6 +1238,8 @@ InternalSmmStartupThisAp ( IN OUT EFI_STATUS *CpuStatus ) { + PROCEDURE_TOKEN *ProcToken; + if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) { DEBUG((DEBUG_ERROR, "CpuIndex(%d) >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus(%d)\n", CpuIndex, gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus)); return EFI_INVALID_PARAMETER; @@ -1237,14 +1272,12 @@ InternalSmmStartupThisAp ( AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); - if (Token != NULL) { - *Token = (MM_COMPLETION) CreateToken (); - } - mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure; mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments; if (Token != NULL) { - mSmmMpSyncData->CpuData[CpuIndex].Token = (SPIN_LOCK *)(*Token); + ProcToken= GetFreeToken (1); + mSmmMpSyncData->CpuData[CpuIndex].Token = ProcToken; + *Token = (MM_COMPLETION)ProcToken->SpinLock; } mSmmMpSyncData->CpuData[CpuIndex].Status = CpuStatus; if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) { @@ -1302,6 +1335,7 @@ InternalSmmStartupAllAPs ( { UINTN Index; UINTN CpuCount; + PROCEDURE_TOKEN *ProcToken; if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) { return EFI_INVALID_PARAMETER; @@ -1311,7 +1345,7 @@ InternalSmmStartupAllAPs ( } CpuCount = 0; - for (Index = mMaxNumberOfCpus; Index-- > 0;) { + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { if (IsPresentAp (Index)) { CpuCount ++; @@ -1330,7 +1364,10 @@ InternalSmmStartupAllAPs ( } if (Token != NULL) { - *Token = (MM_COMPLETION) CreateToken (); + ProcToken = GetFreeToken ((UINT32)mMaxNumberOfCpus); + *Token = (MM_COMPLETION)ProcToken->SpinLock; + } else { + ProcToken = NULL; } // @@ -1340,18 +1377,18 @@ InternalSmmStartupAllAPs ( // Here code always use AcquireSpinLock instead of AcquireSpinLockOrFail for not // block mode. // - for (Index = mMaxNumberOfCpus; Index-- > 0;) { + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { if (IsPresentAp (Index)) { AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy); } } - for (Index = mMaxNumberOfCpus; Index-- > 0;) { + for (Index = 0; Index < mMaxNumberOfCpus; Index++) { if (IsPresentAp (Index)) { mSmmMpSyncData->CpuData[Index].Procedure = (EFI_AP_PROCEDURE2) Procedure; mSmmMpSyncData->CpuData[Index].Parameter = ProcedureArguments; - if (Token != NULL) { - mSmmMpSyncData->CpuData[Index].Token = (SPIN_LOCK *)(*Token); + if (ProcToken != NULL) { + mSmmMpSyncData->CpuData[Index].Token = ProcToken; } if (CPUStatus != NULL) { mSmmMpSyncData->CpuData[Index].Status = &CPUStatus[Index]; @@ -1367,6 +1404,13 @@ InternalSmmStartupAllAPs ( if (CPUStatus != NULL) { CPUStatus[Index] = EFI_NOT_STARTED; } + + // + // Decrease the count to mark this processor(AP or BSP) as finished. + // + if (ProcToken != NULL) { + WaitForSemaphore (&ProcToken->RunningApCount); + } } } @@ -1736,6 +1780,8 @@ InitializeDataForMmMp ( ASSERT (gSmmCpuPrivate->ApWrapperFunc != NULL); InitializeListHead (&gSmmCpuPrivate->TokenList); + + AllocateTokenBuffer (); } /** diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h index daf977f654b..33b3dd140ea 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -212,11 +212,24 @@ typedef struct { UINTN Signature; LIST_ENTRY Link; - SPIN_LOCK *ProcedureToken; + SPIN_LOCK *SpinLock; + volatile UINT32 RunningApCount; + BOOLEAN Used; } PROCEDURE_TOKEN; #define PROCEDURE_TOKEN_FROM_LINK(a) CR (a, PROCEDURE_TOKEN, Link, PROCEDURE_TOKEN_SIGNATURE) +#define TOKEN_BUFFER_SIGNATURE SIGNATURE_32 ('T', 'K', 'B', 'S') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 *Buffer; +} TOKEN_BUFFER; + +#define TOKEN_BUFFER_FROM_LINK(a) CR (a, TOKEN_BUFFER, Link, TOKEN_BUFFER_SIGNATURE) + // // Private structure for the SMM CPU module that is stored in DXE Runtime memory // Contains the SMM Configuration Protocols that is produced. @@ -242,7 +255,6 @@ typedef struct { PROCEDURE_WRAPPER *ApWrapperFunc; LIST_ENTRY TokenList; - } SMM_CPU_PRIVATE_DATA; extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate; @@ -392,7 +404,7 @@ typedef struct { volatile VOID *Parameter; volatile UINT32 *Run; volatile BOOLEAN *Present; - SPIN_LOCK *Token; + PROCEDURE_TOKEN *Token; EFI_STATUS *Status; } SMM_CPU_DATA_BLOCK; @@ -1455,7 +1467,7 @@ InitializeDataForMmMp ( @retval TRUE Access to non-SMRAM is restricted. @retval FALSE Access to non-SMRAM is not restricted. -*/ +**/ BOOLEAN IsRestrictedMemoryAccess ( VOID diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf index b12b2691f8c..76b14629967 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf @@ -140,6 +140,9 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES gEfiMdePkgTokenSpaceGuid.PcdControlFlowEnforcementPropertyMask ## CONSUMES +[FixedPcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmMpTokenCountPerChunk ## CONSUMES + [Pcd.X64] gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmRestrictedMemoryAccess ## CONSUMES diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c index c5131526f0c..c47b5573e36 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c @@ -657,11 +657,9 @@ InitPaging ( Pt = AllocatePageTableMemory (1); ASSERT (Pt != NULL); - *Pd = (UINTN) Pt | IA32_PG_RW | IA32_PG_P; - // Split it - for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++, Pt++) { - *Pt = Address + ((PtIndex << 12) | mAddressEncMask | PAGE_ATTRIBUTE_BITS); + for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++) { + Pt[PtIndex] = Address + ((PtIndex << 12) | mAddressEncMask | PAGE_ATTRIBUTE_BITS); } // end for PT *Pd = (UINT64)(UINTN)Pt | mAddressEncMask | PAGE_ATTRIBUTE_BITS; } // end if IsAddressSplit diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c index e5c4788c13d..810985df20a 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c @@ -1275,7 +1275,7 @@ RestoreCr2 ( @retval TRUE Access to non-SMRAM is restricted. @retval FALSE Access to non-SMRAM is not restricted. -*/ +**/ BOOLEAN IsRestrictedMemoryAccess ( VOID diff --git a/UefiCpuPkg/UefiCpuPkg.ci.yaml b/UefiCpuPkg/UefiCpuPkg.ci.yaml new file mode 100644 index 00000000000..99e460a8b09 --- /dev/null +++ b/UefiCpuPkg/UefiCpuPkg.ci.yaml @@ -0,0 +1,51 @@ +## @file +# CI configuration for UefiCpuPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "CompilerPlugin": { + "DscPath": "UefiCpuPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "UefiCpuPkg/UefiCpuPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "UefiCpuPkg.dsc", + "IgnoreInf": [ + "UefiCpuPkg/ResetVector/FixupVtf/Vtf.inf", + "UefiCpuPkg/ResetVector/Vtf0/Vtf0.inf" + ] + }, + "GuidCheck": { + "IgnoreGuidName": ["SecCore", "ResetVector"], # Expected duplication for gEfiFirmwareVolumeTopFileGuid + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined ci/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log + "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files + "ExtendWords": [], # words to extend to the dictionary for this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + } +} diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index 12f4413ea5b..a6ebdde1cfb 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -63,6 +63,9 @@ ## Include/Guid/CpuFeaturesInitDone.h gEdkiiCpuFeaturesInitDoneGuid = { 0xc77c3a41, 0x61ab, 0x4143, { 0x98, 0x3e, 0x33, 0x39, 0x28, 0x6, 0x28, 0xe5 }} + ## Include/Guid/MicrocodePatchHob.h + gEdkiiMicrocodePatchHobGuid = { 0xd178f11d, 0x8716, 0x418e, { 0xa1, 0x31, 0x96, 0x7d, 0x2a, 0xc4, 0x28, 0x43 }} + [Protocols] ## Include/Protocol/SmmCpuService.h gEfiSmmCpuServiceProtocolGuid = { 0x1d202cab, 0xc8ab, 0x4d5c, { 0x94, 0xf7, 0x3c, 0xfc, 0xc0, 0xd3, 0xd3, 0x35 }} @@ -136,6 +139,12 @@ # @Prompt Lock SMM Feature Control MSR. gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmFeatureControlMsrLock|TRUE|BOOLEAN|0x3213210B + ## Indicates if FIT based microcode shadowing will be enabled.

+ # TRUE - FIT base microcode shadowing will be enabled.
+ # FALSE - FIT base microcode shadowing will be disabled.
+ # @Prompt FIT based microcode shadowing. + gUefiCpuPkgTokenSpaceGuid.PcdCpuShadowMicrocodeByFit|FALSE|BOOLEAN|0x3213210D + [PcdsFixedAtBuild] ## List of exception vectors which need switching stack. # This PCD will only take into effect if PcdCpuStackGuard is enabled. @@ -148,6 +157,10 @@ # @Prompt Specify size of good stack of exception which need switching stack. gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize|2048|UINT32|0x30002001 + ## Count of pre allocated SMM MP tokens per chunk. + # @Prompt Specify the count of pre allocated SMM MP tokens per chunk. + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmMpTokenCountPerChunk|64|UINT32|0x30002002 + [PcdsFixedAtBuild, PcdsPatchableInModule] ## This value is the CPU Local APIC base address, which aligns the address on a 4-KByte boundary. # @Prompt Configure base address of CPU Local APIC diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni index a7e279c5cb1..2db49e841b4 100644 --- a/UefiCpuPkg/UefiCpuPkg.uni +++ b/UefiCpuPkg/UefiCpuPkg.uni @@ -100,6 +100,12 @@ "TRUE - locked.
\n" "FALSE - unlocked.
" +#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuShadowMicrocodeByFit_PROMPT #language en-US "FIT based microcode shadowing" + +#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuShadowMicrocodeByFit_HELP #language en-US "Indicates if FIT based microcode shadowing will be enabled.

\n" + "TRUE - FIT base microcode shadowing will be enabled.
\n" + "FALSE - FIT base microcode shadowing will be disabled.
" + #string STR_gUefiCpuPkgTokenSpaceGuid_PcdPeiTemporaryRamStackSize_PROMPT #language en-US "Stack size in the temporary RAM" #string STR_gUefiCpuPkgTokenSpaceGuid_PcdPeiTemporaryRamStackSize_HELP #language en-US "Specifies stack size in the temporary RAM. 0 means half of TemporaryRamSize." @@ -195,6 +201,22 @@ #string STR_gUefiCpuPkgTokenSpaceGuid_PcdIsPowerOnReset_HELP #language en-US "Indicates if the current boot is a power-on reset." +#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuSmmRestrictedMemoryAccess_PROMPT #language en-US "Access to non-SMRAM memory is restricted to reserved, runtime and ACPI NVS type after SmmReadyToLock." + +#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuSmmRestrictedMemoryAccess_HELP #language en-US "Indicate access to non-SMRAM memory is restricted to reserved, runtime and ACPI NVS type after SmmReadyToLock.

\n" + "MMIO access is always allowed regardless of the value of this PCD.
\n" + "Loose of such restriction is only required by RAS components in X64 platforms.
\n" + "The PCD value is considered as constantly TRUE in IA32 platforms.
\n" + "When the PCD value is TRUE, page table is initialized to cover all memory spaces
\n" + "and the memory occupied by page table is protected by page table itself as read-only.
\n" + "In X64 build, it cannot be enabled at the same time with SMM profile feature (PcdCpuSmmProfileEnable).
\n" + "In X64 build, it could not be enabled also at the same time with heap guard feature for SMM
\n" + "(PcdHeapGuardPropertyMask in MdeModulePkg).
\n" + "In IA32 build, page table memory is not marked as read-only when either SMM profile feature (PcdCpuSmmProfileEnable)
\n" + "or heap guard feature for SMM (PcdHeapGuardPropertyMask in MdeModulePkg) is enabled.
\n" + "TRUE - Access to non-SMRAM memory is restricted to reserved, runtime and ACPI NVS type after SmmReadyToLock.
\n" + "FALSE - Access to any type of non-SMRAM memory after SmmReadyToLock is allowed.
" + #string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuFeaturesCapability_PROMPT #language en-US "Processor feature capabilities." #string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuFeaturesCapability_HELP #language en-US "Indicates processor feature capabilities, each bit corresponding to a specific feature." @@ -256,3 +278,6 @@ "24000000 - 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family(24MHz).
\n" "19200000 - Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH(19.2MHz).
\n" +#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuSmmMpTokenCountPerChunk_PROMPT #language en-US "Specify the count of pre allocated SMM MP tokens per chunk.\n" + +#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuSmmMpTokenCountPerChunk_HELP #language en-US "This value used to specify the count of pre allocated SMM MP tokens per chunk.\n" diff --git a/UefiPayloadPkg/Library/PlatformBootManagerLib/PlatformConsole.c b/UefiPayloadPkg/Library/PlatformBootManagerLib/PlatformConsole.c index ee2d8c8d1ed..a27cc552ab8 100644 --- a/UefiPayloadPkg/Library/PlatformBootManagerLib/PlatformConsole.c +++ b/UefiPayloadPkg/Library/PlatformBootManagerLib/PlatformConsole.c @@ -44,6 +44,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define gPnp16550ComPort \ PNPID_DEVICE_PATH_NODE(0x0501) +#define gPnpPs2Keyboard \ + PNPID_DEVICE_PATH_NODE(0x0303) + #define gUartVendor \ { \ { \ @@ -87,7 +90,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent DEVICE_PATH_MESSAGING_PC_ANSI \ } - +ACPI_HID_DEVICE_PATH gPnpPs2KeyboardDeviceNode = gPnpPs2Keyboard; ACPI_HID_DEVICE_PATH gPnp16550ComPortDeviceNode = gPnp16550ComPort; UART_DEVICE_PATH gUartDeviceNode = gUart; VENDOR_DEVICE_PATH gTerminalTypeDeviceNode = gPcAnsiTerminal; @@ -109,12 +112,15 @@ EFI_DEVICE_PATH_PROTOCOL *gPlatformRootBridges[] = { BOOLEAN mDetectVgaOnly; /** - Add UART to ConOut, ConIn, ErrOut. + Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut. - @param[in] DeviceHandle - LPC device path. + @param[in] DeviceHandle Handle of the LPC Bridge device. - @retval EFI_SUCCESS - Serial console is added to ConOut, ConIn, and ErrOut. - @retval EFI_STATUS - No serial console is added. + @retval EFI_SUCCESS Console devices on the LPC bridge have been added to + ConOut, ConIn, and ErrOut. + + @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing + from DeviceHandle. **/ EFI_STATUS PrepareLpcBridgeDevicePath ( @@ -123,6 +129,7 @@ PrepareLpcBridgeDevicePath ( { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; DevicePath = NULL; Status = gBS->HandleProtocol ( @@ -133,10 +140,18 @@ PrepareLpcBridgeDevicePath ( if (EFI_ERROR (Status)) { return Status; } + TempDevicePath = DevicePath; + + // + // Register Keyboard + // + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode); + EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL); // // Register COM1 // + DevicePath = TempDevicePath; DevicePath = AppendDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *)NULL, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceVendorNode); DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); diff --git a/UefiPayloadPkg/Library/ResetSystemLib/ResetSystemLib.c b/UefiPayloadPkg/Library/ResetSystemLib/ResetSystemLib.c index 3fe3c805afe..2e4b7fe5926 100644 --- a/UefiPayloadPkg/Library/ResetSystemLib/ResetSystemLib.c +++ b/UefiPayloadPkg/Library/ResetSystemLib/ResetSystemLib.c @@ -131,24 +131,6 @@ ResetShutdown ( ASSERT (FALSE); } -/** - Calling this function causes the system to enter a power state for capsule - update. - - Reset update should not return, if it returns, it means the system does - not support capsule update. - -**/ -VOID -EFIAPI -EnterS3WithImmediateWake ( - VOID - ) -{ - AcpiPmControl (5); - ASSERT (FALSE); -} - /** This function causes a systemwide reset. The exact type of the reset is defined by the EFI_GUID that follows the Null-terminated Unicode string passed diff --git a/UefiPayloadPkg/UefiPayloadPkg.fdf b/UefiPayloadPkg/UefiPayloadPkg.fdf index 4cd88a3f855..dfbcde56684 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.fdf +++ b/UefiPayloadPkg/UefiPayloadPkg.fdf @@ -120,6 +120,10 @@ INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf # ISA Support # INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf +!if $(PS2_KEYBOARD_ENABLE) == TRUE +INF OvmfPkg/SioBusDxe/SioBusDxe.inf +INF MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf +!endif # # Console Support diff --git a/UefiPayloadPkg/UefiPayloadPkgIa32.dsc b/UefiPayloadPkg/UefiPayloadPkgIa32.dsc index 11cf17ca064..d52945442e0 100644 --- a/UefiPayloadPkg/UefiPayloadPkgIa32.dsc +++ b/UefiPayloadPkg/UefiPayloadPkgIa32.dsc @@ -491,6 +491,10 @@ # ISA Support # MdeModulePkg/Universal/SerialDxe/SerialDxe.inf +!if $(PS2_KEYBOARD_ENABLE) == TRUE + OvmfPkg/SioBusDxe/SioBusDxe.inf + MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf +!endif # # Console Support diff --git a/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc b/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc index 5b7994a62cd..0736cd99547 100644 --- a/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc +++ b/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc @@ -25,6 +25,7 @@ FLASH_DEFINITION = UefiPayloadPkg/UefiPayloadPkg.fdf DEFINE SOURCE_DEBUG_ENABLE = FALSE + DEFINE PS2_KEYBOARD_ENABLE = FALSE # # SBL: UEFI payload for Slim Bootloader @@ -492,6 +493,10 @@ # ISA Support # MdeModulePkg/Universal/SerialDxe/SerialDxe.inf +!if $(PS2_KEYBOARD_ENABLE) == TRUE + OvmfPkg/SioBusDxe/SioBusDxe.inf + MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf +!endif # # Console Support diff --git a/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf new file mode 100644 index 00000000000..07da7a88e95 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf @@ -0,0 +1,35 @@ +## @file +# This module provides Cmocka Library implementation. +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CmockaLib + MODULE_UNI_FILE = CmockaLib.uni + FILE_GUID = F1662152-3399-49AC-BE44-CAA97575FACE + MODULE_TYPE = BASE + VERSION_STRING = 0.1 + LIBRARY_CLASS = CmockaLib|HOST_APPLICATION + +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources] + cmocka/src/cmocka.c + +[Packages] + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[BuildOptions] + MSFT:*_*_*_CC_FLAGS == /c -DHAVE_VSNPRINTF -DHAVE_SNPRINTF + MSFT:NOOPT_*_*_CC_FLAGS = /Od + + GCC:*_*_*_CC_FLAGS == -g -DHAVE_SIGNAL_H + GCC:NOOPT_*_*_CC_FLAGS = -O0 + GCC:*_*_IA32_CC_FLAGS = -m32 + GCC:*_*_X64_CC_FLAGS = -m64 diff --git a/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni new file mode 100644 index 00000000000..acdb72d075e --- /dev/null +++ b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni @@ -0,0 +1,14 @@ +// /** @file +// This module provides Cmocka Library implementation. +// +// This module provides Cmocka Library implementation. +// +// Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Cmocka Library implementation" + +#string STR_MODULE_DESCRIPTION #language en-US "This module provides Cmocka Library implementation." diff --git a/UnitTestFrameworkPkg/Library/CmockaLib/cmocka b/UnitTestFrameworkPkg/Library/CmockaLib/cmocka new file mode 160000 index 00000000000..1cc9cde3448 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/CmockaLib/cmocka @@ -0,0 +1 @@ +Subproject commit 1cc9cde3448cdd2e000886a26acf1caac2db7cf1 diff --git a/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.c b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.c new file mode 100644 index 00000000000..0daea007284 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.c @@ -0,0 +1,279 @@ +/** @file + Instance of Debug Library based on POSIX APIs + + Uses Print Library to produce formatted output strings sent to printf(). + + Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +#include +#include +#include +#include +#include + +/// +/// Define the maximum debug and assert message length that this library supports +/// +#define MAX_DEBUG_MESSAGE_LENGTH 0x100 + +/** + Prints a debug message to the debug output device if the specified error level is enabled. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format and the + associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param ErrorLevel The error level of the debug message. + @param Format The format string for the debug message to print. + @param ... The variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +DebugPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ) +{ + VA_LIST Marker; + + VA_START (Marker, Format); + DebugVPrint (ErrorLevel, Format, Marker); + VA_END (Marker); +} + +/** + Prints a debug message to the debug output device if the specified + error level is enabled. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format and + the associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param ErrorLevel The error level of the debug message. + @param Format Format string for the debug message to print. + @param VaListMarker VA_LIST marker for the variable argument list. + +**/ +VOID +EFIAPI +DebugVPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + IN VA_LIST VaListMarker + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + + AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker); + printf ("%s", Buffer); +} + +/** + Prints a debug message to the debug output device if the specified + error level is enabled. + This function use BASE_LIST which would provide a more compatible + service than VA_LIST. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format and + the associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param ErrorLevel The error level of the debug message. + @param Format Format string for the debug message to print. + @param BaseListMarker BASE_LIST marker for the variable argument list. + +**/ +VOID +EFIAPI +DebugBPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + IN BASE_LIST BaseListMarker + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + + AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker); + printf ("%s", Buffer); +} + +/** + Prints an assert message containing a filename, line number, and description. + This may be followed by a breakpoint or a dead loop. + + Print a message of the form "ASSERT (): \n" + to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of + PcdDebugPropertyMask is set then CpuBreakpoint() is called. Otherwise, if + DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugPropertyMask is set then + CpuDeadLoop() is called. If neither of these bits are set, then this function + returns immediately after the message is printed to the debug output device. + DebugAssert() must actively prevent recursion. If DebugAssert() is called while + processing another DebugAssert(), then DebugAssert() must return immediately. + + If FileName is NULL, then a string of "(NULL) Filename" is printed. + If Description is NULL, then a string of "(NULL) Description" is printed. + + @param FileName The pointer to the name of the source file that generated the assert condition. + @param LineNumber The line number in the source file that generated the assert condition + @param Description The pointer to the description of the assert condition. + +**/ +VOID +EFIAPI +DebugAssert ( + IN CONST CHAR8 *FileName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ) +{ + printf ("ASSERT: %s(%d): %s\n", FileName, (INT32)(UINT32)LineNumber, Description); + + // + // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings + // + if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) { + CpuBreakpoint (); + } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) { + CpuDeadLoop (); + } +} + +/** + Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer. + + This function fills Length bytes of Buffer with the value specified by + PcdDebugClearMemoryValue, and returns Buffer. + + If Buffer is NULL, then ASSERT(). + If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param Buffer The pointer to the target buffer to be filled with PcdDebugClearMemoryValue. + @param Length The number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue. + + @return Buffer The pointer to the target buffer filled with PcdDebugClearMemoryValue. + +**/ +VOID * +EFIAPI +DebugClearMemory ( + OUT VOID *Buffer, + IN UINTN Length + ) +{ + // + // If Buffer is NULL, then ASSERT(). + // + ASSERT (Buffer != NULL); + + // + // SetMem() checks for the the ASSERT() condition on Length and returns Buffer + // + return SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue)); +} + +/** + Returns TRUE if ASSERT() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of + PcdDebugPropertyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugPropertyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugPropertyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugAssertEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0); +} + +/** + Returns TRUE if DEBUG() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of + PcdDebugPropertyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugPropertyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugPropertyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugPrintEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0); +} + +/** + Returns TRUE if DEBUG_CODE() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of + PcdDebugPropertyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPropertyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPropertyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugCodeEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0); +} + +/** + Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled. + + This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of + PcdDebugPropertyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugPropertyMask is set. + @retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugPropertyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugClearMemoryEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0); +} + +/** + Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel. + + This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel. + + @retval TRUE Current ErrorLevel is supported. + @retval FALSE Current ErrorLevel is not supported. + +**/ +BOOLEAN +EFIAPI +DebugPrintLevelEnabled ( + IN CONST UINTN ErrorLevel + ) +{ + return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0); +} diff --git a/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf new file mode 100644 index 00000000000..5babbca3b04 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf @@ -0,0 +1,35 @@ +## @file +# Instance of Debug Library based on POSIX APIs +# +# Uses Print Library to produce formatted output strings sent to printf(). +# +# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DebugLibPosix + MODULE_UNI_FILE = DebugLibPosix.uni + FILE_GUID = 6A77CE89-C1B6-4A6B-9561-07D7127514A7 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugLib|HOST_APPLICATION + +[Sources] + DebugLibPosix.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseMemoryLib + PcdLib + PrintLib + BaseLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel ## CONSUMES diff --git a/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.uni b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.uni new file mode 100644 index 00000000000..d34f1a05bee --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.uni @@ -0,0 +1,14 @@ +// /** @file +// Instance of Debug Library based on POSIX APIs +// +// Uses Print Library to produce formatted output strings sent to printf(). +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Instance of Debug Library based on POSIX APIs" + +#string STR_MODULE_DESCRIPTION #language en-US "Uses Print Library to produce formatted output strings sent to printf()." diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.c b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.c new file mode 100644 index 00000000000..1f590524d89 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.c @@ -0,0 +1,631 @@ +/** @file + Instance of Memory Allocation Library based on POSIX APIs + + Uses POSIX APIs malloc() and free() to allocate and free memory. + + Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include + +#include +#include +#include + +/// +/// Signature for PAGE_HEAD structure +/// Used to verify that buffer being freed was allocated by this library. +/// +#define PAGE_HEAD_PRIVATE_SIGNATURE SIGNATURE_32 ('P', 'H', 'D', 'R') + +/// +/// Structure placed immediately before an aligned allocation to store the +/// information required to free the entire buffer allocated to support then +/// aligned allocation. +/// +typedef struct { + UINT32 Signature; + VOID *AllocatedBufffer; + UINTN TotalPages; + VOID *AlignedBuffer; + UINTN AlignedPages; +} PAGE_HEAD; + +/** + Allocates one or more 4KB pages of type EfiBootServicesData. + + Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePages ( + IN UINTN Pages + ) +{ + return AllocateAlignedPages (Pages, SIZE_4KB); +} + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData. + + Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimePages ( + IN UINTN Pages + ) +{ + return AllocatePages (Pages); +} + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType. + + Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedPages ( + IN UINTN Pages + ) +{ + return AllocatePages (Pages); +} + +/** + Frees one or more 4KB pages that were previously allocated with one of the page allocation + functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the page allocation services of the Memory + Allocation Library. If it is not possible to free allocated pages, then this function will + perform no actions. + + If Buffer was not allocated with a page allocation function in the Memory Allocation Library, + then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer The pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreePages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + FreeAlignedPages (Buffer, Pages); +} + +/** + Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/VOID * +EFIAPI +AllocateAlignedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + PAGE_HEAD PageHead; + PAGE_HEAD *PageHeadPtr; + UINTN AlignmentMask; + + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Alignment < SIZE_4KB) { + Alignment = SIZE_4KB; + } + AlignmentMask = Alignment - 1; + + // + // We need reserve Alignment pages for PAGE_HEAD, as meta data. + // + PageHead.Signature = PAGE_HEAD_PRIVATE_SIGNATURE; + PageHead.TotalPages = Pages + EFI_SIZE_TO_PAGES (Alignment) * 2; + PageHead.AlignedPages = Pages; + PageHead.AllocatedBufffer = malloc (EFI_PAGES_TO_SIZE (PageHead.TotalPages)); + if (PageHead.AllocatedBufffer == NULL) { + return NULL; + } + PageHead.AlignedBuffer = (VOID *)(((UINTN) PageHead.AllocatedBufffer + AlignmentMask) & ~AlignmentMask); + if ((UINTN)PageHead.AlignedBuffer - (UINTN)PageHead.AllocatedBufffer < sizeof(PAGE_HEAD)) { + PageHead.AlignedBuffer = (VOID *)((UINTN)PageHead.AlignedBuffer + Alignment); + } + + PageHeadPtr = (VOID *)((UINTN)PageHead.AlignedBuffer - sizeof(PAGE_HEAD)); + memcpy (PageHeadPtr, &PageHead, sizeof(PAGE_HEAD)); + + return PageHead.AlignedBuffer; +} + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedRuntimePages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return AllocateAlignedPages (Pages, Alignment); +} + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedReservedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return AllocateAlignedPages (Pages, Alignment); +} + +/** + Frees one or more 4KB pages that were previously allocated with one of the aligned page + allocation functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the aligned page allocation services of the Memory + Allocation Library. If it is not possible to free allocated pages, then this function will + perform no actions. + + If Buffer was not allocated with an aligned page allocation function in the Memory Allocation + Library, then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer The pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreeAlignedPages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + PAGE_HEAD *PageHeadPtr; + + // + // NOTE: Partial free is not supported. Just keep it. + // + PageHeadPtr = (VOID *)((UINTN)Buffer - sizeof(PAGE_HEAD)); + if (PageHeadPtr->Signature != PAGE_HEAD_PRIVATE_SIGNATURE) { + return; + } + if (PageHeadPtr->AlignedPages != Pages) { + return; + } + + PageHeadPtr->Signature = 0; + free (PageHeadPtr->AllocatedBufffer); +} + +/** + Allocates a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/VOID * +EFIAPI +AllocatePool ( + IN UINTN AllocationSize + ) +{ + return malloc (AllocationSize); +} + +/** + Allocates a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimePool ( + IN UINTN AllocationSize + ) +{ + return AllocatePool (AllocationSize); +} + +/** + Allocates a buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedPool ( + IN UINTN AllocationSize + ) +{ + return AllocatePool (AllocationSize); +} + +/** + Allocates and zeros a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateZeroPool ( + IN UINTN AllocationSize + ) +{ + VOID *Buffer; + + Buffer = malloc (AllocationSize); + if (Buffer == NULL) { + return NULL; + } + memset (Buffer, 0, AllocationSize); + return Buffer; +} + +/** + Allocates and zeros a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimeZeroPool ( + IN UINTN AllocationSize + ) +{ + return AllocateZeroPool (AllocationSize); +} + +/** + Allocates and zeros a buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedZeroPool ( + IN UINTN AllocationSize + ) +{ + return AllocateZeroPool (AllocationSize); +} + +/** + Copies a buffer to an allocated buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + VOID *Memory; + + Memory = malloc (AllocationSize); + if (Memory == NULL) { + return NULL; + } + memcpy (Memory, Buffer, AllocationSize); + return Memory; +} + +/** + Copies a buffer to an allocated buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return AllocateCopyPool (AllocationSize, Buffer); +} + +/** + Copies a buffer to an allocated buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return AllocateCopyPool (AllocationSize, Buffer); +} + +/** + Reallocates a buffer of type EfiBootServicesData. + + Allocates and zeros the number bytes specified by NewSize from memory of type + EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocatePool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + VOID *NewBuffer; + + NewBuffer = malloc (NewSize); + if (NewBuffer != NULL && OldBuffer != NULL) { + memcpy (NewBuffer, OldBuffer, MIN (OldSize, NewSize)); + } + if (OldBuffer != NULL) { + FreePool(OldBuffer); + } + return NewBuffer; +} + +/** + Reallocates a buffer of type EfiRuntimeServicesData. + + Allocates and zeros the number bytes specified by NewSize from memory of type + EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocateRuntimePool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return ReallocatePool (OldSize, NewSize, OldBuffer); +} + +/** + Reallocates a buffer of type EfiReservedMemoryType. + + Allocates and zeros the number bytes specified by NewSize from memory of type + EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocateReservedPool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return ReallocatePool (OldSize, NewSize, OldBuffer); +} + +/** + Frees a buffer that was previously allocated with one of the pool allocation functions in the + Memory Allocation Library. + + Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the + pool allocation services of the Memory Allocation Library. If it is not possible to free pool + resources, then this function will perform no actions. + + If Buffer was not allocated with a pool allocation function in the Memory Allocation Library, + then ASSERT(). + + @param Buffer The pointer to the buffer to free. + +**/ +VOID +EFIAPI +FreePool ( + IN VOID *Buffer + ) +{ + free (Buffer); +} diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf new file mode 100644 index 00000000000..44ec3fd5172 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf @@ -0,0 +1,27 @@ +## @file +# Instance of Memory Allocation Library based on POSIX APIs +# +# Uses POSIX APIs malloc() and free() to allocate and free memory. +# +# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemoryAllocationLibPosix + MODULE_UNI_FILE = MemoryAllocationLibPosix.uni + FILE_GUID = A1672454-A3D3-4AAC-A86B-8D63132BBB91 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemoryAllocationLib|HOST_APPLICATION + +[Sources] + MemoryAllocationLibPosix.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.uni b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.uni new file mode 100644 index 00000000000..854b4279764 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.uni @@ -0,0 +1,14 @@ +// /** @file +// Instance of Memory Allocation Library based on POSIX APIs +// +// Uses POSIX APIs malloc() and free() to allocate and free memory. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Instance of Memory Allocation Library based on POSIX APIs" + +#string STR_MODULE_DESCRIPTION #language en-US "Uses POSIX APIs malloc() and free() to allocate and free memory." diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.c b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.c new file mode 100644 index 00000000000..c5a5162c58f --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.c @@ -0,0 +1,26 @@ +/** + NULL implementation for UnitTestBootLib to allow simple compilation + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +/** + Set the boot manager to boot from a specific device on the next boot. This + should be set only for the next boot and shouldn't require any manual clean up + + @retval EFI_SUCCESS Boot device for next boot was set. + @retval EFI_UNSUPPORTED Setting the boot device for the next boot is not + supportted. + @retval Other Boot device for next boot can not be set. +**/ +EFI_STATUS +EFIAPI +SetBootNextDevice( + VOID + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.inf b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.inf new file mode 100644 index 00000000000..a4a907b65b0 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.inf @@ -0,0 +1,23 @@ +## @file +# NULL library for UnitTestBootUsb +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestBootLibNull + MODULE_UNI_FILE = UnitTestBootLibNull.uni + FILE_GUID = f143e75d-76e1-4040-b134-8f4f0bd5e3bd + VERSION_STRING = 1.0 + MODULE_TYPE = DXE_DRIVER + LIBRARY_CLASS = UnitTestBootLib + +[Sources] + UnitTestBootLibNull.c + +[Packages] + MdePkg/MdePkg.dec + diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.uni b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.uni new file mode 100644 index 00000000000..1ed3b205443 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.uni @@ -0,0 +1,11 @@ +// /** @file +// NULL library for UnitTestBootUsb +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "NULL library for UnitTestBootUsb" + +#string STR_MODULE_DESCRIPTION #language en-US "NULL library for UnitTestBootUsb." diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.c b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.c new file mode 100644 index 00000000000..4ce48bd2330 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.c @@ -0,0 +1,127 @@ +/** + Implement UnitTestBootLib using USB Class Boot option. This should be + industry standard and should work on all platforms + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include + +/** + Set the boot manager to boot from a specific device on the next boot. This + should be set only for the next boot and shouldn't require any manual clean up + + @retval EFI_SUCCESS Boot device for next boot was set. + @retval EFI_UNSUPPORTED Setting the boot device for the next boot is not + supportted. + @retval Other Boot device for next boot can not be set. +**/ +EFI_STATUS +EFIAPI +SetBootNextDevice ( + VOID + ) +{ + EFI_STATUS Status; + EFI_BOOT_MANAGER_LOAD_OPTION NewOption; + UINT32 Attributes; + UINT8 *OptionalData; + UINT32 OptionalDataSize; + UINT16 BootNextValue; + USB_CLASS_DEVICE_PATH UsbDp; + EFI_DEVICE_PATH_PROTOCOL *DpEnd; + EFI_DEVICE_PATH_PROTOCOL *Dp; + BOOLEAN NewOptionValid; + + OptionalData = NULL; + OptionalDataSize = 0; + BootNextValue = 0xABCD; // this should be a safe number... + DpEnd = NULL; + Dp = NULL; + NewOptionValid = FALSE; + + UsbDp.Header.Length[0] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) & 0xff); + UsbDp.Header.Length[1] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) >> 8); + UsbDp.Header.Type = MESSAGING_DEVICE_PATH; + UsbDp.Header.SubType = MSG_USB_CLASS_DP; + UsbDp.VendorId = 0xFFFF; + UsbDp.ProductId = 0xFFFF; + UsbDp.DeviceClass = 0xFF; + UsbDp.DeviceSubClass = 0xFF; + UsbDp.DeviceProtocol = 0xFF; + + Attributes = LOAD_OPTION_ACTIVE; + + DpEnd = AppendDevicePathNode (NULL, NULL); + if (DpEnd == NULL) { + DEBUG ((DEBUG_ERROR, "%a: Unable to create device path. DpEnd is NULL.\n", __FUNCTION__)); + Status = EFI_OUT_OF_RESOURCES; + goto CLEANUP; + } + + //@MRT --- Is this memory leak because we lose the old Dp memory + Dp = AppendDevicePathNode ( + DpEnd, + (EFI_DEVICE_PATH_PROTOCOL *)&UsbDp + ); + if (Dp == NULL) { + DEBUG((DEBUG_ERROR, "%a: Unable to create device path. Dp is NULL.\n", __FUNCTION__)); + Status = EFI_OUT_OF_RESOURCES; + goto CLEANUP; + } + + Status = EfiBootManagerInitializeLoadOption ( + &NewOption, + (UINTN) BootNextValue, + LoadOptionTypeBoot, + Attributes, + L"Generic USB Class Device", + Dp, + OptionalData, + OptionalDataSize + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Error creating load option. Status = %r\n", __FUNCTION__, Status)); + goto CLEANUP; + } + + NewOptionValid = TRUE; + DEBUG ((DEBUG_VERBOSE, "%a: Generic USB Class Device boot option created.\n", __FUNCTION__)); + Status = EfiBootManagerLoadOptionToVariable (&NewOption); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Error Saving boot option NV variable. Status = %r\n", __FUNCTION__, Status)); + goto CLEANUP; + } + + // + // Set Boot Next + // + Status = gRT->SetVariable ( + L"BootNext", + &gEfiGlobalVariableGuid, + (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE), + sizeof(BootNextValue), + &(BootNextValue) + ); + + DEBUG((DEBUG_VERBOSE, "%a - Set BootNext Status (%r)\n", __FUNCTION__, Status)); + +CLEANUP: + if (Dp != NULL) { + FreePool (Dp); + } + if (DpEnd != NULL) { + FreePool (DpEnd); + } + if (NewOptionValid) { + EfiBootManagerFreeLoadOption (&NewOption); + } + return Status; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.inf b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.inf new file mode 100644 index 00000000000..80c4e4f111f --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.inf @@ -0,0 +1,34 @@ +## @file +# Library to support booting to USB on the next boot +# This instance uses the industry standard usb class boot option. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestBootLibUsbClass + MODULE_UNI_FILE = UnitTestBootLibUsbClass.uni + FILE_GUID = DFADE2A2-DB69-47DE-A37A-40FB6D52E844 + VERSION_STRING = 1.0 + MODULE_TYPE = UEFI_APPLICATION + LIBRARY_CLASS = UnitTestBootLib + +[Sources] + UnitTestBootLibUsbClass.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + DebugLib + UefiRuntimeServicesTableLib + MemoryAllocationLib + DevicePathLib + UefiBootManagerLib + +[Guids] + gEfiGlobalVariableGuid ## CONSUMES ## Used to probe boot options and set BootNext. diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.uni b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.uni new file mode 100644 index 00000000000..8468b3537c2 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.uni @@ -0,0 +1,12 @@ +// /** @file +// Library to support booting to USB on the next boot +// This instance uses the industry standard usb class boot option. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to support booting to USB on the next boot" + +#string STR_MODULE_DESCRIPTION #language en-US "This instance uses the industry standard usb class boot option.." diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c new file mode 100644 index 00000000000..dd85b84b080 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c @@ -0,0 +1,491 @@ +/** + Implement UnitTestLib assert services + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include + +STATIC +EFI_STATUS +AddUnitTestFailure ( + IN OUT UNIT_TEST *UnitTest, + IN CONST CHAR8 *FailureMessage, + IN FAILURE_TYPE FailureType + ) +{ + // + // Make sure that you're cooking with gas. + // + if (UnitTest == NULL || FailureMessage == NULL) { + return EFI_INVALID_PARAMETER; + } + + UnitTest->FailureType = FailureType; + AsciiStrCpyS ( + &UnitTest->FailureMessage[0], + UNIT_TEST_TESTFAILUREMSG_LENGTH, + FailureMessage + ); + + return EFI_SUCCESS; +} + +STATIC +VOID +UnitTestLogFailure ( + IN FAILURE_TYPE FailureType, + IN CONST CHAR8 *Format, + ... + ) +{ + UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle; + CHAR8 LogString[UNIT_TEST_TESTFAILUREMSG_LENGTH]; + VA_LIST Marker; + + // + // Get active Framework handle + // + FrameworkHandle = GetActiveFrameworkHandle (); + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (LogString, sizeof (LogString), Format, Marker); + VA_END (Marker); + + // + // Finally, add the string to the log. + // + AddUnitTestFailure ( + ((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest, + LogString, + FailureType + ); + + return; +} + +/** + If Expression is TRUE, then TRUE is returned. + If Expression is FALSE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is TRUE. + @retval FALSE Expression is FALSE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (!Expression) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTTRUE, + "%a::%d Expression (%a) is not TRUE!\n", + FunctionName, + LineNumber, + Description + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Expression (%a) is not TRUE!\n", + FunctionName, + LineNumber, + Description + ); + } + return Expression; +} + +/** + If Expression is FALSE, then TRUE is returned. + If Expression is TRUE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is FALSE. + @retval FALSE Expression is TRUE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (Expression) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTFALSE, + "%a::%d Expression(%a) is not FALSE!\n", + FunctionName, + LineNumber, + Description + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Expression (%a) is not FALSE!\n", + FunctionName, + LineNumber, + Description + ); + } + return !Expression; +} + +/** + If Status is not an EFI_ERROR(), then TRUE is returned. + If Status is an EFI_ERROR(), then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Status The EFI_STATUS value to evaluate. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the status + expression being evaluated. + + @retval TRUE Status is not an EFI_ERROR(). + @retval FALSE Status is an EFI_ERROR(). +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (EFI_ERROR (Status)) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTNOTEFIERROR, + "%a::%d Status '%a' is EFI_ERROR (%r)!\n", + FunctionName, + LineNumber, + Description, + Status + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Status '%a' is EFI_ERROR (%r)!\n", + FunctionName, + LineNumber, + Description, + Status + ); + } + return !EFI_ERROR( Status ); +} + +/** + If ValueA is equal ValueB, then TRUE is returned. + If ValueA is not equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA, + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is equal to ValueB. + @retval FALSE ValueA is not equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if ((ValueA != ValueB)) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTEQUAL, + "%a::%d Value %a != %a (%d != %d)!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Value %a != %a (%d != %d)!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + } + return (ValueA == ValueB); +} + +/** + If the contents of BufferA are identical to the contents of BufferB, then TRUE + is returned. If the contents of BufferA are not identical to the contents of + BufferB, then an assert is triggered and the location of the assert provided + by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are + recorded and FALSE is returned. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and BufferB. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of BufferA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of BufferB. + + @retval TRUE The contents of BufferA are identical to the contents of + BufferB. + @retval FALSE The contents of BufferA are not identical to the contents of + BufferB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertMemEqual ( + IN VOID *BufferA, + IN VOID *BufferB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if (CompareMem(BufferA, BufferB, Length) != 0) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTEQUAL, + "%a::%d Memory at %a != %a for length %d bytes!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + Length + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Value %a != %a for length %d bytes!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + Length + ); + return FALSE; + } + return TRUE; +} + +/** + If ValueA is not equal ValueB, then TRUE is returned. + If ValueA is equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is not equal to ValueB. + @retval FALSE ValueA is equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if ((ValueA == ValueB)) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTNOTEQUAL, + "%a::%d Value %a == %a (%d == %d)!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Value %a == %a (%d == %d)!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + } + return (ValueA != ValueB); +} + +/** + If Status is equal to Expected, then TRUE is returned. + If Status is not equal to Expected, then an assert is triggered and the + location of the assert provided by FunctionName, LineNumber, FileName, and + Description are recorded and FALSE is returned. + + @param[in] Status EFI_STATUS value returned from an API under test. + @param[in] Expected The expected EFI_STATUS return value from an API + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string that is a description + of Status. + + @retval TRUE Status is equal to Expected. + @retval FALSE Status is not equal to Expected. +**/ +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if ((Status != Expected)) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTSTATUSEQUAL, + "%a::%d Status '%a' is %r, should be %r!\n", + FunctionName, + LineNumber, + Description, + Status, + Expected + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Status '%a' is %r, should be %r!\n", + FunctionName, + LineNumber, + Description, + Status, + Expected + ); + } + return (Status == Expected); +} + +/** + If Pointer is not equal to NULL, then TRUE is returned. + If Pointer is equal to NULL, then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and PointerName + are recorded and FALSE is returned. + + @param[in] Pointer Pointer value to be checked against NULL. + @param[in] Expected The expected EFI_STATUS return value from a function + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] PointerName Null-terminated ASCII string that is a description + of Pointer. + + @retval TRUE Pointer is not equal to NULL. + @retval FALSE Pointer is equal to NULL. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotNull ( + IN VOID *Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *PointerName + ) +{ + if (Pointer == NULL) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTNOTNULL, + "%a::%d Pointer (%a) is NULL!\n", + FunctionName, + LineNumber, + PointerName + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Pointer (%a) is NULL!\n", + FunctionName, + LineNumber, + PointerName + ); + } + return (Pointer != NULL); +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c new file mode 100644 index 00000000000..e48d614976c --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c @@ -0,0 +1,335 @@ +/** @file + Implement UnitTestLib assert services using cmocka services + + Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_STRING_SIZE 1025 + +/** + If Expression is TRUE, then TRUE is returned. + If Expression is FALSE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is TRUE. + @retval FALSE Expression is FALSE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_TRUE(%s:%x)", Description, Expression); + _assert_true (Expression, TempStr, FileName, (INT32)LineNumber); + + return Expression; +} + +/** + If Expression is FALSE, then TRUE is returned. + If Expression is TRUE, then an assert is triggered and the location of the + assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluation. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression being + evaluated. + + @retval TRUE Expression is FALSE. + @retval FALSE Expression is TRUE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_FALSE(%s:%x)", Description, Expression); + _assert_true (!Expression, TempStr, FileName, (INT32)LineNumber); + + return !Expression; +} + +/** + If Status is not an EFI_ERROR(), then TRUE is returned. + If Status is an EFI_ERROR(), then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and Description are + recorded and FALSE is returned. + + @param[in] Status The EFI_STATUS value to evaluate. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the status + expression being evaluated. + + @retval TRUE Status is not an EFI_ERROR(). + @retval FALSE Status is an EFI_ERROR(). +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_EFI_ERROR(%s:%p)", Description, (void *)Status); + _assert_true (!EFI_ERROR (Status), TempStr, FileName, (INT32)LineNumber); + + return !EFI_ERROR (Status); +} + +/** + If ValueA is equal ValueB, then TRUE is returned. + If ValueA is not equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA, + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is equal to ValueB. + @retval FALSE ValueA is not equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB); + _assert_true ((ValueA == ValueB), TempStr, FileName, (INT32)LineNumber); + + return (ValueA == ValueB); +} + +/** + If the contents of BufferA are identical to the contents of BufferB, then TRUE + is returned. If the contents of BufferA are not identical to the contents of + BufferB, then an assert is triggered and the location of the assert provided + by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are + recorded and FALSE is returned. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and BufferB. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of BufferA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of BufferB. + + @retval TRUE The contents of BufferA are identical to the contents of + BufferB. + @retval FALSE The contents of BufferA are not identical to the contents of + BufferB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertMemEqual ( + IN VOID *BufferA, + IN VOID *BufferB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + BOOLEAN Result; + + Result = (CompareMem(BufferA, BufferB, Length) == 0); + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_MEM_EQUAL(%s:%p, %s:%p)", DescriptionA, BufferA, DescriptionB, BufferB); + _assert_true (Result, TempStr, FileName, (INT32)LineNumber); + + return Result; +} + +/** + If ValueA is not equal ValueB, then TRUE is returned. + If ValueA is equal to ValueB, then an assert is triggered and the location + of the assert provided by FunctionName, LineNumber, FileName, DescriptionA + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a description + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a description + of ValueB. + + @retval TRUE ValueA is not equal to ValueB. + @retval FALSE ValueA is equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB); + _assert_true ((ValueA != ValueB), TempStr, FileName, (INT32)LineNumber); + + return (ValueA != ValueB); +} + +/** + If Status is equal to Expected, then TRUE is returned. + If Status is not equal to Expected, then an assert is triggered and the + location of the assert provided by FunctionName, LineNumber, FileName, and + Description are recorded and FALSE is returned. + + @param[in] Status EFI_STATUS value returned from an API under test. + @param[in] Expected The expected EFI_STATUS return value from an API + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string that is a description + of Status. + + @retval TRUE Status is equal to Expected. + @retval FALSE Status is not equal to Expected. +**/ +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_STATUS_EQUAL(%s:%p)", Description, (VOID *)Status); + _assert_true ((Status == Expected), TempStr, FileName, (INT32)LineNumber); + + return (Status == Expected); +} + +/** + If Pointer is not equal to NULL, then TRUE is returned. + If Pointer is equal to NULL, then an assert is triggered and the location of + the assert provided by FunctionName, LineNumber, FileName, and PointerName + are recorded and FALSE is returned. + + @param[in] Pointer Pointer value to be checked against NULL. + @param[in] Expected The expected EFI_STATUS return value from a function + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macro. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] PointerName Null-terminated ASCII string that is a description + of Pointer. + + @retval TRUE Pointer is not equal to NULL. + @retval FALSE Pointer is equal to NULL. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotNull ( + IN VOID *Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *PointerName + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_NULL(%s:%p)", PointerName, Pointer); + _assert_true ((Pointer != NULL), TempStr, FileName, (INT32)LineNumber); + + return (Pointer != NULL); +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c b/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c new file mode 100644 index 00000000000..78df086a28d --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c @@ -0,0 +1,200 @@ +/** + Implemnet UnitTestLib log services + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH (512) +#define UNIT_TEST_MAX_LOG_BUFFER SIZE_16KB + +struct _UNIT_TEST_LOG_PREFIX_STRING { + UNIT_TEST_STATUS LogLevel; + CHAR8 *String; +}; + +struct _UNIT_TEST_LOG_PREFIX_STRING mLogPrefixStrings[] = { + { UNIT_TEST_LOG_LEVEL_ERROR, "[ERROR] " }, + { UNIT_TEST_LOG_LEVEL_WARN, "[WARNING] " }, + { UNIT_TEST_LOG_LEVEL_INFO, "[INFO] " }, + { UNIT_TEST_LOG_LEVEL_VERBOSE, "[VERBOSE] " } +}; + +// +// Unit-Test Log helper functions +// + +STATIC +CONST CHAR8* +GetStringForStatusLogPrefix ( + IN UINTN LogLevel + ) +{ + UINTN Index; + CHAR8 *Result; + + Result = NULL; + for (Index = 0; Index < ARRAY_SIZE (mLogPrefixStrings); Index++) { + if (mLogPrefixStrings[Index].LogLevel == LogLevel) { + Result = mLogPrefixStrings[Index].String; + break; + } + } + return Result; +} + +STATIC +EFI_STATUS +AddStringToUnitTestLog ( + IN OUT UNIT_TEST *UnitTest, + IN CONST CHAR8 *String + ) +{ + EFI_STATUS Status; + + // + // Make sure that you're cooking with gas. + // + if (UnitTest == NULL || String == NULL) { + return EFI_INVALID_PARAMETER; + } + + // If this is the first log for the test allocate log space + if (UnitTest->Log == NULL) { + UnitTestLogInit (UnitTest, NULL, 0); + } + + if (UnitTest->Log == NULL) { + DEBUG ((DEBUG_ERROR, "Failed to allocate space for unit test log\n")); + ASSERT (UnitTest->Log != NULL); + return EFI_OUT_OF_RESOURCES; + } + + Status = AsciiStrnCatS ( + UnitTest->Log, + UNIT_TEST_MAX_LOG_BUFFER / sizeof (CHAR8), + String, + UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH + ); + if(EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to add unit test log string. Status = %r\n", Status)); + return Status; + } + + return EFI_SUCCESS; +} + +/** + This function is responsible for initializing the log buffer for a single test. It can + be used internally, but may also be consumed by the test framework to add pre-existing + data to a log before it's used. + + @param[in,out] TestHandle A handle to the test being initialized. + @param[in] Buffer [Optional] A pointer to pre-existing log data that should + be used to initialize the log. Should include a NULL terminator. + @param[in] BufferSize [Optional] The size of the pre-existing log data. + +**/ +VOID +EFIAPI +UnitTestLogInit ( + IN OUT UNIT_TEST *Test, + IN UINT8 *Buffer, OPTIONAL + IN UINTN BufferSize OPTIONAL + ) +{ + // + // Make sure that you're cooking with gas. + // + if (Test == NULL) { + DEBUG ((DEBUG_ERROR, "%a called with invalid Test parameter\n", __FUNCTION__)); + return; + } + + // + // If this is the first log for the test allocate log space + // + if (Test->Log == NULL) { + Test->Log = AllocateZeroPool (UNIT_TEST_MAX_LOG_BUFFER); + } + + // + //check again to make sure allocate worked + // + if(Test->Log == NULL) { + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for the log\n")); + return; + } + + if((Buffer != NULL) && (BufferSize > 0) && ((BufferSize <= UNIT_TEST_MAX_LOG_BUFFER))) { + CopyMem (Test->Log, Buffer, BufferSize); + } +} + +/** + Test logging function that records a messages in the test framework log. + Record is associated with the currently executing test case. + + @param[in] ErrorLevel The error level of the unit test log message. + @param[in] Format Formatting string following the format defined in the + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +VOID +EFIAPI +UnitTestLog ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ) +{ + UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle; + CHAR8 NewFormatString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH]; + CHAR8 LogString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH]; + CONST CHAR8 *LogTypePrefix; + VA_LIST Marker; + + FrameworkHandle = GetActiveFrameworkHandle (); + + LogTypePrefix = NULL; + + // + // Make sure that this unit test log level is enabled. + // + if ((ErrorLevel & (UINTN)PcdGet32 (PcdUnitTestLogLevel)) == 0) { + return; + } + + // + // If we need to define a new format string... + // well... get to it. + // + LogTypePrefix = GetStringForStatusLogPrefix (ErrorLevel); + if (LogTypePrefix != NULL) { + AsciiSPrint (NewFormatString, sizeof (NewFormatString), "%a%a", LogTypePrefix, Format); + } else { + AsciiStrCpyS (NewFormatString, sizeof (NewFormatString), Format); + } + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (LogString, sizeof (LogString), NewFormatString, Marker); + VA_END (Marker); + + // + // Finally, add the string to the log. + // + AddStringToUnitTestLog (((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest, LogString); +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c new file mode 100644 index 00000000000..d66382e2d3a --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c @@ -0,0 +1,171 @@ +/** + UnitTestLib APIs to run unit tests + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL; + +UNIT_TEST_FRAMEWORK_HANDLE +GetActiveFrameworkHandle ( + VOID + ) +{ + ASSERT (mFrameworkHandle != NULL); + return mFrameworkHandle; +} + +STATIC +EFI_STATUS +RunTestSuite ( + IN UNIT_TEST_SUITE *Suite + ) +{ + UNIT_TEST_LIST_ENTRY *TestEntry; + UNIT_TEST *Test; + UNIT_TEST_FRAMEWORK *ParentFramework; + + TestEntry = NULL; + ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework; + + if (Suite == NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title)); + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + + if (Suite->Setup != NULL) { + Suite->Setup (); + } + + // + // Iterate all tests within the suite + // + for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList)); + (LIST_ENTRY*)TestEntry != &(Suite->TestCaseList); + TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry)) { + Test = &TestEntry->UT; + ParentFramework->CurrentTest = Test; + + DEBUG ((DEBUG_VERBOSE, "*********************************************************\n")); + DEBUG ((DEBUG_VERBOSE, " RUNNING TEST: %a:\n", Test->Description)); + DEBUG ((DEBUG_VERBOSE, "**********************************************************\n")); + + // + // First, check to see whether the test has already been run. + // NOTE: This would generally only be the case if a saved state was detected and loaded. + // + if (Test->Result != UNIT_TEST_PENDING && Test->Result != UNIT_TEST_RUNNING) { + DEBUG ((DEBUG_VERBOSE, "Test was run on a previous pass. Skipping.\n")); + ParentFramework->CurrentTest = NULL; + continue; + } + + // + // Next, if we're still running, make sure that our test prerequisites are in place. + if (Test->Result == UNIT_TEST_PENDING && Test->Prerequisite != NULL) { + DEBUG ((DEBUG_VERBOSE, "PREREQ\n")); + if (Test->Prerequisite (Test->Context) != UNIT_TEST_PASSED) { + DEBUG ((DEBUG_ERROR, "Prerequisite Not Met\n")); + Test->Result = UNIT_TEST_ERROR_PREREQUISITE_NOT_MET; + ParentFramework->CurrentTest = NULL; + continue; + } + } + + // + // Now we should be ready to call the actual test. + // We set the status to UNIT_TEST_RUNNING in case the test needs to reboot + // or quit. The UNIT_TEST_RUNNING state will allow the test to resume + // but will prevent the Prerequisite from being dispatched a second time. + Test->Result = UNIT_TEST_RUNNING; + Test->Result = Test->RunTest (Test->Context); + + // + // Finally, clean everything up, if need be. + if (Test->CleanUp != NULL) { + DEBUG ((DEBUG_VERBOSE, "CLEANUP\n")); + Test->CleanUp (Test->Context); + } + + // + // End the test. + // + ParentFramework->CurrentTest = NULL; + } + + if (Suite->Teardown != NULL) { + Suite->Teardown (); + } + + return EFI_SUCCESS; +} + +/** + Execute all unit test cases in all unit test suites added to a Framework. + + Once a unit test framework is initialized and all unit test suites and unit + test cases are registered, this function will cause the unit test framework to + dispatch all unit test cases in sequence and record the results for reporting. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + + @retval EFI_SUCCESS All test cases were dispached. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +RunAllTestSuites ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SUITE_LIST_ENTRY *Suite; + EFI_STATUS Status; + + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Suite = NULL; + + if (Framework == NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG ((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES --------------\n")); + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + mFrameworkHandle = FrameworkHandle; + + // + // Iterate all suites + // + for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList); + (LIST_ENTRY *)Suite != &Framework->TestSuiteList; + Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite)) { + Status = RunTestSuite (&(Suite->UTS)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status)); + } + } + + // + // Save current state so if test is started again it doesn't have to run. It will just report + // + SaveFrameworkState (FrameworkHandle, NULL, 0); + OutputUnitTestFrameworkReport (FrameworkHandle); + + mFrameworkHandle = NULL; + + return EFI_SUCCESS; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c new file mode 100644 index 00000000000..cb9c881723e --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c @@ -0,0 +1,278 @@ +/** @file + UnitTestLib APIs to run unit tests using cmocka + + Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL; + +UNIT_TEST_FRAMEWORK_HANDLE +GetActiveFrameworkHandle ( + VOID + ) +{ + ASSERT (mFrameworkHandle != NULL); + return mFrameworkHandle; +} + +// +// The currently active test suite +// +UNIT_TEST_SUITE *mActiveUnitTestSuite = NULL; + +void +CmockaUnitTestFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + + UnitTest = (UNIT_TEST *)(*state); + Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->RunTest == NULL) { + UnitTest->Result = UNIT_TEST_SKIPPED; + } else { + UnitTest->Result = UNIT_TEST_RUNNING; + + Framework->CurrentTest = UnitTest; + UnitTest->Result = UnitTest->RunTest (UnitTest->Context); + Framework->CurrentTest = NULL; + + // Print out the log messages - This is a partial solution as it + // does not get the log into the XML. Need cmocka changes to support + // stdout and stderr in their xml format + // + if (UnitTest->Log != NULL) { + print_message("UnitTest: %s - %s\n", UnitTest->Name, UnitTest->Description); + print_message("Log Output Start\n"); + print_message("%s", UnitTest->Log); + print_message("Log Output End\n"); + } + } +} + +int +CmockaUnitTestSetupFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_STATUS Result; + + UnitTest = (UNIT_TEST *)(*state); + Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->Prerequisite == NULL) { + return 0; + } + + Framework->CurrentTest = UnitTest; + Result = UnitTest->Prerequisite (UnitTest->Context); + Framework->CurrentTest = NULL; + + // + // Return 0 for success. Non-zero for error. + // + return (int)Result; +} + +int +CmockaUnitTestTeardownFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + + UnitTest = (UNIT_TEST *)(*state); + Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->CleanUp == NULL) { + return 0; + } + + Framework->CurrentTest = UnitTest; + UnitTest->CleanUp (UnitTest->Context); + Framework->CurrentTest = NULL; + // + // Return 0 for success. Non-zero for error. + // + return 0; +} + +int +CmockaUnitTestSuiteSetupFunctionRunner ( + void **state + ) +{ + if (mActiveUnitTestSuite == NULL) { + return -1; + } + if (mActiveUnitTestSuite->Setup == NULL) { + return 0; + } + + mActiveUnitTestSuite->Setup (); + // + // Always succeed + // + return 0; +} + +int +CmockaUnitTestSuiteTeardownFunctionRunner ( + void **state + ) +{ + if (mActiveUnitTestSuite == NULL) { + return -1; + } + if (mActiveUnitTestSuite->Teardown == NULL) { + return 0; + } + + mActiveUnitTestSuite->Teardown (); + // + // Always succeed + // + return 0; +} + +STATIC +EFI_STATUS +RunTestSuite ( + IN UNIT_TEST_SUITE *Suite + ) +{ + UNIT_TEST_LIST_ENTRY *TestEntry; + UNIT_TEST *UnitTest; + struct CMUnitTest *Tests; + UINTN Index; + + TestEntry = NULL; + + if (Suite == NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title)); + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + + // + // Allocate buffer of CMUnitTest entries + // + Tests = AllocateZeroPool (Suite->NumTests * sizeof (struct CMUnitTest)); + ASSERT (Tests != NULL); + + // + // Populate buffer of CMUnitTest entries + // + Index = 0; + for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList)); + (LIST_ENTRY *)TestEntry != &(Suite->TestCaseList); + TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry)) { + UnitTest = &TestEntry->UT; + Tests[Index].name = UnitTest->Description; + Tests[Index].test_func = CmockaUnitTestFunctionRunner; + Tests[Index].setup_func = CmockaUnitTestSetupFunctionRunner; + Tests[Index].teardown_func = CmockaUnitTestTeardownFunctionRunner; + Tests[Index].initial_state = UnitTest; + Index++; + } + ASSERT (Index == Suite->NumTests); + + // + // Run all unit tests in a test suite + // + mActiveUnitTestSuite = Suite; + _cmocka_run_group_tests ( + Suite->Title, + Tests, + Suite->NumTests, + CmockaUnitTestSuiteSetupFunctionRunner, + CmockaUnitTestSuiteTeardownFunctionRunner + ); + mActiveUnitTestSuite = NULL; + FreePool (Tests); + + return EFI_SUCCESS; +} + +/** + Execute all unit test cases in all unit test suites added to a Framework. + + Once a unit test framework is initialized and all unit test suites and unit + test cases are registered, this function will cause the unit test framework to + dispatch all unit test cases in sequence and record the results for reporting. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + + @retval EFI_SUCCESS All test cases were dispached. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +RunAllTestSuites ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SUITE_LIST_ENTRY *Suite; + EFI_STATUS Status; + + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Suite = NULL; + + if (Framework == NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES --------------\n")); + DEBUG((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + mFrameworkHandle = FrameworkHandle; + + // + // Iterate all suites + // + for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList); + (LIST_ENTRY *)Suite != &Framework->TestSuiteList; + Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite)) { + Status = RunTestSuite (&(Suite->UTS)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status)); + } + } + + mFrameworkHandle = NULL; + + return EFI_SUCCESS; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c new file mode 100644 index 00000000000..e37c78a41d9 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c @@ -0,0 +1,853 @@ +/** + Implement UnitTestLib + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/// +/// Forward declaration of prototype +/// +STATIC +VOID +UpdateTestFromSave ( + IN OUT UNIT_TEST *Test, + IN UNIT_TEST_SAVE_HEADER *SavedState + ); + +/** + This function will determine whether the short name violates any rules that would + prevent it from being used as a reporting name or as a serialization name. + + Example: If the name cannot be serialized to a filesystem file name. + + @param[in] ShortTitleString A pointer to the short title string to be evaluated. + + @retval TRUE The string is acceptable. + @retval FALSE The string should not be used. + +**/ +STATIC +BOOLEAN +IsFrameworkShortNameValid ( + IN CHAR8 *ShortTitleString + ) +{ + // TODO: Finish this function. + return TRUE; +} + +STATIC +CHAR8* +AllocateAndCopyString ( + IN CHAR8 *StringToCopy + ) +{ + CHAR8 *NewString; + UINTN NewStringLength; + + NewString = NULL; + NewStringLength = AsciiStrnLenS (StringToCopy, UNIT_TEST_MAX_STRING_LENGTH) + 1; + NewString = AllocatePool (NewStringLength * sizeof( CHAR8 )); + if (NewString != NULL) { + AsciiStrCpyS (NewString, NewStringLength, StringToCopy); + } + return NewString; +} + +STATIC +VOID +SetFrameworkFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_FRAMEWORK *Framework + ) +{ + UINT32 NewFingerprint; + + // For this one we'll just use the title and version as the unique fingerprint. + NewFingerprint = CalculateCrc32( Framework->Title, (AsciiStrLen( Framework->Title ) * sizeof( CHAR8 )) ); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Framework->VersionString, (AsciiStrLen( Framework->VersionString ) * sizeof( CHAR8 )) ); + + CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE ); + return; +} + +STATIC +VOID +SetSuiteFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_FRAMEWORK *Framework, + IN UNIT_TEST_SUITE *Suite + ) +{ + UINT32 NewFingerprint; + + // For this one, we'll use the fingerprint from the framework, and the title of the suite. + NewFingerprint = CalculateCrc32( &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE ); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Suite->Title, (AsciiStrLen( Suite->Title ) * sizeof( CHAR8 )) ); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Suite->Name, (AsciiStrLen(Suite->Name) * sizeof(CHAR8)) ); + + CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE ); + return; +} + +STATIC +VOID +SetTestFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_SUITE *Suite, + IN UNIT_TEST *Test + ) +{ + UINT32 NewFingerprint; + + // For this one, we'll use the fingerprint from the suite, and the description and classname of the test. + NewFingerprint = CalculateCrc32( &Suite->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE ); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Test->Description, (AsciiStrLen( Test->Description ) * sizeof( CHAR8 )) ); + NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Test->Name, (AsciiStrLen(Test->Name) * sizeof(CHAR8)) ); + + CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE ); + return; +} + +STATIC +BOOLEAN +CompareFingerprints ( + IN UINT8 *FingerprintA, + IN UINT8 *FingerprintB + ) +{ + return (CompareMem( FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SIZE ) == 0); +} + +/** + Cleanup a test framework. + + After tests are run, this will teardown the entire framework and free all + allocated data within. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + + @retval EFI_SUCCESS All resources associated with framework were + freed. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +FreeUnitTestFramework ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FreeUnitTestSuiteEntry ( + IN UNIT_TEST_SUITE_LIST_ENTRY *SuiteEntry + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FreeUnitTestTestEntry ( + IN UNIT_TEST_LIST_ENTRY *TestEntry + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} + +/** + Method to Initialize the Unit Test framework. This function registers the + test name and also initializes the internal state of the test framework to + receive any new suites and tests. + + @param[out] FrameworkHandle Unit test framework to be created. + @param[in] Title Null-terminated ASCII string that is the user + friendly name of the framework. String is + copied. + @param[in] ShortTitle Null-terminaled ASCII short string that is the + short name of the framework with no spaces. + String is copied. + @param[in] VersionString Null-terminaled ASCII version string for the + framework. String is copied. + + @retval EFI_SUCCESS The unit test framework was initialized. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is NULL. + @retval EFI_INVALID_PARAMETER VersionString is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is invalid. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + initialize the unit test framework. +**/ +EFI_STATUS +EFIAPI +InitUnitTestFramework ( + OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *ShortTitle, + IN CHAR8 *VersionString + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle; + UNIT_TEST_FRAMEWORK *NewFramework; + UNIT_TEST_SAVE_HEADER *SavedState; + + Status = EFI_SUCCESS; + NewFramework = NULL; + + // + // First, check all pointers and make sure nothing's broked. + // + if (FrameworkHandle == NULL || Title == NULL || + ShortTitle == NULL || VersionString == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Next, determine whether all of the strings are good to use. + // + if (!IsFrameworkShortNameValid (ShortTitle)) { + return EFI_INVALID_PARAMETER; + } + + // + // Next, set aside some space to start messing with the framework. + // + NewFramework = AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK)); + if (NewFramework == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Next, set up all the test data. + // + NewFrameworkHandle = (UNIT_TEST_FRAMEWORK_HANDLE)NewFramework; + NewFramework->Title = AllocateAndCopyString (Title); + NewFramework->ShortTitle = AllocateAndCopyString (ShortTitle); + NewFramework->VersionString = AllocateAndCopyString (VersionString); + NewFramework->Log = NULL; + NewFramework->CurrentTest = NULL; + NewFramework->SavedState = NULL; + if (NewFramework->Title == NULL || + NewFramework->ShortTitle == NULL || + NewFramework->VersionString == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + InitializeListHead (&(NewFramework->TestSuiteList)); + + // + // Create the framework fingerprint. + // + SetFrameworkFingerprint (&NewFramework->Fingerprint[0], NewFramework); + + // + // If there is a persisted context, load it now. + // + if (DoesCacheExist (NewFrameworkHandle)) { + SavedState = (UNIT_TEST_SAVE_HEADER *)NewFramework->SavedState; + Status = LoadUnitTestCache (NewFrameworkHandle, &SavedState); + if (EFI_ERROR (Status)) { + // + // Don't actually report it as an error, but emit a warning. + // + DEBUG (( DEBUG_ERROR, "%a - Cache was detected, but failed to load.\n", __FUNCTION__ )); + Status = EFI_SUCCESS; + } + } + +Exit: + // + // If we're good, then let's copy the framework. + // + if (!EFI_ERROR (Status)) { + *FrameworkHandle = NewFrameworkHandle; + } else { + // + // Otherwise, we need to undo this horrible thing that we've done. + // + FreeUnitTestFramework (NewFrameworkHandle); + } + + return Status; +} + +/** + Registers a Unit Test Suite in the Unit Test Framework. + At least one test suite must be registered, because all test cases must be + within a unit test suite. + + @param[out] SuiteHandle Unit test suite to create + @param[in] FrameworkHandle Unit test framework to add unit test suite to + @param[in] Title Null-terminated ASCII string that is the user + friendly name of the test suite. String is + copied. + @param[in] Name Null-terminated ASCII string that is the short + name of the test suite with no spaces. String + is copied. + @param[in] Setup Setup function, runs before suite. This is an + optional parameter that may be NULL. + @param[in] Teardown Teardown function, runs after suite. This is an + optional parameter that may be NULL. + + @retval EFI_SUCCESS The unit test suite was created. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + initialize the unit test suite. +**/ +EFI_STATUS +EFIAPI +CreateUnitTestSuite ( + OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle, + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *Name, + IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL, + IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL + ) +{ + EFI_STATUS Status; + UNIT_TEST_SUITE_LIST_ENTRY *NewSuiteEntry; + UNIT_TEST_FRAMEWORK *Framework; + + Status = EFI_SUCCESS; + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + + // + // First, let's check to make sure that our parameters look good. + // + if ((SuiteHandle == NULL) || (Framework == NULL) || (Title == NULL) || (Name == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Create the new entry. + // + NewSuiteEntry = AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY)); + if (NewSuiteEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the fields we think we need. + // + NewSuiteEntry->UTS.NumTests = 0; + NewSuiteEntry->UTS.Title = AllocateAndCopyString (Title); + NewSuiteEntry->UTS.Name = AllocateAndCopyString (Name); + NewSuiteEntry->UTS.Setup = Setup; + NewSuiteEntry->UTS.Teardown = Teardown; + NewSuiteEntry->UTS.ParentFramework = FrameworkHandle; + InitializeListHead (&(NewSuiteEntry->Entry)); // List entry for sibling suites. + InitializeListHead (&(NewSuiteEntry->UTS.TestCaseList)); // List entry for child tests. + if (NewSuiteEntry->UTS.Title == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + if (NewSuiteEntry->UTS.Name == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Create the suite fingerprint. + // + SetSuiteFingerprint( &NewSuiteEntry->UTS.Fingerprint[0], Framework, &NewSuiteEntry->UTS ); + +Exit: + // + // If everything is going well, add the new suite to the tail list for the framework. + // + if (!EFI_ERROR( Status )) { + InsertTailList (&(Framework->TestSuiteList), (LIST_ENTRY *)NewSuiteEntry); + *SuiteHandle = (UNIT_TEST_SUITE_HANDLE)(&NewSuiteEntry->UTS); + } else { + // + // Otherwise, make with the destruction. + // + FreeUnitTestSuiteEntry (NewSuiteEntry); + } + + return Status; +} + +/** + Adds test case to Suite + + @param[in] SuiteHandle Unit test suite to add test to. + @param[in] Description Null-terminated ASCII string that is the user + friendly description of a test. String is copied. + @param[in] Name Null-terminated ASCII string that is the short name + of the test with no spaces. String is copied. + @param[in] Function Unit test function. + @param[in] Prerequisite Prerequisite function, runs before test. This is + an optional parameter that may be NULL. + @param[in] CleanUp Clean up function, runs after test. This is an + optional parameter that may be NULL. + @param[in] Context Pointer to context. This is an optional parameter + that may be NULL. + + @retval EFI_SUCCESS The unit test case was added to Suite. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER Description is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_INVALID_PARAMETER Function is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + add the unit test case to Suite. +**/ +EFI_STATUS +EFIAPI +AddTestCase ( + IN UNIT_TEST_SUITE_HANDLE SuiteHandle, + IN CHAR8 *Description, + IN CHAR8 *Name, + IN UNIT_TEST_FUNCTION Function, + IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL, + IN UNIT_TEST_CLEANUP CleanUp OPTIONAL, + IN UNIT_TEST_CONTEXT Context OPTIONAL + ) +{ + EFI_STATUS Status; + UNIT_TEST_LIST_ENTRY *NewTestEntry; + UNIT_TEST_FRAMEWORK *ParentFramework; + UNIT_TEST_SUITE *Suite; + + Status = EFI_SUCCESS; + Suite = (UNIT_TEST_SUITE *)SuiteHandle; + ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework; + + // + // First, let's check to make sure that our parameters look good. + // + if ((Suite == NULL) || (Description == NULL) || (Name == NULL) || (Function == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Create the new entry. + NewTestEntry = AllocateZeroPool (sizeof( UNIT_TEST_LIST_ENTRY )); + if (NewTestEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the fields we think we need. + NewTestEntry->UT.Description = AllocateAndCopyString (Description); + NewTestEntry->UT.Name = AllocateAndCopyString (Name); + NewTestEntry->UT.FailureType = FAILURETYPE_NOFAILURE; + NewTestEntry->UT.FailureMessage[0] = '\0'; + NewTestEntry->UT.Log = NULL; + NewTestEntry->UT.Prerequisite = Prerequisite; + NewTestEntry->UT.CleanUp = CleanUp; + NewTestEntry->UT.RunTest = Function; + NewTestEntry->UT.Context = Context; + NewTestEntry->UT.Result = UNIT_TEST_PENDING; + NewTestEntry->UT.ParentSuite = SuiteHandle; + InitializeListHead (&(NewTestEntry->Entry)); // List entry for sibling tests. + if (NewTestEntry->UT.Description == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + if (NewTestEntry->UT.Name == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Create the test fingerprint. + // + SetTestFingerprint (&NewTestEntry->UT.Fingerprint[0], Suite, &NewTestEntry->UT); + + // TODO: Make sure that duplicate fingerprints cannot be created. + + // + // If there is saved test data, update this record. + // + if (ParentFramework->SavedState != NULL) { + UpdateTestFromSave (&NewTestEntry->UT, ParentFramework->SavedState); + } + +Exit: + // + // If everything is going well, add the new suite to the tail list for the framework. + // + if (!EFI_ERROR (Status)) { + InsertTailList (&(Suite->TestCaseList), (LIST_ENTRY*)NewTestEntry); + Suite->NumTests++; + } else { + // + // Otherwise, make with the destruction. + // + FreeUnitTestTestEntry (NewTestEntry); + } + + return Status; +} + +STATIC +VOID +UpdateTestFromSave ( + IN OUT UNIT_TEST *Test, + IN UNIT_TEST_SAVE_HEADER *SavedState + ) +{ + UNIT_TEST_SAVE_TEST *CurrentTest; + UNIT_TEST_SAVE_TEST *MatchingTest; + UINT8 *FloatingPointer; + UNIT_TEST_SAVE_CONTEXT *SavedContext; + UINTN Index; + + // + // First, evaluate the inputs. + // + if (Test == NULL || SavedState == NULL) { + return; + } + if (SavedState->TestCount == 0) { + return; + } + + // + // Next, determine whether a matching test can be found. + // Start at the beginning. + // + MatchingTest = NULL; + FloatingPointer = (UINT8 *)SavedState + sizeof (*SavedState); + for (Index = 0; Index < SavedState->TestCount; Index++) { + CurrentTest = (UNIT_TEST_SAVE_TEST *)FloatingPointer; + if (CompareFingerprints (&Test->Fingerprint[0], &CurrentTest->Fingerprint[0])) { + MatchingTest = CurrentTest; + // + // If there's a saved context, it's important that we iterate through the entire list. + // + if (!SavedState->HasSavedContext) { + break; + } + } + + // + // If we didn't find it, we have to increment to the next test. + // + FloatingPointer = (UINT8 *)CurrentTest + CurrentTest->Size; + } + + // + // If a matching test was found, copy the status. + // + if (MatchingTest) { + // + // Override the test status with the saved status. + // + Test->Result = MatchingTest->Result; + + Test->FailureType = MatchingTest->FailureType; + AsciiStrnCpyS ( + &Test->FailureMessage[0], + UNIT_TEST_TESTFAILUREMSG_LENGTH, + &MatchingTest->FailureMessage[0], + UNIT_TEST_TESTFAILUREMSG_LENGTH + ); + + // + // If there is a log string associated, grab that. + // We can tell that there's a log string because the "size" will be larger than + // the structure size. + // IMPORTANT NOTE: There are security implications here. + // This data is user-supplied and we're about to play kinda + // fast and loose with data buffers. + // + if (MatchingTest->Size > sizeof (UNIT_TEST_SAVE_TEST)) { + UnitTestLogInit (Test, (UINT8 *)MatchingTest->Log, MatchingTest->Size - sizeof (UNIT_TEST_SAVE_TEST)); + } + } + + // + // If the saved context exists and matches this test, grab it, too. + // + if (SavedState->HasSavedContext) { + // + // If there was a saved context, the "matching test" loop will have placed the FloatingPointer + // at the beginning of the context structure. + // + SavedContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer; + if ((SavedContext->Size - sizeof (UNIT_TEST_SAVE_CONTEXT)) > 0 && + CompareFingerprints (&Test->Fingerprint[0], &SavedContext->Fingerprint[0])) { + // + // Override the test context with the saved context. + // + Test->Context = (VOID*)SavedContext->Data; + } + } +} + +STATIC +UNIT_TEST_SAVE_HEADER* +SerializeState ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave, OPTIONAL + IN UINTN ContextToSaveSize + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SAVE_HEADER *Header; + LIST_ENTRY *SuiteListHead; + LIST_ENTRY *Suite; + LIST_ENTRY *TestListHead; + LIST_ENTRY *Test; + UINT32 TestCount; + UINT32 TotalSize; + UINTN LogSize; + UNIT_TEST_SAVE_TEST *TestSaveData; + UNIT_TEST_SAVE_CONTEXT *TestSaveContext; + UNIT_TEST *UnitTest; + UINT8 *FloatingPointer; + + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Header = NULL; + + // + // First, let's not make assumptions about the parameters. + // + if (Framework == NULL || + (ContextToSave != NULL && ContextToSaveSize == 0) || + ContextToSaveSize > MAX_UINT32) { + return NULL; + } + + // + // Next, we've gotta figure out the resources that will be required to serialize the + // the framework state so that we can persist it. + // To start with, we're gonna need a header. + // + TotalSize = sizeof (UNIT_TEST_SAVE_HEADER); + // + // Now we need to figure out how many tests there are. + // + TestCount = 0; + // + // Iterate all suites. + // + SuiteListHead = &Framework->TestSuiteList; + for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) { + // + // Iterate all tests within the suite. + // + TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList; + for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) { + UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT; + // + // Account for the size of a test structure. + // + TotalSize += sizeof( UNIT_TEST_SAVE_TEST ); + // + // If there's a log, make sure to account for the log size. + // + if (UnitTest->Log != NULL) { + // + // The +1 is for the NULL character. Can't forget the NULL character. + // + LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8); + ASSERT (LogSize < MAX_UINT32); + TotalSize += (UINT32)LogSize; + } + // + // Increment the test count. + // + TestCount++; + } + } + // + // If there are no tests, we're done here. + // + if (TestCount == 0) { + return NULL; + } + // + // Add room for the context, if there is one. + // + if (ContextToSave != NULL) { + TotalSize += sizeof (UNIT_TEST_SAVE_CONTEXT) + (UINT32)ContextToSaveSize; + } + + // + // Now that we know the size, we need to allocate space for the serialized output. + // + Header = AllocateZeroPool (TotalSize); + if (Header == NULL) { + return NULL; + } + + // + // Alright, let's start setting up some data. + // + Header->Version = UNIT_TEST_PERSISTENCE_LIB_VERSION; + Header->SaveStateSize = TotalSize; + CopyMem (&Header->Fingerprint[0], &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE); + CopyMem (&Header->StartTime, &Framework->StartTime, sizeof (EFI_TIME)); + Header->TestCount = TestCount; + Header->HasSavedContext = FALSE; + + // + // Start adding all of the test cases. + // Set the floating pointer to the start of the current test save buffer. + // + FloatingPointer = (UINT8*)Header + sizeof( UNIT_TEST_SAVE_HEADER ); + // + // Iterate all suites. + // + SuiteListHead = &Framework->TestSuiteList; + for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) { + // + // Iterate all tests within the suite. + // + TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList; + for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) { + TestSaveData = (UNIT_TEST_SAVE_TEST *)FloatingPointer; + UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT; + + // + // Save the fingerprint. + // + CopyMem (&TestSaveData->Fingerprint[0], &UnitTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE); + + // + // Save the result. + // + TestSaveData->Result = UnitTest->Result; + TestSaveData->FailureType = UnitTest->FailureType; + AsciiStrnCpyS (&TestSaveData->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH, &UnitTest->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH); + + + // + // If there is a log, save the log. + // + FloatingPointer += sizeof (UNIT_TEST_SAVE_TEST); + if (UnitTest->Log != NULL) { + // + // The +1 is for the NULL character. Can't forget the NULL character. + // + LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8); + CopyMem (FloatingPointer, UnitTest->Log, LogSize); + FloatingPointer += LogSize; + } + + // + // Update the size once the structure is complete. + // NOTE: Should this be a straight cast without validation? + // + TestSaveData->Size = (UINT32)(FloatingPointer - (UINT8 *)TestSaveData); + } + } + + // + // If there is a context to save, let's do that now. + // + if (ContextToSave != NULL && Framework->CurrentTest != NULL) { + TestSaveContext = (UNIT_TEST_SAVE_CONTEXT*)FloatingPointer; + TestSaveContext->Size = (UINT32)ContextToSaveSize + sizeof (UNIT_TEST_SAVE_CONTEXT); + CopyMem (&TestSaveContext->Fingerprint[0], &Framework->CurrentTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE); + CopyMem (((UINT8 *)TestSaveContext + sizeof (UNIT_TEST_SAVE_CONTEXT)), ContextToSave, ContextToSaveSize); + Header->HasSavedContext = TRUE; + } + + return Header; +} + +/** + Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're + a framework author) to save the state of the executing framework along with + any allocated data so that the test may be resumed upon reentry. A test case + should pass any needed context (which, to prevent an infinite loop, should be + at least the current execution count) which will be saved by the framework and + passed to the test case upon resume. + + Generally called from within a test case prior to quitting or rebooting. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + @param[in] ContextToSave A buffer of test case-specific data to be saved + along with framework state. Will be passed as + "Context" to the test case upon resume. This + is an optional parameter that may be NULL. + @param[in] ContextToSaveSize Size of the ContextToSave buffer. + + @retval EFI_SUCCESS The framework state and context were saved. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and + ContextToSaveSize is 0. + @retval EFI_INVALID_PARAMETER ContextToSave is >= 4GB. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + save the framework and context state. + @retval EFI_DEVICE_ERROR The framework and context state could not be + saved to a persistent storage device due to a + device error. +**/ +EFI_STATUS +EFIAPI +SaveFrameworkState ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize + ) +{ + EFI_STATUS Status; + UNIT_TEST_SAVE_HEADER *Header; + + Header = NULL; + + // + // First, let's not make assumptions about the parameters. + // + if (FrameworkHandle == NULL || + (ContextToSave != NULL && ContextToSaveSize == 0) || + ContextToSaveSize > MAX_UINT32) { + return EFI_INVALID_PARAMETER; + } + + // + // Now, let's package up all the data for saving. + // + Header = SerializeState (FrameworkHandle, ContextToSave, ContextToSaveSize); + if (Header == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // All that should be left to do is save it using the associated persistence lib. + // + Status = SaveUnitTestCache (FrameworkHandle, Header); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Could not save state! %r\n", __FUNCTION__, Status)); + Status = EFI_DEVICE_ERROR; + } + + // + // Free data that was used. + // + FreePool (Header); + + return Status; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf new file mode 100644 index 00000000000..96e40e973cf --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf @@ -0,0 +1,37 @@ +## @file +# Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestLib + MODULE_UNI_FILE = UnitTestLib.uni + FILE_GUID = 98CEF9CA-15CE-40A3-ADE8-C299953CD0F6 + VERSION_STRING = 1.0 + MODULE_TYPE = UEFI_DRIVER + LIBRARY_CLASS = UnitTestLib|PEIM DXE_DRIVER DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION + +[Sources] + UnitTestLib.c + RunTests.c + Assert.c + Log.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + PcdLib + DebugLib + MemoryAllocationLib + UnitTestPersistenceLib + UnitTestResultReportLib + +[Pcd] + gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni new file mode 100644 index 00000000000..fe7c9c7f715 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni @@ -0,0 +1,11 @@ +// /** @file +// Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications." diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf new file mode 100644 index 00000000000..b12af915765 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf @@ -0,0 +1,38 @@ +## @file +# Library to support Unit Testing from host environments using Cmocka services. +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestLibCmocka + MODULE_UNI_FILE = UnitTestLibCmocka.uni + FILE_GUID = C800595F-45A3-45A1-8B50-28F01C2A5A4F + VERSION_STRING = 1.0 + MODULE_TYPE = UEFI_DRIVER + LIBRARY_CLASS = UnitTestLib|HOST_APPLICATION + +[Sources] + UnitTestLib.c + RunTestsCmocka.c + AssertCmocka.c + Log.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + PcdLib + DebugLib + MemoryAllocationLib + UnitTestPersistenceLib + UnitTestResultReportLib + CmockaLib + +[Pcd] + gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni new file mode 100644 index 00000000000..aa25a44e359 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni @@ -0,0 +1,11 @@ +// /** @file +// Library to support Unit Testing from host environments using Cmocka services. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to support Unit Testing from host environments using Cmocka services" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to support Unit Testing from host environments using Cmocka services." diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.c b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.c new file mode 100644 index 00000000000..e28327652ea --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.c @@ -0,0 +1,75 @@ +/** @file + This is an instance of the Unit Test Persistence Lib that does nothing. + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include + +/** + Determines whether a persistence cache already exists for + the given framework. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + + @retval TRUE + @retval FALSE Cache doesn't exist or an error occurred. + +**/ +BOOLEAN +EFIAPI +DoesCacheExist ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + return FALSE; +} + +/** + Will save the data associated with an internal Unit Test Framework + state in a manner that can persist a Unit Test Application quit or + even a system reboot. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + @param[in] SaveData A pointer to the buffer containing the serialized + framework internal state. + + @retval EFI_SUCCESS Data is persisted and the test can be safely quit. + @retval Others Data is not persisted and test cannot be resumed upon exit. + +**/ +EFI_STATUS +EFIAPI +SaveUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_SAVE_HEADER *SaveData + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Will retrieve any cached state associated with the given framework. + Will allocate a buffer to hold the loaded data. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + @param[in] SaveData A pointer pointer that will be updated with the address + of the loaded data buffer. + + @retval EFI_SUCCESS Data has been loaded successfully and SaveData is updated + with a pointer to the buffer. + @retval Others An error has occurred and no data has been loaded. SaveData + is set to NULL. + +**/ +EFI_STATUS +EFIAPI +LoadUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + OUT UNIT_TEST_SAVE_HEADER **SaveData + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf new file mode 100644 index 00000000000..11757726624 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf @@ -0,0 +1,28 @@ +## @file +# This is an instance of the Unit Test Persistence Lib does nothing. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestPersistenceLibNull + MODULE_UNI_FILE = UnitTestPersistenceLibNull.uni + FILE_GUID = B8553C7A-0B0B-4BBD-9DF3-825804BF26AB + VERSION_STRING = 1.0 + MODULE_TYPE = UEFI_DRIVER + LIBRARY_CLASS = UnitTestPersistenceLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + UnitTestPersistenceLibNull.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.uni b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.uni new file mode 100644 index 00000000000..00f7d8d7f00 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.uni @@ -0,0 +1,11 @@ +// /** @file +// NULL library for Unit Test Persistence Lib. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "NULL library for Unit Test Persistence Lib" + +#string STR_MODULE_DESCRIPTION #language en-US "NULL library for Unit Test Persistence Lib." diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c new file mode 100644 index 00000000000..ccca9bfacb7 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c @@ -0,0 +1,416 @@ +/** @file + This is an instance of the Unit Test Persistence Lib that will utilize + the filesystem that a test application is running from to save a serialized + version of the internal test state in case the test needs to quit and restore. + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CACHE_FILE_SUFFIX L"_Cache.dat" + +/** + Generate the device path to the cache file. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + + @retval !NULL A pointer to the EFI_FILE protocol instance for the filesystem. + @retval NULL Filesystem could not be found or an error occurred. + +**/ +STATIC +EFI_DEVICE_PATH_PROTOCOL* +GetCacheFileDevicePath ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK *Framework; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + CHAR16 *AppPath; + CHAR16 *CacheFilePath; + CHAR16 *TestName; + UINTN DirectorySlashOffset; + UINTN CacheFilePathLength; + EFI_DEVICE_PATH_PROTOCOL *CacheFileDevicePath; + + Framework = (UNIT_TEST_FRAMEWORK*)FrameworkHandle; + AppPath = NULL; + CacheFilePath = NULL; + TestName = NULL; + CacheFileDevicePath = NULL; + + // + // First, we need to get some information from the loaded image. + // + Status = gBS->HandleProtocol ( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a - Failed to locate DevicePath for loaded image. %r\n", __FUNCTION__, Status)); + return NULL; + } + + // + // Before we can start, change test name from ASCII to Unicode. + // + CacheFilePathLength = AsciiStrLen (Framework->ShortTitle) + 1; + TestName = AllocatePool (CacheFilePathLength); + if (!TestName) { + goto Exit; + } + AsciiStrToUnicodeStrS (Framework->ShortTitle, TestName, CacheFilePathLength); + + // + // Now we should have the device path of the root device and a file path for the rest. + // In order to target the directory for the test application, we must process + // the file path a little. + // + // NOTE: This may not be necessary... Path processing functions exist... + // PathCleanUpDirectories (FileNameCopy); + // if (PathRemoveLastItem (FileNameCopy)) { + // + AppPath = ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE); // NOTE: This must be freed. + DirectorySlashOffset = StrLen (AppPath); + // + // Make sure we didn't get any weird data. + // + if (DirectorySlashOffset == 0) { + DEBUG ((DEBUG_ERROR, "%a - Weird 0-length string when processing app path.\n", __FUNCTION__)); + goto Exit; + } + + // + // Now that we know we have a decent string, let's take a deeper look. + // + do { + if (AppPath[DirectorySlashOffset] == L'\\') { + break; + } + DirectorySlashOffset--; + } while (DirectorySlashOffset > 0); + + // + // After that little maneuver, DirectorySlashOffset should be pointing at the last '\' in AppString. + // That would be the path to the parent directory that the test app is executing from. + // Let's check and make sure that's right. + // + if (AppPath[DirectorySlashOffset] != L'\\') { + DEBUG ((DEBUG_ERROR, "%a - Could not find a single directory separator in app path.\n", __FUNCTION__)); + goto Exit; + } + + // + // Now we know some things, we're ready to produce our output string, I think. + // + CacheFilePathLength = DirectorySlashOffset + 1; + CacheFilePathLength += StrLen (TestName); + CacheFilePathLength += StrLen (CACHE_FILE_SUFFIX); + CacheFilePathLength += 1; // Don't forget the NULL terminator. + CacheFilePath = AllocateZeroPool (CacheFilePathLength * sizeof (CHAR16)); + if (!CacheFilePath) { + goto Exit; + } + + // + // Let's produce our final path string, shall we? + // + StrnCpyS (CacheFilePath, CacheFilePathLength, AppPath, DirectorySlashOffset + 1); // Copy the path for the parent directory. + StrCatS (CacheFilePath, CacheFilePathLength, TestName); // Copy the base name for the test cache. + StrCatS (CacheFilePath, CacheFilePathLength, CACHE_FILE_SUFFIX); // Copy the file suffix. + + // + // Finally, try to create the device path for the thing thing. + // + CacheFileDevicePath = FileDevicePath (LoadedImage->DeviceHandle, CacheFilePath); + +Exit: + // + // Free allocated buffers. + // + if (AppPath != NULL) { + FreePool (AppPath); + } + if (CacheFilePath != NULL) { + FreePool (CacheFilePath); + } + if (TestName != NULL) { + FreePool (TestName); + } + + return CacheFileDevicePath; +} + +/** + Determines whether a persistence cache already exists for + the given framework. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + + @retval TRUE + @retval FALSE Cache doesn't exist or an error occurred. + +**/ +BOOLEAN +EFIAPI +DoesCacheExist ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + EFI_STATUS Status; + SHELL_FILE_HANDLE FileHandle; + + // + // NOTE: This devpath is allocated and must be freed. + // + FileDevicePath = GetCacheFileDevicePath (FrameworkHandle); + + // + // Check to see whether the file exists. If the file can be opened for + // reading, it exists. Otherwise, probably not. + // + Status = ShellOpenFileByDevicePath ( + &FileDevicePath, + &FileHandle, + EFI_FILE_MODE_READ, + 0 + ); + if (!EFI_ERROR (Status)) { + ShellCloseFile (&FileHandle); + } + + if (FileDevicePath != NULL) { + FreePool (FileDevicePath); + } + + DEBUG ((DEBUG_VERBOSE, "%a - Returning %d\n", __FUNCTION__, !EFI_ERROR (Status))); + + return (!EFI_ERROR (Status)); +} + +/** + Will save the data associated with an internal Unit Test Framework + state in a manner that can persist a Unit Test Application quit or + even a system reboot. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + @param[in] SaveData A pointer to the buffer containing the serialized + framework internal state. + + @retval EFI_SUCCESS Data is persisted and the test can be safely quit. + @retval Others Data is not persisted and test cannot be resumed upon exit. + +**/ +EFI_STATUS +EFIAPI +SaveUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_SAVE_HEADER *SaveData + ) +{ + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + EFI_STATUS Status; + SHELL_FILE_HANDLE FileHandle; + UINTN WriteCount; + + // + // Check the inputs for sanity. + // + if (FrameworkHandle == NULL || SaveData == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Determine the path for the cache file. + // NOTE: This devpath is allocated and must be freed. + // + FileDevicePath = GetCacheFileDevicePath (FrameworkHandle); + + // + //First lets open the file if it exists so we can delete it...This is the work around for truncation + // + Status = ShellOpenFileByDevicePath ( + &FileDevicePath, + &FileHandle, + (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE), + 0 + ); + + if (!EFI_ERROR (Status)) { + // + // If file handle above was opened it will be closed by the delete. + // + Status = ShellDeleteFile (&FileHandle); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a failed to delete file %r\n", __FUNCTION__, Status)); + } + } + + // + // Now that we know the path to the file... let's open it for writing. + // + Status = ShellOpenFileByDevicePath ( + &FileDevicePath, + &FileHandle, + (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE), + 0 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __FUNCTION__, Status)); + goto Exit; + } + + // + // Write the data to the file. + // + WriteCount = SaveData->SaveStateSize; + DEBUG ((DEBUG_INFO, "%a - Writing %d bytes to file...\n", __FUNCTION__, WriteCount)); + Status = ShellWriteFile ( + FileHandle, + &WriteCount, + SaveData + ); + + if (EFI_ERROR (Status) || WriteCount != SaveData->SaveStateSize) { + DEBUG ((DEBUG_ERROR, "%a - Writing to file failed! %r\n", __FUNCTION__, Status)); + } else { + DEBUG ((DEBUG_INFO, "%a - SUCCESS!\n", __FUNCTION__)); + } + + // + // No matter what, we should probably close the file. + // + ShellCloseFile (&FileHandle); + +Exit: + if (FileDevicePath != NULL) { + FreePool (FileDevicePath); + } + + return Status; +} + +/** + Will retrieve any cached state associated with the given framework. + Will allocate a buffer to hold the loaded data. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + @param[in] SaveData A pointer pointer that will be updated with the address + of the loaded data buffer. + + @retval EFI_SUCCESS Data has been loaded successfully and SaveData is updated + with a pointer to the buffer. + @retval Others An error has occurred and no data has been loaded. SaveData + is set to NULL. + +**/ +EFI_STATUS +EFIAPI +LoadUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + OUT UNIT_TEST_SAVE_HEADER **SaveData + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + SHELL_FILE_HANDLE FileHandle; + BOOLEAN IsFileOpened; + UINT64 LargeFileSize; + UINTN FileSize; + UNIT_TEST_SAVE_HEADER *Buffer; + + IsFileOpened = FALSE; + Buffer = NULL; + + // + // Check the inputs for sanity. + // + if (FrameworkHandle == NULL || SaveData == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Determine the path for the cache file. + // NOTE: This devpath is allocated and must be freed. + // + FileDevicePath = GetCacheFileDevicePath (FrameworkHandle); + + // + // Now that we know the path to the file... let's open it for writing. + // + Status = ShellOpenFileByDevicePath ( + &FileDevicePath, + &FileHandle, + EFI_FILE_MODE_READ, + 0 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __FUNCTION__, Status)); + goto Exit; + } else { + IsFileOpened = TRUE; + } + + // + // Now that the file is opened, we need to determine how large a buffer we need. + // + Status = ShellGetFileSize (FileHandle, &LargeFileSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to determine file size! %r\n", __FUNCTION__, Status)); + goto Exit; + } + + // + // Now that we know the size, let's allocated a buffer to hold the contents. + // + FileSize = (UINTN)LargeFileSize; // You know what... if it's too large, this lib don't care. + Buffer = AllocatePool (FileSize); + if (Buffer == NULL) { + DEBUG ((DEBUG_ERROR, "%a - Failed to allocate a pool to hold the file contents! %r\n", __FUNCTION__, Status)); + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Finally, let's read the data. + // + Status = ShellReadFile (FileHandle, &FileSize, Buffer); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to read the file contents! %r\n", __FUNCTION__, Status)); + } + +Exit: + // + // Free allocated buffers + // + if (FileDevicePath != NULL) { + FreePool (FileDevicePath); + } + if (IsFileOpened) { + ShellCloseFile (&FileHandle); + } + + // + // If we're returning an error, make sure + // the state is sane. + if (EFI_ERROR (Status) && Buffer != NULL) { + FreePool (Buffer); + Buffer = NULL; + } + + *SaveData = Buffer; + return Status; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf new file mode 100644 index 00000000000..c518c4e5ce4 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf @@ -0,0 +1,47 @@ +## @file +# UEFI Simple File System based version of the Unit Test Persistence Lib +# +# Instance of the Unit Test Persistence Lib that utilizes the UEFI filesystem +# that a test application is running from to save a serialized version of the +# internal test state in case the test needs to quit and restore. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestPersistenceLibSimpleFileSystem + MODULE_UNI_FILE = UnitTestPersistenceLibSimpleFileSystem.uni + FILE_GUID = 9200844A-CDFD-4368-B4BD-106354702605 + VERSION_STRING = 1.0 + MODULE_TYPE = UEFI_APPLICATION + LIBRARY_CLASS = UnitTestPersistenceLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + UnitTestPersistenceLibSimpleFileSystem.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + DebugLib + UefiBootServicesTableLib + BaseLib + ShellLib + +[Protocols] + gEfiLoadedImageProtocolGuid + gEfiSimpleFileSystemProtocolGuid + +[Guids] + gEfiFileInfoGuid + gEfiFileSystemInfoGuid diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.uni b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.uni new file mode 100644 index 00000000000..e6593be137d --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.uni @@ -0,0 +1,15 @@ +// /** @file +// UEFI Simple File System based version of the Unit Test Persistence Lib +// +// Instance of the Unit Test Persistence Lib that utilizes the UEFI filesystem +// that a test application is running from to save a serialized version of the +// internal test state in case the test needs to quit and restore. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "UEFI Simple File System based version of the Unit Test Persistence Lib" + +#string STR_MODULE_DESCRIPTION #language en-US "UEFI Simple File System based version of the Unit Test Persistence Lib." diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c new file mode 100644 index 00000000000..687a04f55da --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c @@ -0,0 +1,216 @@ +/** @file + Implement UnitTestResultReportLib doing plain txt out to console + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include + +VOID +ReportPrint ( + IN CONST CHAR8 *Format, + ... + ); + +VOID +ReportOutput ( + IN CONST CHAR8 *Output + ); + +struct _UNIT_TEST_STATUS_STRING { + UNIT_TEST_STATUS Status; + CHAR8 *String; +}; + +struct _UNIT_TEST_FAILURE_TYPE_STRING { + FAILURE_TYPE Type; + CHAR8 *String; +}; + +struct _UNIT_TEST_STATUS_STRING mStatusStrings[] = { + { UNIT_TEST_PASSED, "PASSED"}, + { UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, "NOT RUN - PREREQUISITE FAILED"}, + { UNIT_TEST_ERROR_TEST_FAILED, "FAILED"}, + { UNIT_TEST_RUNNING, "RUNNING"}, + { UNIT_TEST_PENDING, "PENDING"}, + { 0, "**UNKNOWN**"} +}; + +struct _UNIT_TEST_FAILURE_TYPE_STRING mFailureTypeStrings[] = { + { FAILURETYPE_NOFAILURE, "NO FAILURE"}, + { FAILURETYPE_OTHER, "OTHER FAILURE"}, + { FAILURETYPE_ASSERTTRUE, "ASSERT_TRUE FAILURE"}, + { FAILURETYPE_ASSERTFALSE, "ASSERT_FALSE FAILURE"}, + { FAILURETYPE_ASSERTEQUAL, "ASSERT_EQUAL FAILURE"}, + { FAILURETYPE_ASSERTNOTEQUAL, "ASSERT_NOTEQUAL FAILURE"}, + { FAILURETYPE_ASSERTNOTEFIERROR, "ASSERT_NOTEFIERROR FAILURE"}, + { FAILURETYPE_ASSERTSTATUSEQUAL, "ASSERT_STATUSEQUAL FAILURE"}, + { FAILURETYPE_ASSERTNOTNULL , "ASSERT_NOTNULL FAILURE"}, + { 0, "*UNKNOWN* Failure"} +}; + +// +// TEST REPORTING FUNCTIONS +// + +STATIC +CONST CHAR8* +GetStringForUnitTestStatus ( + IN UNIT_TEST_STATUS Status + ) +{ + UINTN Index; + + for (Index = 0; Index < ARRAY_SIZE (mStatusStrings); Index++) { + if (mStatusStrings[Index].Status == Status) { + // + // Return string from matching entry + // + return mStatusStrings[Index].String; + } + } + // + // Return last entry if no match found. + // + return mStatusStrings[Index].String; +} + +STATIC +CONST CHAR8* +GetStringForFailureType ( + IN FAILURE_TYPE Failure + ) +{ + UINTN Index; + + for (Index = 0; Index < ARRAY_SIZE (mFailureTypeStrings); Index++) { + if (mFailureTypeStrings[Index].Type == Failure) { + // + // Return string from matching entry + // + return mFailureTypeStrings[Index].String; + } + } + // + // Return last entry if no match found. + // + DEBUG((DEBUG_INFO, "%a Failure Type does not have string defined 0x%X\n", __FUNCTION__, (UINT32)Failure)); + return mFailureTypeStrings[Index].String; +} + +/* + Method to print the Unit Test run results + + @retval Success +*/ +EFI_STATUS +EFIAPI +OutputUnitTestFrameworkReport ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + INTN Passed; + INTN Failed; + INTN NotRun; + UNIT_TEST_SUITE_LIST_ENTRY *Suite; + UNIT_TEST_LIST_ENTRY *Test; + INTN SPassed; + INTN SFailed; + INTN SNotRun; + + Passed = 0; + Failed = 0; + NotRun = 0; + Suite = NULL; + + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + if (Framework == NULL) { + return EFI_INVALID_PARAMETER; + } + + ReportPrint ("---------------------------------------------------------\n"); + ReportPrint ("------------- UNIT TEST FRAMEWORK RESULTS ---------------\n"); + ReportPrint ("---------------------------------------------------------\n"); + + //print the version and time + + // + // Iterate all suites + // + for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY*)GetFirstNode(&Framework->TestSuiteList); + (LIST_ENTRY*)Suite != &Framework->TestSuiteList; + Suite = (UNIT_TEST_SUITE_LIST_ENTRY*)GetNextNode(&Framework->TestSuiteList, (LIST_ENTRY*)Suite)) { + + Test = NULL; + SPassed = 0; + SFailed = 0; + SNotRun = 0; + + ReportPrint ("/////////////////////////////////////////////////////////\n"); + ReportPrint (" SUITE: %a\n", Suite->UTS.Title); + ReportPrint (" PACKAGE: %a\n", Suite->UTS.Name); + ReportPrint ("/////////////////////////////////////////////////////////\n"); + + // + // Iterate all tests within the suite + // + for (Test = (UNIT_TEST_LIST_ENTRY*)GetFirstNode(&(Suite->UTS.TestCaseList)); + (LIST_ENTRY*)Test != &(Suite->UTS.TestCaseList); + Test = (UNIT_TEST_LIST_ENTRY*)GetNextNode(&(Suite->UTS.TestCaseList), (LIST_ENTRY*)Test)) { + + ReportPrint ("*********************************************************\n"); + ReportPrint (" CLASS NAME: %a\n", Test->UT.Name); + ReportPrint (" TEST: %a\n", Test->UT.Description); + ReportPrint (" STATUS: %a\n", GetStringForUnitTestStatus (Test->UT.Result)); + ReportPrint (" FAILURE: %a\n", GetStringForFailureType (Test->UT.FailureType)); + ReportPrint (" FAILURE MESSAGE:\n%a\n", Test->UT.FailureMessage); + + if (Test->UT.Log != NULL) { + ReportPrint (" LOG:\n"); + ReportOutput (Test->UT.Log); + } + + switch (Test->UT.Result) { + case UNIT_TEST_PASSED: + SPassed++; + break; + case UNIT_TEST_ERROR_TEST_FAILED: + SFailed++; + break; + case UNIT_TEST_PENDING: // Fall through... + case UNIT_TEST_RUNNING: // Fall through... + case UNIT_TEST_ERROR_PREREQUISITE_NOT_MET: + SNotRun++; + break; + default: + break; + } + ReportPrint ("**********************************************************\n"); + } //End Test iteration + + ReportPrint ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + ReportPrint ("Suite Stats\n"); + ReportPrint (" Passed: %d (%d%%)\n", SPassed, (SPassed * 100)/(SPassed+SFailed+SNotRun)); + ReportPrint (" Failed: %d (%d%%)\n", SFailed, (SFailed * 100) / (SPassed + SFailed + SNotRun)); + ReportPrint (" Not Run: %d (%d%%)\n", SNotRun, (SNotRun * 100) / (SPassed + SFailed + SNotRun)); + ReportPrint ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" ); + + Passed += SPassed; //add to global counters + Failed += SFailed; //add to global counters + NotRun += SNotRun; //add to global counters + }//End Suite iteration + + ReportPrint ("=========================================================\n"); + ReportPrint ("Total Stats\n"); + ReportPrint (" Passed: %d (%d%%)\n", Passed, (Passed * 100) / (Passed + Failed + NotRun)); + ReportPrint (" Failed: %d (%d%%)\n", Failed, (Failed * 100) / (Passed + Failed + NotRun)); + ReportPrint (" Not Run: %d (%d%%)\n", NotRun, (NotRun * 100) / (Passed + Failed + NotRun)); + ReportPrint ("=========================================================\n" ); + + return EFI_SUCCESS; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.c b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.c new file mode 100644 index 00000000000..139360ee165 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.c @@ -0,0 +1,48 @@ +/** @file + Implement UnitTestResultReportLib doing plain txt out to console + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include + +VOID +ReportPrint ( + IN CONST CHAR8 *Format, + ... + ) +{ + VA_LIST Marker; + CHAR16 String[256]; + UINTN Length; + + VA_START (Marker, Format); + Length = UnicodeVSPrintAsciiFormat (String, sizeof (String), Format, Marker); + if (Length == 0) { + DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__)); + } else { + gST->ConOut->OutputString (gST->ConOut, String); + } + VA_END (Marker); +} + +VOID +ReportOutput ( + IN CONST CHAR8 *Output + ) +{ + CHAR8 AsciiString[128]; + UINTN Length; + UINTN Index; + + Length = AsciiStrLen (Output); + for (Index = 0; Index < Length; Index += (sizeof (AsciiString) - 1)) { + AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]); + ReportPrint ("%a", AsciiString); + } +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf new file mode 100644 index 00000000000..4382199fbc7 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf @@ -0,0 +1,29 @@ +## @file +# Library to support printing out the unit test report to a UEFI console +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestResultReportLibConOut + MODULE_UNI_FILE = UnitTestResultReportLibConOut.uni + FILE_GUID = C659641D-BA1F-4B58-946E-B1E1103903F9 + VERSION_STRING = 1.0 + MODULE_TYPE = UEFI_DRIVER + LIBRARY_CLASS = UnitTestResultReportLib + +[LibraryClasses] + BaseLib + DebugLib + UefiBootServicesTableLib + PrintLib + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[Sources] + UnitTestResultReportLib.c + UnitTestResultReportLibConOut.c diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.uni b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.uni new file mode 100644 index 00000000000..92ba1b84da3 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.uni @@ -0,0 +1,11 @@ +// /** @file +// Library to support printing out the unit test report to a UEFI console +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to support printing out the unit test report to a UEFI console" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to support printing out the unit test report to a UEFI console." diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.c b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.c new file mode 100644 index 00000000000..743aad2958a --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.c @@ -0,0 +1,47 @@ +/** @file + Implement UnitTestResultReportLib doing plain txt out to console + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include + +VOID +ReportPrint ( + IN CONST CHAR8 *Format, + ... + ) +{ + VA_LIST Marker; + CHAR8 String[256]; + UINTN Length; + + VA_START (Marker, Format); + Length = AsciiVSPrint (String, sizeof (String), Format, Marker); + if (Length == 0) { + DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__)); + } else { + DEBUG ((DEBUG_INFO, String)); + } + VA_END (Marker); +} + +VOID +ReportOutput ( + IN CONST CHAR8 *Output + ) +{ + CHAR8 AsciiString[128]; + UINTN Length; + UINTN Index; + + Length = AsciiStrLen (Output); + for (Index = 0; Index < Length; Index += (sizeof (AsciiString) - 1)) { + AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]); + DEBUG ((DEBUG_INFO, AsciiString)); + } +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf new file mode 100644 index 00000000000..a1c786a700e --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf @@ -0,0 +1,28 @@ +## @file +# Library to support printing out the unit test report using DEBUG() macros. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = UnitTestResultReportLibDebugLib + MODULE_UNI_FILE = UnitTestResultReportLibDebugLib.uni + FILE_GUID = BED736D4-D197-475F-B7CE-0D828FF2C9A6 + VERSION_STRING = 1.0 + MODULE_TYPE = UEFI_DRIVER + LIBRARY_CLASS = UnitTestResultReportLib + +[LibraryClasses] + BaseLib + DebugLib + PrintLib + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[Sources] + UnitTestResultReportLib.c + UnitTestResultReportLibDebugLib.c diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.uni b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.uni new file mode 100644 index 00000000000..4f1993417ad --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.uni @@ -0,0 +1,11 @@ +// /** @file +// Library to support printing out the unit test report using DEBUG() macros. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to support printing out the unit test report using DEBUG() macros" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to support printing out the unit test report using DEBUG() macros." diff --git a/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestBootLib.h b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestBootLib.h new file mode 100644 index 00000000000..d90bff0e4c1 --- /dev/null +++ b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestBootLib.h @@ -0,0 +1,31 @@ +/** @file + Provides a library function that can be customized to set the platform to boot + from USB on the next boot. This allows the test framework to reboot back to + USB. Since boot managers are not all the same creating a lib to support + platform customization will make porting to new code base/platform easier. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __UNIT_TEST_BOOT_LIB_H__ +#define __UNIT_TEST_BOOT_LIB_H__ + +/** + Set the boot manager to boot from a specific device on the next boot. This + should be set only for the next boot and shouldn't require any manual clean up + + @retval EFI_SUCCESS Boot device for next boot was set. + @retval EFI_UNSUPPORTED Setting the boot device for the next boot is not + supportted. + @retval Other Boot device for next boot can not be set. +**/ +EFI_STATUS +EFIAPI +SetBootNextDevice ( + VOID + ); + +#endif diff --git a/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestPersistenceLib.h b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestPersistenceLib.h new file mode 100644 index 00000000000..af19ba8f539 --- /dev/null +++ b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestPersistenceLib.h @@ -0,0 +1,76 @@ +/** @file + This header file describes a library that contains functions to save and + restore unit test internal state, in case the test needs to pause and resume + (eg. a reboot-based test). + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UNIT_TEST_PERSISTENCE_LIB_H_ +#define _UNIT_TEST_PERSISTENCE_LIB_H_ + +#include + +#define UNIT_TEST_PERSISTENCE_LIB_VERSION 1 + +/** + Determines whether a persistence cache already exists for + the given framework. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + + @retval TRUE + @retval FALSE Cache doesn't exist or an error occurred. + +**/ +BOOLEAN +EFIAPI +DoesCacheExist ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ); + +/** + Will save the data associated with an internal Unit Test Framework + state in a manner that can persist a Unit Test Application quit or + even a system reboot. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + @param[in] SaveData A pointer to the buffer containing the serialized + framework internal state. + + @retval EFI_SUCCESS Data is persisted and the test can be safely quit. + @retval Others Data is not persisted and test cannot be resumed upon exit. + +**/ +EFI_STATUS +EFIAPI +SaveUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_SAVE_HEADER *SaveData + ); + +/** + Will retrieve any cached state associated with the given framework. + Will allocate a buffer to hold the loaded data. + + @param[in] FrameworkHandle A pointer to the framework that is being persisted. + @param[in] SaveData A pointer pointer that will be updated with the address + of the loaded data buffer. + + @retval EFI_SUCCESS Data has been loaded successfully and SaveData is updated + with a pointer to the buffer. + @retval Others An error has occurred and no data has been loaded. SaveData + is set to NULL. + +**/ +EFI_STATUS +EFIAPI +LoadUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + OUT UNIT_TEST_SAVE_HEADER **SaveData + ); + +#endif diff --git a/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestResultReportLib.h b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestResultReportLib.h new file mode 100644 index 00000000000..a417f490dc9 --- /dev/null +++ b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestResultReportLib.h @@ -0,0 +1,27 @@ +/** @file + Provides a unit test result report. This allows new result output formats to + be easily customized. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __UNIT_TEST_RESULT_REPORT_LIB_H__ +#define __UNIT_TEST_RESULT_REPORT_LIB_H__ + +#include + +/** +Method to produce the Unit Test run results + +@retval Success +**/ +EFI_STATUS +EFIAPI +OutputUnitTestFrameworkReport ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ); + +#endif diff --git a/UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h b/UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h new file mode 100644 index 00000000000..e58b30093e4 --- /dev/null +++ b/UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h @@ -0,0 +1,183 @@ +/** @file + Provides the basic types and common elements of the unit test framework + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __UNIT_TEST_TYPES_H__ +#define __UNIT_TEST_TYPES_H__ + +#include + +/// +/// The maximum length of a string stored in the unit test framework +/// +#define UNIT_TEST_MAX_STRING_LENGTH (120) + +/// +/// The size of a firngerprint used to save/resume execution of a unit test +/// framework. This is the size of a CRC32 value which is 32-bit value. +/// +/// +#define UNIT_TEST_FINGERPRINT_SIZE (sizeof (UINT32)) + +/// +/// The maximum length of a test failure message stored in the unit test +/// framework +/// +#define UNIT_TEST_TESTFAILUREMSG_LENGTH (120) + +/// +/// FAILURE_TYPE used to record the type of assert that was triggered by a unit +/// test. +/// +typedef UINT32 FAILURE_TYPE; +#define FAILURETYPE_NOFAILURE (0) +#define FAILURETYPE_OTHER (1) +#define FAILURETYPE_ASSERTTRUE (2) +#define FAILURETYPE_ASSERTFALSE (3) +#define FAILURETYPE_ASSERTEQUAL (4) +#define FAILURETYPE_ASSERTNOTEQUAL (5) +#define FAILURETYPE_ASSERTNOTEFIERROR (6) +#define FAILURETYPE_ASSERTSTATUSEQUAL (7) +#define FAILURETYPE_ASSERTNOTNULL (8) + +/// +/// Unit Test context structure tracked by the unit test framework. +/// +typedef struct { + CHAR8 *Description; + CHAR8 *Name; //can't have spaces and should be short + CHAR8 *Log; + FAILURE_TYPE FailureType; + CHAR8 FailureMessage[UNIT_TEST_TESTFAILUREMSG_LENGTH]; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; + UNIT_TEST_STATUS Result; + UNIT_TEST_FUNCTION RunTest; + UNIT_TEST_PREREQUISITE Prerequisite; + UNIT_TEST_CLEANUP CleanUp; + UNIT_TEST_CONTEXT Context; + UNIT_TEST_SUITE_HANDLE ParentSuite; +} UNIT_TEST; + +/// +/// Structure used to store the set of unit tests in a unit test suite as a list. +/// +typedef struct { + LIST_ENTRY Entry; + UNIT_TEST UT; +} UNIT_TEST_LIST_ENTRY; + +/// +/// Unit Test Suite context structure tracked by the unit test framework. +/// +typedef struct { + UINTN NumTests; + CHAR8 *Title; + CHAR8 *Name; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; + UNIT_TEST_SUITE_SETUP Setup; + UNIT_TEST_SUITE_TEARDOWN Teardown; + LIST_ENTRY TestCaseList; // UNIT_TEST_LIST_ENTRY + UNIT_TEST_FRAMEWORK_HANDLE ParentFramework; +} UNIT_TEST_SUITE; + +/// +/// Structure used to store the set of unit test suites in a unit test framework +/// as a list. +/// +typedef struct { + LIST_ENTRY Entry; + UNIT_TEST_SUITE UTS; +} UNIT_TEST_SUITE_LIST_ENTRY; + +/// +/// Unit Test Framework context structure tracked by the unit test framework. +/// +typedef struct { + CHAR8 *Title; + CHAR8 *ShortTitle; // This title should contain NO spaces or non-filename characters. Is used in reporting and serialization. + CHAR8 *VersionString; + CHAR8 *Log; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; + LIST_ENTRY TestSuiteList; // UNIT_TEST_SUITE_LIST_ENTRY + EFI_TIME StartTime; + EFI_TIME EndTime; + UNIT_TEST *CurrentTest; + VOID *SavedState; // This is an instance of UNIT_TEST_SAVE_HEADER*, if present. +} UNIT_TEST_FRAMEWORK; + +/// +/// Serialized version of a unit test +/// +typedef struct { + UINT32 Size; // Size of the UNIT_TEST_SAVE_TEST including Log[] + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; // Fingerprint of the test itself. + CHAR8 FailureMessage[UNIT_TEST_TESTFAILUREMSG_LENGTH]; + FAILURE_TYPE FailureType; + UNIT_TEST_STATUS Result; + CHAR8 Log[]; +} UNIT_TEST_SAVE_TEST; + +/// +/// Serialized version of a unit test context +/// +typedef struct { + UINT32 Size; // Size of the UNIT_TEST_SAVE_CONTEXT including Data[] + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; // Fingerprint of the corresponding test. + UINT8 Data[]; // Actual data of the context. +} UNIT_TEST_SAVE_CONTEXT; + +/// +/// Serialized version of unit test framework +/// +typedef struct { + UINT8 Version; + UINT32 SaveStateSize; // Size of the entire serialized buffer. + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; // Fingerprint of the framework that has been saved. + EFI_TIME StartTime; + UINT32 TestCount; + BOOLEAN HasSavedContext; + // UNIT_TEST_SAVE_TEST Tests[]; // Array of structures starts here. + // UNIT_TEST_SAVE_CONTEXT SavedContext[]; // Saved context for the currently running test. + // CHAR8 Log[]; // NOTE: Not yet implemented!! +} UNIT_TEST_SAVE_HEADER; + +/** + This function is responsible for initializing the log buffer for a single test. It can + be used internally, but may also be consumed by the test framework to add pre-existing + data to a log before it's used. + + @param[in,out] TestHandle A handle to the test being initialized. + @param[in] Buffer [Optional] A pointer to pre-existing log data that should + be used to initialize the log. Should include a NULL terminator. + @param[in] BufferSize [Optional] The size of the pre-existing log data. + +**/ +VOID +EFIAPI +UnitTestLogInit ( + IN OUT UNIT_TEST *Test, + IN UINT8 *Buffer OPTIONAL, + IN UINTN BufferSize OPTIONAL + ); + +/** + Internal helper function to return a handle to the currently executing framework. + This function is generally used for communication within the UnitTest framework, but is + defined here so that it can be consumed by the Assertion and Logging macros. + + There should be no need to consume as a test writer, but it's there if you need it. + + @retval Handle to the currently executing test framework. + +**/ +UNIT_TEST_FRAMEWORK_HANDLE +GetActiveFrameworkHandle ( + VOID + ); + +#endif diff --git a/UnitTestFrameworkPkg/ReadMe.md b/UnitTestFrameworkPkg/ReadMe.md new file mode 100644 index 00000000000..7296f0a45c5 --- /dev/null +++ b/UnitTestFrameworkPkg/ReadMe.md @@ -0,0 +1,257 @@ +# Unit Test Framework Package + +## About + +This package adds a unit test framework capable of building tests for multiple contexts including +the UEFI shell environment and host-based environments. It allows for unit test development to focus +on the tests and leave error logging, result formatting, context persistance, and test running to the framework. +The unit test framework works well for low level unit tests as well as system level tests and +fits easily in automation frameworks. + +### UnitTestLib + +The main "framework" library. The core of the framework is the Framework object, which can have any number +of test cases and test suites registered with it. The Framework object is also what drives test execution. + +The Framework also provides helper macros and functions for checking test conditions and +reporting errors. Status and error info will be logged into the test context. There are a number +of Assert macros that make the unit test code friendly to view and easy to understand. + +Finally, the Framework also supports logging strings during the test execution. This data is logged +to the test context and will be available in the test reporting phase. This should be used for +logging test details and helpful messages to resolve test failures. + +### UnitTestPersistenceLib + +Persistence lib has the main job of saving and restoring test context to a storage medium so that for tests +that require exiting the active process and then resuming state can be maintained. This is critical +in supporting a system reboot in the middle of a test run. + +### UnitTestResultReportLib + +Library provides function to run at the end of a framework test run and handles formatting the report. +This is a common customization point and allows the unit test framework to fit its output reports into +other test infrastructure. In this package a simple library instances has been supplied to output test +results to the console as plain text. + +## Samples + +There is a sample unit test provided as both an example of how to write a unit test and leverage +many of the features of the framework. This sample can be found in the `Test/UnitTest/Sample/SampleUnitTest` +directory. + +The sample is provided in PEI, SMM, DXE, and UEFI App flavors. It also has a flavor for the HOST_APPLICATION +build type, which can be run on a host system without needing a target. + +## Usage + +This section is built a lot like a "Getting Started". We'll go through some of the components that are needed +when constructing a unit test and some of the decisions that are made by the test writer. We'll also describe +how to check for expected conditions in test cases and a bit of the logging characteristics. + +Most of these examples will refer to the SampleUnitTestUefiShell app found in this package. + +### Requirements - INF + +In our INF file, we'll need to bring in the `UnitTestLib` library. Conveniently, the interface +header for the `UnitTestLib` is located in `MdePkg`, so you shouldn't need to depend on any other +packages. As long as your DSC file knows where to find the lib implementation that you want to use, +you should be good to go. + +See this example in 'SampleUnitTestApp.inf'... + +``` +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib +``` + +### Requirements - Code + +Not to state the obvious, but let's make sure we have the following include before getting too far along... + +```c +#include +``` + +Now that we've got that squared away, let's look at our 'Main()'' routine (or DriverEntryPoint() or whatever). + +### Configuring the Framework + +Everything in the UnitTestPkg framework is built around an object called -- conveniently -- the Framework. +This Framework object will contain all the information about our test, the test suites and test cases associated +with it, the current location within the test pass, and any results that have been recorded so far. + +To get started with a test, we must first create a Framework instance. The function for this is +`InitUnitTestFramework`. It takes in `CHAR8` strings for the long name, short name, and test version. +The long name and version strings are just for user presentation and relatively flexible. The short name +will be used to name any cache files and/or test results, so should be a name that makes sense in that context. +These strings are copied internally to the Framework, so using stack-allocated or literal strings is fine. + +In the 'SampleUnitTestUefiShell' app, the module name is used as the short name, so the init looks like this. + +```c +DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION )); + +// +// Start setting up the test framework for running the tests. +// +Status = InitUnitTestFramework( &Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION ); +``` + +The `&Framework` returned here is the handle to the Framework. If it's successfully returned, we can start adding +test suites and test cases. + +Test suites exist purely to help organize test cases and to differentiate the results in reports. If you're writing +a small unit test, you can conceivably put all test cases into a single suite. However, if you end up with 20+ test +cases, it may be beneficial to organize them according to purpose. You _must_ have at least one test suite, even if +it's just a catch-all. The function to create a test suite is `CreateUnitTestSuite`. It takes in a handle to +the Framework object, a `CHAR8` string for the suite title and package name, and optional function pointers for +a setup function and a teardown function. + +The suite title is for user presentation. The package name is for xUnit type reporting and uses a '.'-separated +hierarchical format (see 'SampleUnitTestApp' for example). If provided, the setup and teardown functions will be +called once at the start of the suite (before _any_ tests have run) and once at the end of the suite (after _all_ +tests have run), respectively. If either or both of these are unneeded, pass `NULL`. The function prototypes are +`UNIT_TEST_SUITE_SETUP` and `UNIT_TEST_SUITE_TEARDOWN`. + +Looking at 'SampleUnitTestUefiShell' app, you can see that the first test suite is created as below... + +```c +// +// Populate the SimpleMathTests Unit Test Suite. +// +Status = CreateUnitTestSuite( &SimpleMathTests, Fw, "Simple Math Tests", "Sample.Math", NULL, NULL ); +``` + +This test suite has no setup or teardown functions. The `&SimpleMathTests` returned here is a handle to the suite and +will be used when adding test cases. + +Great! Now we've finished some of the cruft, red tape, and busy work. We're ready to add some tests. Adding a test +to a test suite is accomplished with the -- you guessed it -- `AddTestCase` function. It takes in the suite handle; +a `CHAR8` string for the description and class name; a function pointer for the test case itself; additional, optional +function pointers for prerequisite check and cleanup routines; and and optional pointer to a context structure. + +Okay, that's a lot. Let's take it one piece at a time. The description and class name strings are very similar in +usage to the suite title and package name strings in the test suites. The former is for user presentation and the +latter is for xUnit parsing. The test case function pointer is what is actually executed as the "test" and the +prototype should be `UNIT_TEST_FUNCTION`. The last three parameters require a little bit more explaining. + +The prerequisite check function has a prototype of `UNIT_TEST_PREREQUISITE` and -- if provided -- will be called +immediately before the test case. If this function returns any error, the test case will not be run and will be +recorded as `UNIT_TEST_ERROR_PREREQUISITE_NOT_MET`. The cleanup function (prototype `UNIT_TEST_CLEANUP`) will be called +immediately after the test case to provide an opportunity to reset any global state that may have been changed in the +test case. In the event of a prerequisite failure, the cleanup function will also be skipped. If either of these +functions is not needed, pass `NULL`. + +The context pointer is entirely case-specific. It will be passed to the test case upon execution. One of the purposes +of the context pointer is to allow test case reuse with different input data. (Another use is for testing that wraps +around a system reboot, but that's beyond the scope of this guide.) The test case must know how to interpret the context +pointer, so it could be a simple value, or it could be a complex structure. If unneeded, pass `NULL`. + +In 'SampleUnitTestUefiShell' app, the first test case is added using the code below... + +```c +AddTestCase( SimpleMathTests, "Adding 1 to 1 should produce 2", "Addition", OnePlusOneShouldEqualTwo, NULL, NULL, NULL ); +``` + +This test case calls the function `OnePlusOneShouldEqualTwo` and has no prerequisite, cleanup, or context. + +Once all the suites and cases are added, it's time to run the Framework. + +```c +// +// Execute the tests. +// +Status = RunAllTestSuites( Framework ); +``` + +### A Simple Test Case + +We'll take a look at the below test case from 'SampleUnitTestApp'... + +```c +UNIT_TEST_STATUS +EFIAPI +OnePlusOneShouldEqualTwo ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UNIT_TEST_CONTEXT Context + ) +{ + UINTN A, B, C; + + A = 1; + B = 1; + C = A + B; + + UT_ASSERT_EQUAL(C, 2); + return UNIT_TEST_PASSED; +} // OnePlusOneShouldEqualTwo() +``` + +The prototype for this function matches the `UNIT_TEST_FUNCTION` prototype. It takes in a handle to the Framework +itself and the context pointer. The context pointer could be cast and interpreted as anything within this test case, +which is why it's important to configure contexts carefully. The test case returns a value of `UNIT_TEST_STATUS`, which +will be recorded in the Framework and reported at the end of all suites. + +In this test case, the `UT_ASSERT_EQUAL` assertion is being used to establish that the business logic has functioned +correctly. There are several assertion macros, and you are encouraged to use one that matches as closely to your +intended test criterium as possible, because the logging is specific to the macro and more specific macros have more +detailed logs. When in doubt, there are always `UT_ASSERT_TRUE` and `UT_ASSERT_FALSE`. Assertion macros that fail their +test criterium will immediately return from the test case with `UNIT_TEST_ERROR_TEST_FAILED` and log an error string. +_Note_ that this early return can have implications for memory leakage. + +At the end, if all test criteria pass, you should return `UNIT_TEST_PASSED`. + +### More Complex Cases + +To write more advanced tests, first take a look at all the Assertion and Logging macros provided in the framework. + +Beyond that, if you're writing host-based tests and want to take a dependency on the UnitTestFrameworkPkg, you can +leverage the `cmocka.h` interface and write tests with all the features of the Cmocka framework. + +Documentation for Cmocka can be found here: +https://api.cmocka.org/ + +## Development + +When using the EDK2 Pytools for CI testing, the host-based unit tests will be built and run on any build that includes the `NOOPT` build target. + +If you are trying to iterate on a single test, a convenient pattern is to build only that test module. For example, the following command will build only the SafeIntLib host-based test from the MdePkg... + +```bash +stuart_ci_build -c .pytool/CISettings.py TOOL_CHAIN_TAG=VS2017 -p MdePkg -t NOOPT BUILDMODULE=MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.inf +``` + +## Known Limitations + +### PEI, DXE, SMM + +While sample tests have been provided for these execution environments, only cursory build validation +has been performed. Care has been taken while designing the frameworks to allow for execution during +boot phases, but only UEFI Shell and host-based tests have been thoroughly evaluated. Full support for +PEI, DXE, and SMM is forthcoming, but should be considered beta/staging for now. + +### Host-Based Support vs Other Tests + +The host-based test framework is powered internally by the Cmocka framework. As such, it has abilities +that the target-based tests don't (yet). It would be awesome if this meant that it was a super set of +the target-based tests, and it worked just like the target-based tests but with more features. Unfortunately, +this is not the case. While care has been taken to keep them as close a possible, there are a few known +inconsistencies that we're still ironing out. For example, the logging messages in the target-based tests +are cached internally and associated with the running test case. They can be saved later as part of the +reporting lib. This isn't currently possible with host-based. Only the assertion failures are logged. + +We will continue trying to make these as similar as possible. + +## Copyright + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTest.c b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTest.c new file mode 100644 index 00000000000..63017f1abe2 --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTest.c @@ -0,0 +1,289 @@ +/** @file + This is a sample to demostrate the usage of the Unit Test Library that + supports the PEI, DXE, SMM, UEFI SHell, and host execution environments. + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include +#include + +#define UNIT_TEST_NAME "Sample Unit Test" +#define UNIT_TEST_VERSION "0.1" + +/// +/// Global variables used in unit tests +/// +BOOLEAN mSampleGlobalTestBoolean = FALSE; +VOID *mSampleGlobalTestPointer = NULL; + +/** + Sample Unit-Test Prerequisite Function that checks to make sure the global + pointer used in the test is already set to NULL. + + Funtions with this prototype are registered to be dispatched by the unit test + framework prior to a given test case. If this prereq function returns + UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, the test case will be skipped. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED Unit test case prerequisites + are met. + @retval UNIT_TEST_ERROR_PREREQUISITE_NOT_MET Test case should be skipped. + +**/ +UNIT_TEST_STATUS +EFIAPI +MakeSureThatPointerIsNull ( + IN UNIT_TEST_CONTEXT Context + ) +{ + UT_ASSERT_EQUAL ((UINTN)mSampleGlobalTestPointer, (UINTN)NULL); + return UNIT_TEST_PASSED; +} + +/** + Sample Unit-Test Cleanup (after) function that resets the global pointer to + NULL. + + Funtions with this prototype are registered to be dispatched by the + unit test framework after a given test case. This will be called even if the + test case returns an error, but not if the prerequisite fails and the test is + skipped. The purpose of this function is to clean up any global state or + test data. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED Test case cleanup succeeded. + @retval UNIT_TEST_ERROR_CLEANUP_FAILED Test case cleanup failed. + +**/ +VOID +EFIAPI +ClearThePointer ( + IN UNIT_TEST_CONTEXT Context + ) +{ + mSampleGlobalTestPointer = NULL; +} + +/** + Sample unit test that verifies the expected result of an unsigned integer + addition operation. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +OnePlusOneShouldEqualTwo ( + IN UNIT_TEST_CONTEXT Context + ) +{ + UINTN A; + UINTN B; + UINTN C; + + A = 1; + B = 1; + C = A + B; + + UT_ASSERT_EQUAL (C, 2); + + return UNIT_TEST_PASSED; +} + +/** + Sample unit test that verifies that a global BOOLEAN is updatable. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +GlobalBooleanShouldBeChangeable ( + IN UNIT_TEST_CONTEXT Context + ) +{ + mSampleGlobalTestBoolean = TRUE; + UT_ASSERT_TRUE (mSampleGlobalTestBoolean); + + mSampleGlobalTestBoolean = FALSE; + UT_ASSERT_FALSE (mSampleGlobalTestBoolean); + + return UNIT_TEST_PASSED; +} + +/** + Sample unit test that logs a warning message and verifies that a global + pointer is updatable. + + @param[in] Context [Optional] An optional paramter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that the + contents are well understood by all test cases that may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +GlobalPointerShouldBeChangeable ( + IN UNIT_TEST_CONTEXT Context + ) +{ + // + // Example of logging. + // + UT_LOG_WARNING ("About to change a global pointer! Current value is 0x%X\n", mSampleGlobalTestPointer); + + mSampleGlobalTestPointer = (VOID *)-1; + UT_ASSERT_EQUAL ((UINTN)mSampleGlobalTestPointer, (UINTN)((VOID *)-1)); + return UNIT_TEST_PASSED; +} + +/** + Initialize the unit test framework, suite, and unit tests for the + sample unit tests and run the unit tests. + + @retval EFI_SUCCESS All test cases were dispached. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + initialize the unit tests. +**/ +EFI_STATUS +EFIAPI +UefiTestMain ( + VOID + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework; + UNIT_TEST_SUITE_HANDLE SimpleMathTests; + UNIT_TEST_SUITE_HANDLE GlobalVarTests; + + Framework = NULL; + + DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION )); + + // + // Start setting up the test framework for running the tests. + // + Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status)); + goto EXIT; + } + + // + // Populate the SimpleMathTests Unit Test Suite. + // + Status = CreateUnitTestSuite (&SimpleMathTests, Framework, "Simple Math Tests", "Sample.Math", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for SimpleMathTests\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase (SimpleMathTests, "Adding 1 to 1 should produce 2", "Addition", OnePlusOneShouldEqualTwo, NULL, NULL, NULL); + + // + // Populate the GlobalVarTests Unit Test Suite. + // + Status = CreateUnitTestSuite (&GlobalVarTests, Framework, "Global Variable Tests", "Sample.Globals", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for GlobalVarTests\n")); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase (GlobalVarTests, "You should be able to change a global BOOLEAN", "Boolean", GlobalBooleanShouldBeChangeable, NULL, NULL, NULL); + AddTestCase (GlobalVarTests, "You should be able to change a global pointer", "Pointer", GlobalPointerShouldBeChangeable, MakeSureThatPointerIsNull, ClearThePointer, NULL); + + // + // Execute the tests. + // + Status = RunAllTestSuites (Framework); + +EXIT: + if (Framework) { + FreeUnitTestFramework (Framework); + } + + return Status; +} + +/** + Standard PEIM entry point for target based unit test execution from PEI. +**/ +EFI_STATUS +EFIAPI +PeiEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + return UefiTestMain (); +} + +/** + Standard UEFI entry point for target based unit test execution from DXE, SMM, + UEFI Shell. +**/ +EFI_STATUS +EFIAPI +DxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return UefiTestMain (); +} + +/** + Standard POSIX C entry point for host based unit test execution. +**/ +int +main ( + int argc, + char *argv[] + ) +{ + return UefiTestMain (); +} diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestDxe.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestDxe.inf new file mode 100644 index 00000000000..e253cf6e16d --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestDxe.inf @@ -0,0 +1,36 @@ +## @file +# Sample UnitTest built for execution in DXE. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = SampleUnitTestDxe + FILE_GUID = 96BB18BD-FF2B-4B51-B683-0DC9A4BF12CF + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib + +[Depex] + TRUE diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestHost.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestHost.inf new file mode 100644 index 00000000000..59a367cc6ed --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestHost.inf @@ -0,0 +1,30 @@ +## @file +# Sample UnitTest built for execution on a Host/Dev machine. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SampleUnitTestHost + FILE_GUID = CC0EA77E-BF2D-4134-B419-0C02E15CE08E + MODULE_TYPE = HOST_APPLICATION + VERSION_STRING = 1.0 + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + UnitTestLib diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestPei.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestPei.inf new file mode 100644 index 00000000000..60f5252c343 --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestPei.inf @@ -0,0 +1,36 @@ +## @file +# Sample UnitTest built for execution in PEI. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = SampleUnitTestPei + FILE_GUID = B9BD9451-3DC8-48EA-A6F0-55753BF186F1 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeiEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + PeimEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestSmm.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestSmm.inf new file mode 100644 index 00000000000..324ad2686e6 --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestSmm.inf @@ -0,0 +1,37 @@ +## @file +# Sample UnitTest built for execution in SMM. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = SampleUnitTestSmm + FILE_GUID = 389B16DB-F622-424C-9000-9E43C69CBF71 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = DxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib + +[Depex] + gEfiSmmCpuProtocolGuid diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestUefiShell.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestUefiShell.inf new file mode 100644 index 00000000000..6e39c229d4d --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestUefiShell.inf @@ -0,0 +1,33 @@ +## @file +# Sample UnitTest built for execution in UEFI Shell. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = SampleUnitTestUefiShell + FILE_GUID = 9E8F461A-17E1-4312-B49C-E66F0A88EA8B + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = DxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib diff --git a/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc b/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc new file mode 100644 index 00000000000..701e7299d76 --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc @@ -0,0 +1,33 @@ +## @file +# UnitTestFrameworkPkg DSC file used to build host-based unit tests. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME = UnitTestFrameworkPkgHostTest + PLATFORM_GUID = C7F97D6D-54AC-45A9-8197-CC99B20CC7EC + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/UnitTestFrameworkPkg/HostTest + SUPPORTED_ARCHITECTURES = IA32|X64 + BUILD_TARGETS = NOOPT + SKUID_IDENTIFIER = DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc + +[Components] + # + # Build HOST_APPLICATION that tests the SampleUnitTest + # + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestHost.inf + + # + # Build Libraries + # + UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf + UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf + UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf + UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml new file mode 100644 index 00000000000..01648595055 --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml @@ -0,0 +1,76 @@ +## @file +# CI configuration for UnitTestFrameworkPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + ## options defined .pytool/Plugin/CompilerPlugin + "CompilerPlugin": { + "DscPath": "UnitTestFrameworkPkg.dsc" + }, + ## options defined .pytool/Plugin/HostUnitTestCompilerPlugin + "HostUnitTestCompilerPlugin": { + "DscPath": "Test/UnitTestFrameworkPkgHostTest.dsc" + }, + ## options defined .pytool/Plugin/CharEncodingCheck + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + + ## options defined .pytool/Plugin/DependencyCheck + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[ + "MdeModulePkg/MdeModulePkg.dec", + "ShellPkg/ShellPkg.dec" + ], + "IgnoreInf": [] + }, + ## options defined .pytool/Plugin/DscCompleteCheck + "DscCompleteCheck": { + "DscPath": "UnitTestFrameworkPkg.dsc", + "IgnoreInf": [] + }, + ## options defined .pytool/Plugin/HostUnitTestDscCompleteCheck + "HostUnitTestDscCompleteCheck": { + "IgnoreInf": [], + "DscPath": "Test/UnitTestFrameworkPkgHostTest.dsc" + }, + ## options defined .pytool/Plugin/GuidCheck + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [] + }, + ## options defined .pytool/Plugin/LibraryClassCheck + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined .pytool/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": False, # Fails test but run in AuditOnly mode to collect log + "IgnoreFiles": [ # use gitignore syntax to ignore errors in matching files + "/Library/CmockaLib/cmocka/**/*.*" # not going to spell check a submodule + ], + "ExtendWords": [ # words to extend to the dictionary for this package + "cmocka", + "buildmodule", + "criterium", + "pytool", + "pytools", + "NOFAILURE", + "DHAVE" # build flag for cmocka in the INF + ], + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) + } +} diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec new file mode 100644 index 00000000000..069289f0096 --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec @@ -0,0 +1,50 @@ +## @file +# This Package provides all definitions (including functions, MACROs, +# structures library classes, and PCDs) and libraries instances, which are used +# to support unit testing and interface testing. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = UnitTestFrameworkPkg + PACKAGE_UNI_FILE = UnitTestFrameworkPkg.uni + PACKAGE_GUID = 4A70C4A0-D72C-4D3F-9943-BE7C41C50BA3 + PACKAGE_VERSION = 1.00 + +[Includes] + Library/CmockaLib/cmocka/include + +[Includes.Common.Private] + PrivateInclude + Library/CmockaLib/cmocka/include/cmockery + +[LibraryClasses.Common.Private] + ## @libraryclass Allows save and restore unit test internal state + # + UnitTestPersistenceLib|PrivateInclude/Library/UnitTestPersistenceLib.h + + ## @libraryclass Provides a unit test result report + # + UnitTestResultReportLib|PrivateInclude/Library/UnitTestResultReportLib.h + + ## @libraryclass Provides boot-option routines useful in shell-based tests. + # + UnitTestBootLib|PrivateInclude/Library/UnitTestBootLib.h + +[Guids] + gUnitTestFrameworkPkgTokenSpaceGuid = { 0x833d3aba, 0x39b4, 0x43a2, { 0xb9, 0x30, 0x7a, 0x34, 0x53, 0x39, 0x31, 0xb3 } } + +[PcdsFixedAtBuild] + ## This flag is used to control build time optimization based on unit test + # log level. The default value is 0xFFFFFFFF to enable all unit test log + # messages. + # BIT0 - Error unit test log messages.
+ # BIT1 - Warning unit test log messages.
+ # BIT2 - Informational unit test log messages.
+ # BIT3 - Verbose unit test log messages.
+ # @Prompt Unit Test Log Message Level + gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel|0xFFFFFFFF|UINT32|0x00000001 diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc new file mode 100644 index 00000000000..0ad44822738 --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc @@ -0,0 +1,34 @@ +## @file +# UnitTestFrameworkPkg +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME = UnitTestFrameworkPkg + PLATFORM_GUID = 7420CC7E-334E-4EFF-B974-A39613455168 + PLATFORM_VERSION = 1.00 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/UnitTestFrameworkPkg + SUPPORTED_ARCHITECTURES = IA32|X64|EBC|ARM|AARCH64 + BUILD_TARGETS = DEBUG|RELEASE|NOOPT + SKUID_IDENTIFIER = DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc + +[Components] + UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf + UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf + UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf + UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.inf + UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf + UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.inf + UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf + + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestDxe.inf + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestPei.inf + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestSmm.inf + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestUefiShell.inf diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.uni b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.uni new file mode 100644 index 00000000000..180675ae1a0 --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.uni @@ -0,0 +1,21 @@ +// /** @file +// This Package provides all definitions (including functions, MACROs, +// structures library classes, and PCDs) and libraries instances, which are used +// to support unit testing and interface testing. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PACKAGE_ABSTRACT #language en-US "This Package provides all definitions (including functions, MACROs, structures library classes, and PCDs) and libraries instances, which are used to support unit testing and interface testing." + +#string STR_PACKAGE_DESCRIPTION #language en-US "This Package provides all definitions (including functions, MACROs, structures library classes, and PCDs) and libraries instances, which are used to support unit testing and interface testing." + +#string STR_gUnitTestFrameworkPkgTokenSpaceGuid_PcdUnitTestLogLevel_PROMPT #language en-US "Unit Test Log Message Level" + +#string STR_gUnitTestFrameworkPkgTokenSpaceGuid_PcdUnitTestLogLevel_HELP #language en-US "This flag is used to control build time optimization based on unit test log level. The default value is 0xFFFFFFFF to enable all unit test log messages.

\n" + "BIT0 - Error unit test log messages.
\n" + "BIT1 - Warning unit test log messages.
\n" + "BIT2 - Informational unit test log messages.
\n" + "BIT3 - Verbose unit test log messages.
\n" diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc b/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc new file mode 100644 index 00000000000..cf833b26b46 --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc @@ -0,0 +1,56 @@ +## @file +# UnitTestFrameworkPkg DSC include file for host based test DSC +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc + +[LibraryClasses.common.HOST_APPLICATION] + CmockaLib|UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf + UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf + DebugLib|UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf + MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf + +[BuildOptions] + GCC:*_*_*_CC_FLAGS = -fno-pie + +[BuildOptions.common.EDKII.HOST_APPLICATION] + # + # MSFT + # + MSFT:*_*_*_DLINK_FLAGS == /out:"$(BIN_DIR)\$(BASE_NAME).exe" /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb" /IGNORE:4001 /NOLOGO /SUBSYSTEM:CONSOLE /DEBUG /NODEFAULTLIB:libcmt.lib libcmtd.lib + MSFT:*_*_IA32_DLINK_FLAGS = /MACHINE:I386 + MSFT:*_*_X64_DLINK_FLAGS = /MACHINE:AMD64 + + MSFT:*_VS2015_IA32_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%Lib" /LIBPATH:"%VS2015_PREFIX%VC\Lib" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" + MSFT:*_VS2015x86_IA32_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%Lib" /LIBPATH:"%VS2015_PREFIX%VC\Lib" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" + MSFT:*_VS2017_IA32_DLINK_FLAGS = /LIBPATH:"%VCToolsInstallDir%lib\x86" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" + MSFT:*_VS2019_IA32_DLINK_FLAGS = /LIBPATH:"%VCToolsInstallDir%lib\x86" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" + + MSFT:*_VS2015_X64_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%VC\Lib\AMD64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" + MSFT:*_VS2015x86_X64_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%VC\Lib\AMD64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" + MSFT:*_VS2017_X64_DLINK_FLAGS = /LIBPATH:"%VCToolsInstallDir%lib\x64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" + MSFT:*_VS2019_X64_DLINK_FLAGS = /LIBPATH:"%VCToolsInstallDir%lib\x64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" + + # + # GCC + # + GCC:*_*_IA32_DLINK_FLAGS == -o $(BIN_DIR)/$(BASE_NAME) -m32 + GCC:*_*_X64_DLINK_FLAGS == -o $(BIN_DIR)/$(BASE_NAME) -m64 + GCC:*_*_*_DLINK2_FLAGS == -lgcov + + # + # Need to do this link via gcc and not ld as the pathing to libraries changes from OS version to OS version + # + XCODE:*_*_IA32_DLINK_PATH == gcc + XCODE:*_*_IA32_CC_FLAGS = -I$(WORKSPACE)/EmulatorPkg/Unix/Host/X11IncludeHack + XCODE:*_*_IA32_DLINK_FLAGS == -arch i386 -o $(BIN_DIR)/Host -L/usr/X11R6/lib -lXext -lX11 -framework Carbon + XCODE:*_*_IA32_ASM_FLAGS == -arch i386 -g + + XCODE:*_*_X64_DLINK_PATH == gcc + XCODE:*_*_X64_DLINK_FLAGS == -o $(BIN_DIR)/Host -L/usr/X11R6/lib -lXext -lX11 -framework Carbon -Wl,-no_pie + XCODE:*_*_X64_ASM_FLAGS == -g + XCODE:*_*_X64_CC_FLAGS = -O0 -target x86_64-apple-darwin -I$(WORKSPACE)/EmulatorPkg/Unix/Host/X11IncludeHack "-DEFIAPI=__attribute__((ms_abi))" diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc b/UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc new file mode 100644 index 00000000000..c29b056fcac --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc @@ -0,0 +1,58 @@ +## @file +# UnitTestFrameworkPkg DSC include file for target based test DSC +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[LibraryClasses] + # + # Entry point + # + PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + + UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf + UnitTestPersistenceLib|UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf + UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf + +[LibraryClasses.ARM, LibraryClasses.AARCH64] + # + # It is not possible to prevent ARM compiler calls to generic intrinsic functions. + # This library provides the instrinsic functions generated by a given compiler. + # [LibraryClasses.ARM] and NULL mean link this library into all ARM images. + # + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + + # + # Since software stack checking may be heuristically enabled by the compiler + # include BaseStackCheckLib unconditionally. + # + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf + +[LibraryClasses.common.PEIM] + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf + MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf + PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf + +[LibraryClasses.common.UEFI_APPLICATION] + UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf + +[PcdsFixedAtBuild] + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17 + +[BuildOptions] + MSFT:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES + GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/edksetup.bat b/edksetup.bat index 024f57a4b73..7b9377aaa5c 100755 --- a/edksetup.bat +++ b/edksetup.bat @@ -113,6 +113,18 @@ if not defined NASM_PREFIX ( @if not exist "C:\nasm\nasm.exe" echo Attempting to build modules that require NASM will fail. ) +:check_CLANGPDB +@REM In Windows, set CLANG_HOST_BIN=n to use nmake command +@set CLANG_HOST_BIN=n +if not defined CLANG_BIN ( + @echo. + @echo !!! WARNING !!! CLANG_BIN environment variable is not set + @if exist "C:\Program Files\LLVM\bin\clang.exe" ( + @set CLANG_BIN=C:\Program Files\LLVM\bin\ + @echo Found LLVM, setting CLANG_BIN environment variable to C:\Program Files\LLVM\bin\ + ) +) + :check_cygwin if defined CYGWIN_HOME ( if not exist "%CYGWIN_HOME%" ( diff --git a/pip-requirements.txt b/pip-requirements.txt new file mode 100644 index 00000000000..6a41a95ec59 --- /dev/null +++ b/pip-requirements.txt @@ -0,0 +1,16 @@ +## @file +# EDK II Python PIP requirements file +# +# This file provides the list of python components to install using PIP. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# https://pypi.org/project/pip/ +# https://pip.pypa.io/en/stable/user_guide/#requirements-files +# https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format +# +## + +edk2-pytool-library==0.10.* +edk2-pytool-extensions==0.12.*