summaryrefslogtreecommitdiff
path: root/Core/UefiCpuPkg/Feature
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2017-04-27 11:22:26 +0800
committerGuo Mang <mang.guo@intel.com>2017-04-27 11:22:26 +0800
commit38c2cbb9354d7f58e48f9f649f23eb9bd0d3cfca (patch)
tree1d4540cd9c19c47d10a161184c8f1a12f8ffc455 /Core/UefiCpuPkg/Feature
parentc6ff7c547bfc71da9d5e71a73984b9d3a4ea0809 (diff)
downloadedk2-platforms-38c2cbb9354d7f58e48f9f649f23eb9bd0d3cfca.tar.xz
UefiCpuPkg: Move to new location
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Core/UefiCpuPkg/Feature')
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.c42
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf40
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.uni21
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc33
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf32
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/Readme.md20
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Microcode/Microcode.inf27
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc39
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf32
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Readme.md33
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c748
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c981
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h494
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf71
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni21
-rw-r--r--Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni20
16 files changed, 2654 insertions, 0 deletions
diff --git a/Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.c b/Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.c
new file mode 100644
index 0000000000..7a5ec152d7
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.c
@@ -0,0 +1,42 @@
+/** @file
+ Microcode flash device access library NULL instance.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ 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 <PiDxe.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/MicrocodeFlashAccessLib.h>
+
+/**
+ Perform microcode write opreation.
+
+ @param[in] FlashAddress The address of flash device to be accessed.
+ @param[in] Buffer The pointer to the data buffer.
+ @param[in] Length The length of data buffer in bytes.
+
+ @retval EFI_SUCCESS The operation returns successfully.
+ @retval EFI_WRITE_PROTECTED The flash device is read only.
+ @retval EFI_UNSUPPORTED The flash device access is unsupported.
+ @retval EFI_INVALID_PARAMETER The input parameter is not valid.
+**/
+EFI_STATUS
+EFIAPI
+MicrocodeFlashWrite (
+ IN EFI_PHYSICAL_ADDRESS FlashAddress,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ CopyMem((VOID *)(UINTN)(FlashAddress), Buffer, Length);
+ return EFI_SUCCESS;
+}
diff --git a/Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf b/Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf
new file mode 100644
index 0000000000..a4a47e0737
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf
@@ -0,0 +1,40 @@
+## @file
+# Microcode flash device access library.
+#
+# Microcode flash device access library NULL instance.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# 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 = 0x00010005
+ BASE_NAME = MicrocodeFlashAccessLibNull
+ MODULE_UNI_FILE = MicrocodeFlashAccessLibNull.uni
+ FILE_GUID = 6F871ADD-9D86-4676-8BAD-68E2E451FC5B
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MicrocodeFlashAccessLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ MicrocodeFlashAccessLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
diff --git a/Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.uni b/Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.uni
new file mode 100644
index 0000000000..cc4195c412
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Microcode flash device access library.
+//
+// Microcode flash device access library NULL instance.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Microcode flash device access library."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Microcode flash device access library NULL instance."
+
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc
new file mode 100644
index 0000000000..1b22c55117
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc
@@ -0,0 +1,33 @@
+## @file
+# MicrocodeCapsulePdb
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+# 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]
+#
+# Uncomment the following line and update with your platform pkg name
+#
+# PLATFORM_NAME = <PlatformPkg>
+ PLATFORM_GUID = 6875FD33-602E-4EF9-9DF2-8BA7D8B7A7AF
+ PLATFORM_VERSION = 0.1
+#
+# Uncomment the following line and update with your platform pkg name
+#
+# FLASH_DEFINITION = <PlatformPkg>/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf
+#
+# Uncomment the following line and update with your platform pkg name
+#
+# OUTPUT_DIRECTORY = Build/<PlatformPkg>
+ SUPPORTED_ARCHITECTURES = IA32|X64
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf
new file mode 100644
index 0000000000..f171604d4f
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf
@@ -0,0 +1,32 @@
+## @file
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+# 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.
+#
+##
+
+[FmpPayload.FmpPayloadMicrocode1]
+IMAGE_HEADER_INIT_VERSION = 0x02
+IMAGE_TYPE_ID = 96d4fdcd-1502-424d-9d4c-9b12d2dcae5c # Microcode GUID (do not change it)
+IMAGE_INDEX = 0x1
+HARDWARE_INSTANCE = 0x0
+
+#
+# Uncomment the following line and update with path to Microcode PDB file
+#
+#FILE DATA = $(WORKSPACE)/<PlatformPkg>/Microcode/Microcode.pdb
+
+[Capsule.MicrocodeCapsule]
+CAPSULE_GUID = 6dcbd5ed-e82d-4c44-bda1-7194199ad92a # FMP special Guid (do not change it)
+CAPSULE_FLAGS = PersistAcrossReset,InitiateReset
+CAPSULE_HEADER_SIZE = 0x20
+CAPSULE_HEADER_INIT_VERSION = 0x1
+
+FMP_PAYLOAD = FmpPayloadMicrocode1
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/Readme.md b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/Readme.md
new file mode 100644
index 0000000000..9f81373fda
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/Readme.md
@@ -0,0 +1,20 @@
+# How to generate Microcode FMP from Microcode PDB file
+
+1) Copy directory `UefiCpuPkg/Feature/Capsule/MicrocodeUpdatePdb` to `<Your Platform Package>/MicrocodeUpdatePdb`.
+
+2) Uncomment and update `FILE DATA` statement in `<Your Platform Package>/MicrocodeUpdatePdb/MicrocodeCapsulePdb.fdf` with path to a Microcode PDB file. The PDB file can placed in `<Your Platform Package>/MicrocodeUpdatePdb` or any other path.
+
+`FILE DATA = <your Microcode PDB file path>`
+
+Uncomment and update `PLATFORM_NAME`, `FLASH_DEFINITION`, `OUTPUT_DIRECTORY` section in `<Your Platform Package>/MicrocodeUpdatePdb/MicrocodeCapsulePdb.dsc` with <Your Platform Package>.
+
+ PLATFORM_NAME = <Your Platform Package>
+ FLASH_DEFINITION = <Your Platform Package>/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf
+ OUTPUT_DIRECTORY = Build/<Your Platform Package>
+
+3) Use EDK II build tools to generate the Microcode FMP Capsule
+
+`build -p <Your Platform Package>/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc`
+
+4) The Microcode FMP Capsule is generated at `$(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/FV/MicrocodeCapsule.Cap`
+
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Microcode/Microcode.inf b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Microcode/Microcode.inf
new file mode 100644
index 0000000000..81af841f2c
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Microcode/Microcode.inf
@@ -0,0 +1,27 @@
+## @file
+# Microcode text file to binary
+#
+# Convert text format microcode to binary format.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# 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]
+BASE_NAME = Microcode
+FILE_GUID = ABC36AAC-2031-4422-896E-0A3B899AD0B4
+COMPONENT_TYPE = Microcode
+FFS_EXT = .ffs
+
+[Sources]
+#
+# Uncomment the following line and update with name of Microcode TXT file
+#
+#Microcode.txt
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc
new file mode 100644
index 0000000000..a66f89b4e2
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc
@@ -0,0 +1,39 @@
+## @file
+# MicrocodeCapsuleTxt
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+# 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]
+#
+# Uncomment the following line and update with your platform pkg name
+#
+# PLATFORM_NAME = <PlatformPkg>
+ PLATFORM_GUID = 6875FD33-602E-4EF9-9DF2-8BA7D8B7A7AF
+ PLATFORM_VERSION = 0.1
+#
+# Uncomment the following line and update with your platform pkg name
+#
+# FLASH_DEFINITION = <PlatformPkg>/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf
+#
+# Uncomment the following line and update with your platform pkg name
+#
+# OUTPUT_DIRECTORY = Build/<PlatformPkg>
+ SUPPORTED_ARCHITECTURES = IA32|X64
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+
+[Components]
+#
+# Uncomment the following line and update with path to Microcode INF file
+#
+# <PlatformPkg>/MicrocodeCapsuleTxt/Microcode/Microcode.inf
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf
new file mode 100644
index 0000000000..113693b1df
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf
@@ -0,0 +1,32 @@
+## @file
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+# 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.
+#
+##
+
+[FmpPayload.FmpPayloadMicrocode1]
+IMAGE_HEADER_INIT_VERSION = 0x02
+IMAGE_TYPE_ID = 96d4fdcd-1502-424d-9d4c-9b12d2dcae5c # Microcode GUID (do not change it)
+IMAGE_INDEX = 0x1
+HARDWARE_INSTANCE = 0x0
+
+#
+# Uncomment the following line and update with path to Microcode MCB file
+#
+#FILE DATA = $(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/IA32/PlatformPkg/MicrocodeCapsuleTxt/Microcode/Microcode/OUTPUT/Microcode.mcb
+
+[Capsule.MicrocodeCapsule]
+CAPSULE_GUID = 6dcbd5ed-e82d-4c44-bda1-7194199ad92a # FMP special Guid (do not change it)
+CAPSULE_FLAGS = PersistAcrossReset,InitiateReset
+CAPSULE_HEADER_SIZE = 0x20
+CAPSULE_HEADER_INIT_VERSION = 0x1
+
+FMP_PAYLOAD = FmpPayloadMicrocode1
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Readme.md b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Readme.md
new file mode 100644
index 0000000000..f7d7040fcb
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Readme.md
@@ -0,0 +1,33 @@
+# How to generate Microcode FMP from Microcode TXT file
+
+1) Copy directory `UefiCpuPkg/Feature/Capsule/MicrocodeUpdateTxt` to `<Your Platform Package>/MicrocodeUpdateTxt`
+
+2) Copy microcode TXT file to`<Your Platform Package>/MicrocodeUpdateTxt/Microcode`
+
+3) Uncomment and update statement in `[Sources]` section of `<Your Platform Package>/MicrocodeUpdateTxt/Microcode/Microcode.inf` with name of Microcode TXT file copied in previous step.
+
+ [Sources]
+ <Your Microcode TXT file>
+
+Uncomment and update `FILE DATA` statement in `<Your Platform Package>/MicrocodeUpdateTxt/MicrocodeCapsuleTxt.fdf` with path to a Microcode MCB file. The MCB file is placed in `$(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/IA32/<Your Platform Package>/MicrocodeUpdateTxt/Microcode/Microcode/OUTPUT/`.
+
+`FILE DATA = <your Microcode MCB file path>`
+
+Uncomment and update `PLATFORM_NAME`, `FLASH_DEFINITION`, `OUTPUT_DIRECTORY` section in `<Your Platform Package>/MicrocodeUpdateTxt/MicrocodeCapsuleTxt.dsc` with <Your Platform Package>.
+
+ PLATFORM_NAME = <Your Platform Package>
+ FLASH_DEFINITION = <Your Platform Package>/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf
+ OUTPUT_DIRECTORY = Build/<Your Platform Package>
+
+Uncomment and update statement in `Components` section of `<Your Platform Package>/MicrocodeUpdateTxt/MicrocodeCapsuleTxt.dsc` with path to a Microcode INF file.
+
+ [Components]
+ <Your Microcode INF file>
+
+4) Use EDK II build tools to generate the Microcode FMP Capsule
+
+`build -p <Your Platform Package>/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc`
+
+5) The generated Microcode FMP Capsule is found at `$(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/FV/MicrocodeCapsule.Cap`
+
+
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
new file mode 100644
index 0000000000..ebde93a91e
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
@@ -0,0 +1,748 @@
+/** @file
+ Produce FMP instance for Microcode.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ 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 "MicrocodeUpdate.h"
+
+//
+// MicrocodeFmp driver private data
+//
+MICROCODE_FMP_PRIVATE_DATA *mMicrocodeFmpPrivate = NULL;
+
+EFI_FIRMWARE_MANAGEMENT_PROTOCOL mFirmwareManagementProtocol = {
+ FmpGetImageInfo,
+ FmpGetImage,
+ FmpSetImage,
+ FmpCheckImage,
+ FmpGetPackageInfo,
+ FmpSetPackageInfo
+};
+
+/**
+ Initialize Microcode Descriptor.
+
+ @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+ @return EFI_SUCCESS Microcode Descriptor is initialized.
+**/
+EFI_STATUS
+InitializeMicrocodeDescriptor (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+ );
+
+/**
+ Returns information about the current firmware image(s) of the device.
+
+ This function allows a copy of the current firmware image to be created and saved.
+ The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in, out] ImageInfoSize A pointer to the size, in bytes, of the ImageInfo buffer.
+ On input, this is the size of the buffer allocated by the caller.
+ On output, it is the size of the buffer returned by the firmware
+ if the buffer was large enough, or the size of the buffer needed
+ to contain the image(s) information if the buffer was too small.
+ @param[in, out] ImageInfo A pointer to the buffer in which firmware places the current image(s)
+ information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
+ @param[out] DescriptorVersion A pointer to the location in which firmware returns the version number
+ associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] DescriptorCount A pointer to the location in which firmware returns the number of
+ descriptors or firmware images within this device.
+ @param[out] DescriptorSize A pointer to the location in which firmware returns the size, in bytes,
+ of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] PackageVersion A version number that represents all the firmware images in the device.
+ The format is vendor specific and new version must have a greater value
+ than the old version. If PackageVersion is not supported, the value is
+ 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison
+ is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates
+ that package version update is in progress.
+ @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing the
+ package version name. The buffer is allocated by this function with
+ AllocatePool(), and it is the caller's responsibility to free it with a call
+ to FreePool().
+
+ @retval EFI_SUCCESS The device was successfully updated with the new image.
+ @retval EFI_BUFFER_TOO_SMALL The ImageInfo buffer was too small. The current buffer size
+ needed to hold the image(s) information is returned in ImageInfoSize.
+ @retval EFI_INVALID_PARAMETER ImageInfoSize is NULL.
+ @retval EFI_DEVICE_ERROR Valid information could not be returned. Possible corrupted image.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetImageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN OUT UINTN *ImageInfoSize,
+ IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ OUT UINT32 *DescriptorVersion,
+ OUT UINT8 *DescriptorCount,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName
+ )
+{
+ MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
+ UINTN Index;
+
+ MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This);
+
+ if(ImageInfoSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*ImageInfoSize < sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount) {
+ *ImageInfoSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (ImageInfo == NULL ||
+ DescriptorVersion == NULL ||
+ DescriptorCount == NULL ||
+ DescriptorSize == NULL ||
+ PackageVersion == NULL ||
+ PackageVersionName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *ImageInfoSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount;
+ *DescriptorSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR);
+ *DescriptorCount = MicrocodeFmpPrivate->DescriptorCount;
+ *DescriptorVersion = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
+
+ //
+ // supports 1 ImageInfo descriptor
+ //
+ CopyMem(&ImageInfo[0], MicrocodeFmpPrivate->ImageDescriptor, sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount);
+ for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+ if ((ImageInfo[Index].AttributesSetting & IMAGE_ATTRIBUTE_IN_USE) != 0) {
+ ImageInfo[Index].LastAttemptVersion = MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion;
+ ImageInfo[Index].LastAttemptStatus = MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus;
+ }
+ }
+
+ //
+ // package version
+ //
+ *PackageVersion = MicrocodeFmpPrivate->PackageVersion;
+ if (MicrocodeFmpPrivate->PackageVersionName != NULL) {
+ *PackageVersionName = AllocateCopyPool(StrSize(MicrocodeFmpPrivate->PackageVersionName), MicrocodeFmpPrivate->PackageVersionName);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves a copy of the current firmware image of the device.
+
+ This function allows a copy of the current firmware image to be created and saved.
+ The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
+ The number is between 1 and DescriptorCount.
+ @param[in,out] Image Points to the buffer where the current image is copied to.
+ @param[in,out] ImageSize On entry, points to the size of the buffer pointed to by Image, in bytes.
+ On return, points to the length of the image, in bytes.
+
+ @retval EFI_SUCCESS The device was successfully updated with the new image.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to hold the
+ image. The current buffer size needed to hold the image is returned
+ in ImageSize.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_NOT_FOUND The current image is not copied to the buffer.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN OUT VOID *Image,
+ IN OUT UINTN *ImageSize
+ )
+{
+ MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
+ MICROCODE_INFO *MicrocodeInfo;
+
+ if (Image == NULL || ImageSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This);
+
+ if (ImageIndex == 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorCount || ImageSize == NULL || Image == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MicrocodeInfo = &MicrocodeFmpPrivate->MicrocodeInfo[ImageIndex - 1];
+
+ if (*ImageSize < MicrocodeInfo->TotalSize) {
+ *ImageSize = MicrocodeInfo->TotalSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *ImageSize = MicrocodeInfo->TotalSize;
+ CopyMem (Image, MicrocodeInfo->MicrocodeEntryPoint, MicrocodeInfo->TotalSize);
+ return EFI_SUCCESS;
+}
+
+/**
+ Updates the firmware image of the device.
+
+ This function updates the hardware with the new firmware image.
+ This function returns EFI_UNSUPPORTED if the firmware image is not updatable.
+ If the firmware image is updatable, the function should perform the following minimal validations
+ before proceeding to do the firmware image update.
+ - Validate the image authentication if image has attribute
+ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns
+ EFI_SECURITY_VIOLATION if the validation fails.
+ - Validate the image is a supported image for this device. The function returns EFI_ABORTED if
+ the image is unsupported. The function can optionally provide more detailed information on
+ why the image is not a supported image.
+ - Validate the data from VendorCode if not null. Image validation must be performed before
+ VendorCode data validation. VendorCode data is ignored or considered invalid if image
+ validation failed. The function returns EFI_ABORTED if the data is invalid.
+
+ VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if
+ the caller did not specify the policy or use the default policy. As an example, vendor can implement
+ a policy to allow an option to force a firmware image update when the abort reason is due to the new
+ firmware image version is older than the current firmware image version or bad image checksum.
+ Sensitive operations such as those wiping the entire firmware image and render the device to be
+ non-functional should be encoded in the image itself rather than passed with the VendorCode.
+ AbortReason enables vendor to have the option to provide a more detailed description of the abort
+ reason to the caller.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
+ The number is between 1 and DescriptorCount.
+ @param[in] Image Points to the new image.
+ @param[in] ImageSize Size of the new image in bytes.
+ @param[in] VendorCode This enables vendor to implement vendor-specific firmware image update policy.
+ Null indicates the caller did not specify the policy or use the default policy.
+ @param[in] Progress A function used by the driver to report the progress of the firmware update.
+ @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
+ details for the aborted operation. The buffer is allocated by this function
+ with AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+
+ @retval EFI_SUCCESS The device was successfully updated with the new image.
+ @retval EFI_ABORTED The operation is aborted.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpSetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
+ OUT CHAR16 **AbortReason
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS VarStatus;
+ MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
+
+ if (Image == NULL || AbortReason == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This);
+ *AbortReason = NULL;
+
+ if (ImageIndex == 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorCount || Image == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = MicrocodeWrite(MicrocodeFmpPrivate, (VOID *)Image, ImageSize, &MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, &MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus, AbortReason);
+ DEBUG((DEBUG_INFO, "SetImage - LastAttemp Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));
+ VarStatus = gRT->SetVariable(
+ MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(MicrocodeFmpPrivate->LastAttempt),
+ &MicrocodeFmpPrivate->LastAttempt
+ );
+ DEBUG((DEBUG_INFO, "SetLastAttemp - %r\n", VarStatus));
+
+ if (!EFI_ERROR(Status)) {
+ InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
+ DumpPrivateInfo (MicrocodeFmpPrivate);
+ }
+
+ return Status;
+}
+
+/**
+ Checks if the firmware image is valid for the device.
+
+ This function allows firmware update application to validate the firmware image without
+ invoking the SetImage() first.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
+ The number is between 1 and DescriptorCount.
+ @param[in] Image Points to the new image.
+ @param[in] ImageSize Size of the new image in bytes.
+ @param[out] ImageUpdatable Indicates if the new image is valid for update. It also provides,
+ if available, additional information if the image is invalid.
+
+ @retval EFI_SUCCESS The image was successfully checked.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpCheckImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *ImageUpdatable
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Returns information about the firmware package.
+
+ This function returns package information.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[out] PackageVersion A version number that represents all the firmware images in the device.
+ The format is vendor specific and new version must have a greater value
+ than the old version. If PackageVersion is not supported, the value is
+ 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version
+ comparison is to be performed using PackageVersionName. A value of
+ 0xFFFFFFFD indicates that package version update is in progress.
+ @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing
+ the package version name. The buffer is allocated by this function with
+ AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+ @param[out] PackageVersionNameMaxLen The maximum length of package version name if device supports update of
+ package version name. A value of 0 indicates the device does not support
+ update of package version name. Length is the number of Unicode characters,
+ including the terminating null character.
+ @param[out] AttributesSupported Package attributes that are supported by this device. See 'Package Attribute
+ Definitions' for possible returned values of this parameter. A value of 1
+ indicates the attribute is supported and the current setting value is
+ indicated in AttributesSetting. A value of 0 indicates the attribute is not
+ supported and the current setting value in AttributesSetting is meaningless.
+ @param[out] AttributesSetting Package attributes. See 'Package Attribute Definitions' for possible returned
+ values of this parameter
+
+ @retval EFI_SUCCESS The package information was successfully returned.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName,
+ OUT UINT32 *PackageVersionNameMaxLen,
+ OUT UINT64 *AttributesSupported,
+ OUT UINT64 *AttributesSetting
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Updates information about the firmware package.
+
+ This function updates package information.
+ This function returns EFI_UNSUPPORTED if the package information is not updatable.
+ VendorCode enables vendor to implement vendor-specific package information update policy.
+ Null if the caller did not specify this policy or use the default policy.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] Image Points to the authentication image.
+ Null if authentication is not required.
+ @param[in] ImageSize Size of the authentication image in bytes.
+ 0 if authentication is not required.
+ @param[in] VendorCode This enables vendor to implement vendor-specific firmware
+ image update policy.
+ Null indicates the caller did not specify this policy or use
+ the default policy.
+ @param[in] PackageVersion The new package version.
+ @param[in] PackageVersionName A pointer to the new null-terminated Unicode string representing
+ the package version name.
+ The string length is equal to or less than the value returned in
+ PackageVersionNameMaxLen.
+
+ @retval EFI_SUCCESS The device was successfully updated with the new package
+ information.
+ @retval EFI_INVALID_PARAMETER The PackageVersionName length is longer than the value
+ returned in PackageVersionNameMaxLen.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpSetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN UINT32 PackageVersion,
+ IN CONST CHAR16 *PackageVersionName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Initialize Processor Microcode Index.
+
+ @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+**/
+VOID
+InitializedProcessorMicrocodeIndex (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+ )
+{
+ UINTN CpuIndex;
+ UINTN MicrocodeIndex;
+ UINTN TargetCpuIndex;
+ UINT32 AttemptStatus;
+ EFI_STATUS Status;
+
+ for (CpuIndex = 0; CpuIndex < MicrocodeFmpPrivate->ProcessorCount; CpuIndex++) {
+ if (MicrocodeFmpPrivate->ProcessorInfo[CpuIndex].MicrocodeIndex != (UINTN)-1) {
+ continue;
+ }
+ for (MicrocodeIndex = 0; MicrocodeIndex < MicrocodeFmpPrivate->DescriptorCount; MicrocodeIndex++) {
+ if (!MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].InUse) {
+ continue;
+ }
+ TargetCpuIndex = CpuIndex;
+ Status = VerifyMicrocode(
+ MicrocodeFmpPrivate,
+ MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].MicrocodeEntryPoint,
+ MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].TotalSize,
+ FALSE,
+ &AttemptStatus,
+ NULL,
+ &TargetCpuIndex
+ );
+ if (!EFI_ERROR(Status)) {
+ MicrocodeFmpPrivate->ProcessorInfo[CpuIndex].MicrocodeIndex = MicrocodeIndex;
+ }
+ }
+ }
+}
+
+/**
+ Initialize Microcode Descriptor.
+
+ @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+ @return EFI_SUCCESS Microcode Descriptor is initialized.
+**/
+EFI_STATUS
+InitializeMicrocodeDescriptor (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+ )
+{
+ UINT8 CurrentMicrocodeCount;
+
+ CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, 0, NULL, NULL);
+
+ if (CurrentMicrocodeCount > MicrocodeFmpPrivate->DescriptorCount) {
+ if (MicrocodeFmpPrivate->ImageDescriptor != NULL) {
+ FreePool(MicrocodeFmpPrivate->ImageDescriptor);
+ MicrocodeFmpPrivate->ImageDescriptor = NULL;
+ }
+ if (MicrocodeFmpPrivate->MicrocodeInfo != NULL) {
+ FreePool(MicrocodeFmpPrivate->MicrocodeInfo);
+ MicrocodeFmpPrivate->MicrocodeInfo = NULL;
+ }
+ } else {
+ ZeroMem(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR));
+ ZeroMem(MicrocodeFmpPrivate->MicrocodeInfo, MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));
+ }
+
+ MicrocodeFmpPrivate->DescriptorCount = CurrentMicrocodeCount;
+
+ if (MicrocodeFmpPrivate->ImageDescriptor == NULL) {
+ MicrocodeFmpPrivate->ImageDescriptor = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR));
+ if (MicrocodeFmpPrivate->ImageDescriptor == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {
+ MicrocodeFmpPrivate->MicrocodeInfo = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));
+ if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, MicrocodeFmpPrivate->DescriptorCount, MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->MicrocodeInfo);
+ ASSERT(CurrentMicrocodeCount == MicrocodeFmpPrivate->DescriptorCount);
+
+ InitializedProcessorMicrocodeIndex (MicrocodeFmpPrivate);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize MicrocodeFmpDriver multiprocessor information.
+
+ @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+ @return EFI_SUCCESS private data is initialized.
+**/
+EFI_STATUS
+InitializeProcessorInfo (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpService;
+ UINTN NumberOfProcessors;
+ UINTN NumberOfEnabledProcessors;
+ UINTN Index;
+ UINTN BspIndex;
+
+ Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpService);
+ ASSERT_EFI_ERROR(Status);
+
+ MicrocodeFmpPrivate->MpService = MpService;
+ MicrocodeFmpPrivate->ProcessorCount = 0;
+ MicrocodeFmpPrivate->ProcessorInfo = NULL;
+
+ Status = MpService->GetNumberOfProcessors (MpService, &NumberOfProcessors, &NumberOfEnabledProcessors);
+ ASSERT_EFI_ERROR(Status);
+ MicrocodeFmpPrivate->ProcessorCount = NumberOfProcessors;
+
+ Status = MpService->WhoAmI (MpService, &BspIndex);
+ ASSERT_EFI_ERROR(Status);
+ MicrocodeFmpPrivate->BspIndex = BspIndex;
+
+ MicrocodeFmpPrivate->ProcessorInfo = AllocateZeroPool (sizeof(PROCESSOR_INFO) * MicrocodeFmpPrivate->ProcessorCount);
+ if (MicrocodeFmpPrivate->ProcessorInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < NumberOfProcessors; Index++) {
+ MicrocodeFmpPrivate->ProcessorInfo[Index].CpuIndex = Index;
+ MicrocodeFmpPrivate->ProcessorInfo[Index].MicrocodeIndex = (UINTN)-1;
+ if (Index == BspIndex) {
+ CollectProcessorInfo (&MicrocodeFmpPrivate->ProcessorInfo[Index]);
+ } else {
+ Status = MpService->StartupThisAP (
+ MpService,
+ CollectProcessorInfo,
+ Index,
+ NULL,
+ 0,
+ &MicrocodeFmpPrivate->ProcessorInfo[Index],
+ NULL
+ );
+ ASSERT_EFI_ERROR(Status);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Dump private information.
+
+ @param[in] MicrocodeFmpPrivate private data structure.
+**/
+VOID
+DumpPrivateInfo (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+ )
+{
+ UINTN Index;
+ PROCESSOR_INFO *ProcessorInfo;
+ MICROCODE_INFO *MicrocodeInfo;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor;
+
+ DEBUG ((DEBUG_INFO, "ProcessorInfo:\n"));
+ DEBUG ((DEBUG_INFO, " ProcessorCount - 0x%x\n", MicrocodeFmpPrivate->ProcessorCount));
+ DEBUG ((DEBUG_INFO, " BspIndex - 0x%x\n", MicrocodeFmpPrivate->BspIndex));
+
+ ProcessorInfo = MicrocodeFmpPrivate->ProcessorInfo;
+ for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
+ DEBUG ((
+ DEBUG_INFO,
+ " ProcessorInfo[0x%x] - 0x%08x, 0x%02x, 0x%08x, (0x%x)\n",
+ ProcessorInfo[Index].CpuIndex,
+ ProcessorInfo[Index].ProcessorSignature,
+ ProcessorInfo[Index].PlatformId,
+ ProcessorInfo[Index].MicrocodeRevision,
+ ProcessorInfo[Index].MicrocodeIndex
+ ));
+ }
+
+ DEBUG ((DEBUG_INFO, "MicrocodeInfo:\n"));
+ MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
+ DEBUG ((DEBUG_INFO, " MicrocodeRegion - 0x%x - 0x%x\n", MicrocodeFmpPrivate->MicrocodePatchAddress, MicrocodeFmpPrivate->MicrocodePatchRegionSize));
+ DEBUG ((DEBUG_INFO, " MicrocodeCount - 0x%x\n", MicrocodeFmpPrivate->DescriptorCount));
+ for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+ DEBUG ((
+ DEBUG_INFO,
+ " MicrocodeInfo[0x%x] - 0x%08x, 0x%08x, (0x%x)\n",
+ Index,
+ MicrocodeInfo[Index].MicrocodeEntryPoint,
+ MicrocodeInfo[Index].TotalSize,
+ MicrocodeInfo[Index].InUse
+ ));
+ }
+
+ ImageDescriptor = MicrocodeFmpPrivate->ImageDescriptor;
+ DEBUG ((DEBUG_VERBOSE, "ImageDescriptor:\n"));
+ for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+ DEBUG((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));
+ DEBUG((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", ImageDescriptor[Index].ImageIndex));
+ DEBUG((DEBUG_VERBOSE, " ImageTypeId - %g\n", &ImageDescriptor[Index].ImageTypeId));
+ DEBUG((DEBUG_VERBOSE, " ImageId - 0x%lx\n", ImageDescriptor[Index].ImageId));
+ DEBUG((DEBUG_VERBOSE, " ImageIdName - %s\n", ImageDescriptor[Index].ImageIdName));
+ DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", ImageDescriptor[Index].Version));
+ DEBUG((DEBUG_VERBOSE, " VersionName - %s\n", ImageDescriptor[Index].VersionName));
+ DEBUG((DEBUG_VERBOSE, " Size - 0x%x\n", ImageDescriptor[Index].Size));
+ DEBUG((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", ImageDescriptor[Index].AttributesSupported));
+ DEBUG((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", ImageDescriptor[Index].AttributesSetting));
+ DEBUG((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", ImageDescriptor[Index].Compatibilities));
+ DEBUG((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", ImageDescriptor[Index].LowestSupportedImageVersion));
+ DEBUG((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", ImageDescriptor[Index].LastAttemptVersion));
+ DEBUG((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", ImageDescriptor[Index].LastAttemptStatus));
+ DEBUG((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", ImageDescriptor[Index].HardwareInstance));
+ }
+}
+
+/**
+ Initialize MicrocodeFmpDriver private data structure.
+
+ @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+ @return EFI_SUCCESS private data is initialized.
+**/
+EFI_STATUS
+InitializePrivateData (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS VarStatus;
+ UINTN VarSize;
+ BOOLEAN Result;
+
+ MicrocodeFmpPrivate->Signature = MICROCODE_FMP_PRIVATE_DATA_SIGNATURE;
+ MicrocodeFmpPrivate->Handle = NULL;
+ CopyMem(&MicrocodeFmpPrivate->Fmp, &mFirmwareManagementProtocol, sizeof(EFI_FIRMWARE_MANAGEMENT_PROTOCOL));
+
+ MicrocodeFmpPrivate->PackageVersion = 0x1;
+ MicrocodeFmpPrivate->PackageVersionName = L"Microcode";
+
+ MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion = 0x0;
+ MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus = 0x0;
+ VarSize = sizeof(MicrocodeFmpPrivate->LastAttempt);
+ VarStatus = gRT->GetVariable(
+ MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME,
+ &gEfiCallerIdGuid,
+ NULL,
+ &VarSize,
+ &MicrocodeFmpPrivate->LastAttempt
+ );
+ DEBUG((DEBUG_INFO, "GetLastAttemp - %r\n", VarStatus));
+ DEBUG((DEBUG_INFO, "GetLastAttemp Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));
+
+ Result = GetMicrocodeRegion(&MicrocodeFmpPrivate->MicrocodePatchAddress, &MicrocodeFmpPrivate->MicrocodePatchRegionSize);
+ if (!Result) {
+ DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ Status = InitializeProcessorInfo (MicrocodeFmpPrivate);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "InitializeProcessorInfo - %r\n", Status));
+ return Status;
+ }
+
+ Status = InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "InitializeMicrocodeDescriptor - %r\n", Status));
+ return Status;
+ }
+
+ DumpPrivateInfo (MicrocodeFmpPrivate);
+
+ return Status;
+}
+
+/**
+ Microcode FMP module entrypoint
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @return EFI_SUCCESS Microcode FMP module is initialized.
+**/
+EFI_STATUS
+EFIAPI
+MicrocodeFmpMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Initialize MicrocodeFmpPrivateData
+ //
+ mMicrocodeFmpPrivate = AllocateZeroPool (sizeof(MICROCODE_FMP_PRIVATE_DATA));
+ if (mMicrocodeFmpPrivate == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = InitializePrivateData(mMicrocodeFmpPrivate);
+ if (EFI_ERROR(Status)) {
+ FreePool(mMicrocodeFmpPrivate);
+ mMicrocodeFmpPrivate = NULL;
+ return Status;
+ }
+
+ //
+ // Install FMP protocol.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mMicrocodeFmpPrivate->Handle,
+ &gEfiFirmwareManagementProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mMicrocodeFmpPrivate->Fmp
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool(mMicrocodeFmpPrivate);
+ mMicrocodeFmpPrivate = NULL;
+ return Status;
+ }
+
+ return Status;
+}
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
new file mode 100644
index 0000000000..4e8f1d5fd8
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
@@ -0,0 +1,981 @@
+/** @file
+ SetImage instance to update Microcode.
+
+ Caution: This module requires additional review when modified.
+ This module will have external input - capsule image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ 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 "MicrocodeUpdate.h"
+
+/**
+ Get Microcode Region.
+
+ @param[out] MicrocodePatchAddress The address of Microcode
+ @param[out] MicrocodePatchRegionSize The region size of Microcode
+
+ @retval TRUE The Microcode region is returned.
+ @retval FALSE No Microcode region.
+**/
+BOOLEAN
+GetMicrocodeRegion (
+ OUT VOID **MicrocodePatchAddress,
+ OUT UINTN *MicrocodePatchRegionSize
+ )
+{
+ *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);
+ *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);
+
+ if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Get Microcode update signature of currently loaded Microcode update.
+
+ @return Microcode signature.
+
+**/
+UINT32
+GetCurrentMicrocodeSignature (
+ VOID
+ )
+{
+ UINT64 Signature;
+
+ AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);
+ AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
+ Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);
+ return (UINT32)RShiftU64(Signature, 32);
+}
+
+/**
+ Get current processor signature.
+
+ @return current processor signature.
+**/
+UINT32
+GetCurrentProcessorSignature (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
+ return RegEax;
+}
+
+/**
+ Get current platform ID.
+
+ @return current platform ID.
+**/
+UINT8
+GetCurrentPlatformId (
+ VOID
+ )
+{
+ UINT8 PlatformId;
+
+ PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);
+ return PlatformId;
+}
+
+/**
+ Load new Microcode.
+
+ @param[in] Address The address of new Microcode.
+
+ @return Loaded Microcode signature.
+
+**/
+UINT32
+LoadMicrocode (
+ IN UINT64 Address
+ )
+{
+ AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);
+ return GetCurrentMicrocodeSignature();
+}
+
+/**
+ Load Microcode on an Application Processor.
+ The function prototype for invoking a function on an Application Processor.
+
+ @param[in,out] Buffer The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+MicrocodeLoadAp (
+ IN OUT VOID *Buffer
+ )
+{
+ MICROCODE_LOAD_BUFFER *MicrocodeLoadBuffer;
+
+ MicrocodeLoadBuffer = Buffer;
+ MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);
+}
+
+/**
+ Load new Microcode on this processor
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] CpuIndex The index of the processor.
+ @param[in] Address The address of new Microcode.
+
+ @return Loaded Microcode signature.
+
+**/
+UINT32
+LoadMicrocodeOnThis (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN UINTN CpuIndex,
+ IN UINT64 Address
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpService;
+ MICROCODE_LOAD_BUFFER MicrocodeLoadBuffer;
+
+ if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {
+ return LoadMicrocode (Address);
+ } else {
+ MpService = MicrocodeFmpPrivate->MpService;
+ MicrocodeLoadBuffer.Address = Address;
+ MicrocodeLoadBuffer.Revision = 0;
+ Status = MpService->StartupThisAP (
+ MpService,
+ MicrocodeLoadAp,
+ CpuIndex,
+ NULL,
+ 0,
+ &MicrocodeLoadBuffer,
+ NULL
+ );
+ ASSERT_EFI_ERROR(Status);
+ return MicrocodeLoadBuffer.Revision;
+ }
+}
+
+/**
+ Collect processor information.
+ The function prototype for invoking a function on an Application Processor.
+
+ @param[in,out] Buffer The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+CollectProcessorInfo (
+ IN OUT VOID *Buffer
+ )
+{
+ PROCESSOR_INFO *ProcessorInfo;
+
+ ProcessorInfo = Buffer;
+ ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();
+ ProcessorInfo->PlatformId = GetCurrentPlatformId();
+ ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();
+}
+
+/**
+ Get current Microcode information.
+
+ The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
+ in MicrocodeFmpPrivate must be initialized.
+
+ The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
+ in MicrocodeFmpPrivate may not be avaiable in this function.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.
+ @param[out] ImageDescriptor Microcode ImageDescriptor
+ @param[out] MicrocodeInfo Microcode information
+
+ @return Microcode count
+**/
+UINTN
+GetMicrocodeInfo (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN UINTN DescriptorCount, OPTIONAL
+ OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL
+ OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL
+ )
+{
+ VOID *MicrocodePatchAddress;
+ UINTN MicrocodePatchRegionSize;
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
+ UINTN MicrocodeEnd;
+ UINTN TotalSize;
+ UINTN Count;
+ UINT64 ImageAttributes;
+ BOOLEAN IsInUse;
+ EFI_STATUS Status;
+ UINT32 AttemptStatus;
+ UINTN TargetCpuIndex;
+
+ MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+ MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+ DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));
+
+ Count = 0;
+
+ MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
+ do {
+ if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {
+ //
+ // It is the microcode header. It is not the padding data between microcode patches
+ // becasue the padding data should not include 0x00000001 and it should be the repeated
+ // byte format (like 0xXYXYXYXY....).
+ //
+ if (MicrocodeEntryPoint->DataSize == 0) {
+ TotalSize = 2048;
+ } else {
+ TotalSize = MicrocodeEntryPoint->TotalSize;
+ }
+
+ TargetCpuIndex = (UINTN)-1;
+ Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);
+ if (!EFI_ERROR(Status)) {
+ IsInUse = TRUE;
+ ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
+ MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;
+ } else {
+ IsInUse = FALSE;
+ }
+
+ if (ImageDescriptor != NULL && DescriptorCount > Count) {
+ ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);
+ CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);
+ ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;
+ ImageDescriptor[Count].ImageIdName = NULL;
+ ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;
+ ImageDescriptor[Count].VersionName = NULL;
+ ImageDescriptor[Count].Size = TotalSize;
+ ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;
+ if (IsInUse) {
+ ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;
+ }
+ ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;
+ ImageDescriptor[Count].AttributesSetting = ImageAttributes;
+ ImageDescriptor[Count].Compatibilities = 0;
+ ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback
+ ImageDescriptor[Count].LastAttemptVersion = 0;
+ ImageDescriptor[Count].LastAttemptStatus = 0;
+ ImageDescriptor[Count].HardwareInstance = 0;
+ }
+ if (MicrocodeInfo != NULL && DescriptorCount > Count) {
+ MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;
+ MicrocodeInfo[Count].TotalSize = TotalSize;
+ MicrocodeInfo[Count].InUse = IsInUse;
+ }
+ } else {
+ //
+ // It is the padding data between the microcode patches for microcode patches alignment.
+ // Because the microcode patch is the multiple of 1-KByte, the padding data should not
+ // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
+ // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
+ // find the next possible microcode patch header.
+ //
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
+ continue;
+ }
+
+ Count++;
+ ASSERT(Count < 0xFF);
+
+ //
+ // Get the next patch.
+ //
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
+ } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
+
+ return Count;
+}
+
+/**
+ Return matched processor information.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] ProcessorSignature The processor signature to be matched
+ @param[in] ProcessorFlags The processor flags to be matched
+ @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
+ On output, the index of target CPU which matches the Microcode.
+
+ @return matched processor information.
+**/
+PROCESSOR_INFO *
+GetMatchedProcessor (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN UINT32 ProcessorSignature,
+ IN UINT32 ProcessorFlags,
+ IN OUT UINTN *TargetCpuIndex
+ )
+{
+ UINTN Index;
+
+ if (*TargetCpuIndex != (UINTN)-1) {
+ Index = *TargetCpuIndex;
+ if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
+ ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
+ return &MicrocodeFmpPrivate->ProcessorInfo[Index];
+ } else {
+ return NULL;
+ }
+ }
+
+ for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
+ if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
+ ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
+ *TargetCpuIndex = Index;
+ return &MicrocodeFmpPrivate->ProcessorInfo[Index];
+ }
+ }
+ return NULL;
+}
+
+/**
+ Verify Microcode.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] Image The Microcode image buffer.
+ @param[in] ImageSize The size of Microcode image buffer in bytes.
+ @param[in] TryLoad Try to load Microcode or not.
+ @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
+ details for the aborted operation. The buffer is allocated by this function
+ with AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+ @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
+ On output, the index of target CPU which matches the Microcode.
+
+ @retval EFI_SUCCESS The Microcode image passes verification.
+ @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
+ @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
+ @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.
+ @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
+**/
+EFI_STATUS
+VerifyMicrocode (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN VOID *Image,
+ IN UINTN ImageSize,
+ IN BOOLEAN TryLoad,
+ OUT UINT32 *LastAttemptStatus,
+ OUT CHAR16 **AbortReason, OPTIONAL
+ IN OUT UINTN *TargetCpuIndex
+ )
+{
+ UINTN Index;
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
+ UINTN TotalSize;
+ UINTN DataSize;
+ UINT32 CurrentRevision;
+ PROCESSOR_INFO *ProcessorInfo;
+ UINT32 CheckSum32;
+ UINTN ExtendedTableLength;
+ UINT32 ExtendedTableCount;
+ CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
+ CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
+ BOOLEAN CorrectMicrocode;
+
+ //
+ // Check HeaderVersion
+ //
+ MicrocodeEntryPoint = Image;
+ if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");
+ }
+ return EFI_INCOMPATIBLE_VERSION;
+ }
+ //
+ // Check LoaderRevision
+ //
+ if (MicrocodeEntryPoint->LoaderRevision != 0x1) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");
+ }
+ return EFI_INCOMPATIBLE_VERSION;
+ }
+ //
+ // Check Size
+ //
+ if (MicrocodeEntryPoint->DataSize == 0) {
+ TotalSize = 2048;
+ } else {
+ TotalSize = MicrocodeEntryPoint->TotalSize;
+ }
+ if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
+ }
+ return EFI_VOLUME_CORRUPTED;
+ }
+ if (TotalSize != ImageSize) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on TotalSize\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
+ }
+ return EFI_VOLUME_CORRUPTED;
+ }
+ //
+ // Check CheckSum32
+ //
+ if (MicrocodeEntryPoint->DataSize == 0) {
+ DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);
+ } else {
+ DataSize = MicrocodeEntryPoint->DataSize;
+ }
+ if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
+ }
+ return EFI_VOLUME_CORRUPTED;
+ }
+ if ((DataSize & 0x3) != 0) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize not aligned\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
+ }
+ return EFI_VOLUME_CORRUPTED;
+ }
+ CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));
+ if (CheckSum32 != 0) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");
+ }
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Check ProcessorSignature/ProcessorFlags
+ //
+
+ ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);
+ if (ProcessorInfo == NULL) {
+ CorrectMicrocode = FALSE;
+ ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));
+ if (ExtendedTableLength != 0) {
+ //
+ // Extended Table exist, check if the CPU in support list
+ //
+ ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER));
+ //
+ // Calculate Extended Checksum
+ //
+ if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) != 0)) {
+ CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
+ if (CheckSum32 == 0) {
+ //
+ // Checksum correct
+ //
+ ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
+ if (ExtendedTableCount <= (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {
+ ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
+ for (Index = 0; Index < ExtendedTableCount; Index++) {
+ CheckSum32 = CalculateSum32((UINT32 *)ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));
+ if (CheckSum32 == 0) {
+ //
+ // Verify Header
+ //
+ ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);
+ if (ProcessorInfo != NULL) {
+ //
+ // Find one
+ //
+ CorrectMicrocode = TRUE;
+ break;
+ }
+ }
+ ExtendedTable++;
+ }
+ }
+ }
+ }
+ }
+ if (!CorrectMicrocode) {
+ if (TryLoad) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));
+ }
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");
+ }
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Check UpdateRevision
+ //
+ CurrentRevision = ProcessorInfo->MicrocodeRevision;
+ if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||
+ (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {
+ if (TryLoad) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));
+ }
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");
+ }
+ return EFI_INCOMPATIBLE_VERSION;
+ }
+
+ //
+ // try load MCU
+ //
+ if (TryLoad) {
+ CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));
+ if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {
+ DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;
+ if (AbortReason != NULL) {
+ *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");
+ }
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get next Microcode entrypoint.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] MicrocodeEntryPoint Current Microcode entrypoint
+
+ @return next Microcode entrypoint.
+**/
+CPU_MICROCODE_HEADER *
+GetNextMicrocode (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+ if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {
+ if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {
+ // it is last one
+ return NULL;
+ } else {
+ // return next one
+ return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;
+ }
+ }
+ }
+
+ ASSERT(FALSE);
+ return NULL;
+}
+
+/**
+ Get current Microcode used region size.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+
+ @return current Microcode used region size.
+**/
+UINTN
+GetCurrentMicrocodeUsedRegionSize (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+ )
+{
+ if (MicrocodeFmpPrivate->DescriptorCount == 0) {
+ return 0;
+ }
+
+ return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint
+ + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize
+ - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;
+}
+
+/**
+ Update Microcode.
+
+ @param[in] Address The flash address of Microcode.
+ @param[in] Image The Microcode image buffer.
+ @param[in] ImageSize The size of Microcode image buffer in bytes.
+ @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The Microcode image is updated.
+ @retval EFI_WRITE_PROTECTED The flash device is read only.
+**/
+EFI_STATUS
+UpdateMicrocode (
+ IN UINT64 Address,
+ IN VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *LastAttemptStatus
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG((DEBUG_INFO, "PlatformUpdate:"));
+ DEBUG((DEBUG_INFO, " Address - 0x%lx,", Address));
+ DEBUG((DEBUG_INFO, " Legnth - 0x%x\n", ImageSize));
+
+ Status = MicrocodeFlashWrite (
+ Address,
+ Image,
+ ImageSize
+ );
+ if (!EFI_ERROR(Status)) {
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+ } else {
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
+ }
+ return Status;
+}
+
+/**
+ Update Microcode flash region.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated
+ @param[in] Image The Microcode image buffer.
+ @param[in] ImageSize The size of Microcode image buffer in bytes.
+ @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The Microcode image is written.
+ @retval EFI_WRITE_PROTECTED The flash device is read only.
+**/
+EFI_STATUS
+UpdateMicrocodeFlashRegion (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,
+ IN VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *LastAttemptStatus
+ )
+{
+ VOID *MicrocodePatchAddress;
+ UINTN MicrocodePatchRegionSize;
+ UINTN TargetTotalSize;
+ UINTN UsedRegionSize;
+ EFI_STATUS Status;
+ VOID *MicrocodePatchScratchBuffer;
+ UINT8 *ScratchBufferPtr;
+ UINTN ScratchBufferSize;
+ UINTN RestSize;
+ UINTN AvailableSize;
+ VOID *NextMicrocodeEntryPoint;
+ MICROCODE_INFO *MicrocodeInfo;
+ UINTN MicrocodeCount;
+ UINTN Index;
+
+ DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));
+
+ MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+ MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+ MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);
+ if (MicrocodePatchScratchBuffer == NULL) {
+ DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ScratchBufferPtr = MicrocodePatchScratchBuffer;
+ ScratchBufferSize = 0;
+
+ //
+ // Target data collection
+ //
+ TargetTotalSize = 0;
+ AvailableSize = 0;
+ NextMicrocodeEntryPoint = NULL;
+ if (TargetMicrocodeEntryPoint != NULL) {
+ if (TargetMicrocodeEntryPoint->DataSize == 0) {
+ TargetTotalSize = 2048;
+ } else {
+ TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;
+ }
+ DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));
+ NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);
+ DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));
+ if (NextMicrocodeEntryPoint != NULL) {
+ ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
+ AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;
+ } else {
+ AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;
+ }
+ DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));
+ }
+ ASSERT (AvailableSize >= TargetTotalSize);
+ UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);
+ DEBUG((DEBUG_INFO, " UsedRegionSize - 0x%x\n", UsedRegionSize));
+ ASSERT (UsedRegionSize >= TargetTotalSize);
+ if (TargetMicrocodeEntryPoint != NULL) {
+ ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
+ }
+ //
+ // Total Size means the Microcode data size.
+ // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.
+ //
+ // (1)
+ // +------+-----------+-----+------+===================+
+ // | MCU1 | Microcode | PAD | MCU2 | Empty |
+ // +------+-----------+-----+------+===================+
+ // | TotalSize |
+ // |<-AvailableSize->|
+ // |<- UsedRegionSize ->|
+ //
+ // (2)
+ // +------+-----------+===================+
+ // | MCU | Microcode | Empty |
+ // +------+-----------+===================+
+ // | TotalSize |
+ // |<- AvailableSize ->|
+ // |<-UsedRegionSize->|
+ //
+
+ //
+ // Update based on policy
+ //
+
+ //
+ // 1. If there is enough space to update old one in situ, replace old microcode in situ.
+ //
+ if (AvailableSize >= ImageSize) {
+ DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));
+ //
+ // +------+------------+------+===================+
+ // |Other1| Old Image |Other2| Empty |
+ // +------+------------+------+===================+
+ //
+ // +------+---------+--+------+===================+
+ // |Other1|New Image|FF|Other2| Empty |
+ // +------+---------+--+------+===================+
+ //
+ // 1.1. Copy new image
+ CopyMem (ScratchBufferPtr, Image, ImageSize);
+ ScratchBufferSize += ImageSize;
+ ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+ // 1.2. Pad 0xFF
+ RestSize = AvailableSize - ImageSize;
+ if (RestSize > 0) {
+ SetMem (ScratchBufferPtr, RestSize, 0xFF);
+ ScratchBufferSize += RestSize;
+ ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+ }
+ Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+ return Status;
+ }
+
+ //
+ // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.
+ //
+ if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {
+ if (TargetMicrocodeEntryPoint == NULL) {
+ DEBUG((DEBUG_INFO, "Append new microcode\n"));
+ //
+ // +------+------------+------+===================+
+ // |Other1| Other |Other2| Empty |
+ // +------+------------+------+===================+
+ //
+ // +------+------------+------+-----------+=======+
+ // |Other1| Other |Other2| New Image | Empty |
+ // +------+------------+------+-----------+=======+
+ //
+ Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);
+ } else {
+ DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));
+ //
+ // +------+------------+------+===================+
+ // |Other1| Old Image |Other2| Empty |
+ // +------+------------+------+===================+
+ //
+ // +------+---------------+------+================+
+ // |Other1| New Image |Other2| Empty |
+ // +------+---------------+------+================+
+ //
+ // 2.1. Copy new image
+ CopyMem (ScratchBufferPtr, Image, ImageSize);
+ ScratchBufferSize += ImageSize;
+ ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+ // 2.2. Copy rest images after the old image.
+ if (NextMicrocodeEntryPoint != 0) {
+ RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);
+ CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);
+ ScratchBufferSize += RestSize;
+ ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+ }
+ Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+ }
+ return Status;
+ }
+
+ //
+ // 3. The new image can be put in MCU region, but not all others can be put.
+ // So all the unused MCU is removed.
+ //
+ if (MicrocodePatchRegionSize >= ImageSize) {
+ //
+ // +------+------------+------+===================+
+ // |Other1| Old Image |Other2| Empty |
+ // +------+------------+------+===================+
+ //
+ // +-------------------------------------+--------+
+ // | New Image | Other |
+ // +-------------------------------------+--------+
+ //
+ DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));
+
+ MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;
+ MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
+
+ // 3.1. Copy new image
+ CopyMem (ScratchBufferPtr, Image, ImageSize);
+ ScratchBufferSize += ImageSize;
+ ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+ // 3.2. Copy some others to rest buffer
+ for (Index = 0; Index < MicrocodeCount; Index++) {
+ if (!MicrocodeInfo[Index].InUse) {
+ continue;
+ }
+ if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {
+ continue;
+ }
+ if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {
+ CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);
+ ScratchBufferSize += MicrocodeInfo[Index].TotalSize;
+ ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+ }
+ }
+ // 3.3. Pad 0xFF
+ RestSize = MicrocodePatchRegionSize - ScratchBufferSize;
+ if (RestSize > 0) {
+ SetMem (ScratchBufferPtr, RestSize, 0xFF);
+ ScratchBufferSize += RestSize;
+ ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+ }
+ Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+ return Status;
+ }
+
+ //
+ // 4. The new image size is bigger than the whole MCU region.
+ //
+ DEBUG((DEBUG_ERROR, "Microcode too big\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+ Status = EFI_OUT_OF_RESOURCES;
+
+ return Status;
+}
+
+/**
+ Write Microcode.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] Image The Microcode image buffer.
+ @param[in] ImageSize The size of Microcode image buffer in bytes.
+ @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
+ details for the aborted operation. The buffer is allocated by this function
+ with AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+
+ @retval EFI_SUCCESS The Microcode image is written.
+ @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
+ @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
+ @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
+ @retval EFI_WRITE_PROTECTED The flash device is read only.
+**/
+EFI_STATUS
+MicrocodeWrite (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *LastAttemptVersion,
+ OUT UINT32 *LastAttemptStatus,
+ OUT CHAR16 **AbortReason
+ )
+{
+ EFI_STATUS Status;
+ VOID *AlignedImage;
+ CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint;
+ UINTN TargetCpuIndex;
+ UINTN TargetMicrcodeIndex;
+
+ //
+ // MCU must be 16 bytes aligned
+ //
+ AlignedImage = AllocateCopyPool(ImageSize, Image);
+ if (AlignedImage == NULL) {
+ DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;
+ TargetCpuIndex = (UINTN)-1;
+ Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));
+ FreePool(AlignedImage);
+ return Status;
+ }
+ DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));
+
+ DEBUG((DEBUG_INFO, " TargetCpuIndex - 0x%x\n", TargetCpuIndex));
+ ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
+ TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;
+ DEBUG((DEBUG_INFO, " TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));
+ if (TargetMicrcodeIndex != (UINTN)-1) {
+ ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);
+ TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;
+ } else {
+ TargetMicrocodeEntryPoint = NULL;
+ }
+ DEBUG((DEBUG_INFO, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));
+
+ Status = UpdateMicrocodeFlashRegion(
+ MicrocodeFmpPrivate,
+ TargetMicrocodeEntryPoint,
+ AlignedImage,
+ ImageSize,
+ LastAttemptStatus
+ );
+
+ FreePool(AlignedImage);
+
+ return Status;
+}
+
+
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
new file mode 100644
index 0000000000..9dc306324e
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
@@ -0,0 +1,494 @@
+/** @file
+ Microcode update header file.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ 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.
+
+**/
+
+#ifndef _MICROCODE_FMP_H_
+#define _MICROCODE_FMP_H_
+
+#include <PiDxe.h>
+
+#include <Guid/SystemResourceTable.h>
+#include <Guid/MicrocodeFmp.h>
+
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/MpService.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HobLib.h>
+#include <Library/MicrocodeFlashAccessLib.h>
+
+#include <Register/Cpuid.h>
+#include <Register/Msr.h>
+#include <Register/Microcode.h>
+
+#define MICROCODE_FMP_PRIVATE_DATA_SIGNATURE SIGNATURE_32('M', 'C', 'U', 'F')
+
+//
+// Microcode FMP private data structure.
+//
+
+typedef struct {
+ UINT32 LastAttemptVersion;
+ UINT32 LastAttemptStatus;
+} MICROCODE_FMP_LAST_ATTEMPT_VARIABLE;
+
+typedef struct {
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
+ UINTN TotalSize;
+ BOOLEAN InUse;
+} MICROCODE_INFO;
+
+typedef struct {
+ UINTN CpuIndex;
+ UINT32 ProcessorSignature;
+ UINT8 PlatformId;
+ UINT32 MicrocodeRevision;
+ UINTN MicrocodeIndex;
+} PROCESSOR_INFO;
+
+typedef struct {
+ UINT64 Address;
+ UINT32 Revision;
+} MICROCODE_LOAD_BUFFER;
+
+struct _MICROCODE_FMP_PRIVATE_DATA {
+ UINT32 Signature;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL Fmp;
+ EFI_HANDLE Handle;
+ VOID *MicrocodePatchAddress;
+ UINTN MicrocodePatchRegionSize;
+ UINT8 DescriptorCount;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor;
+ MICROCODE_INFO *MicrocodeInfo;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+ MICROCODE_FMP_LAST_ATTEMPT_VARIABLE LastAttempt;
+ EFI_MP_SERVICES_PROTOCOL *MpService;
+ UINTN BspIndex;
+ UINTN ProcessorCount;
+ PROCESSOR_INFO *ProcessorInfo;
+};
+
+typedef struct _MICROCODE_FMP_PRIVATE_DATA MICROCODE_FMP_PRIVATE_DATA;
+
+#define MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME L"MicrocodeLastAttempVar"
+
+/**
+ Returns a pointer to the MICROCODE_FMP_PRIVATE_DATA structure from the input a as Fmp.
+
+ If the signatures matches, then a pointer to the data structure that contains
+ a specified field of that data structure is returned.
+
+ @param a Pointer to the field specified by ServiceBinding within
+ a data structure of type MICROCODE_FMP_PRIVATE_DATA.
+
+**/
+#define MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(a) \
+ CR ( \
+ (a), \
+ MICROCODE_FMP_PRIVATE_DATA, \
+ Fmp, \
+ MICROCODE_FMP_PRIVATE_DATA_SIGNATURE \
+ )
+
+/**
+ Get Microcode Region.
+
+ @param[out] MicrocodePatchAddress The address of Microcode
+ @param[out] MicrocodePatchRegionSize The region size of Microcode
+
+ @retval TRUE The Microcode region is returned.
+ @retval FALSE No Microcode region.
+**/
+BOOLEAN
+GetMicrocodeRegion (
+ OUT VOID **MicrocodePatchAddress,
+ OUT UINTN *MicrocodePatchRegionSize
+ );
+
+/**
+ Collect processor information.
+ The function prototype for invoking a function on an Application Processor.
+
+ @param[in,out] Buffer The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+CollectProcessorInfo (
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Get current Microcode information.
+
+ The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
+ in MicrocodeFmpPrivate must be initialized.
+
+ The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
+ in MicrocodeFmpPrivate may not be avaiable in this function.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.
+ @param[out] ImageDescriptor Microcode ImageDescriptor
+ @param[out] MicrocodeInfo Microcode information
+
+ @return Microcode count
+**/
+UINTN
+GetMicrocodeInfo (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN UINTN DescriptorCount, OPTIONAL
+ OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL
+ OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL
+ );
+
+/**
+ Verify Microcode.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] Image The Microcode image buffer.
+ @param[in] ImageSize The size of Microcode image buffer in bytes.
+ @param[in] TryLoad Try to load Microcode or not.
+ @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
+ details for the aborted operation. The buffer is allocated by this function
+ with AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+ @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
+ On output, the index of target CPU which matches the Microcode.
+
+ @retval EFI_SUCCESS The Microcode image passes verification.
+ @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
+ @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
+ @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.
+ @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
+**/
+EFI_STATUS
+VerifyMicrocode (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN VOID *Image,
+ IN UINTN ImageSize,
+ IN BOOLEAN TryLoad,
+ OUT UINT32 *LastAttemptStatus,
+ OUT CHAR16 **AbortReason, OPTIONAL
+ IN OUT UINTN *TargetCpuIndex OPTIONAL
+ );
+
+/**
+ Write Microcode.
+
+ @param[in] MicrocodeFmpPrivate The Microcode driver private data
+ @param[in] Image The Microcode image buffer.
+ @param[in] ImageSize The size of Microcode image buffer in bytes.
+ @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
+ details for the aborted operation. The buffer is allocated by this function
+ with AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+
+ @retval EFI_SUCCESS The Microcode image is written.
+ @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
+ @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
+ @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
+ @retval EFI_WRITE_PROTECTED The flash device is read only.
+**/
+EFI_STATUS
+MicrocodeWrite (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
+ IN VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *LastAttemptVersion,
+ OUT UINT32 *LastAttemptStatus,
+ OUT CHAR16 **AbortReason
+ );
+
+/**
+ Dump private information.
+
+ @param[in] MicrocodeFmpPrivate private data structure.
+**/
+VOID
+DumpPrivateInfo (
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+ );
+
+/**
+ Returns information about the current firmware image(s) of the device.
+
+ This function allows a copy of the current firmware image to be created and saved.
+ The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in, out] ImageInfoSize A pointer to the size, in bytes, of the ImageInfo buffer.
+ On input, this is the size of the buffer allocated by the caller.
+ On output, it is the size of the buffer returned by the firmware
+ if the buffer was large enough, or the size of the buffer needed
+ to contain the image(s) information if the buffer was too small.
+ @param[in, out] ImageInfo A pointer to the buffer in which firmware places the current image(s)
+ information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
+ @param[out] DescriptorVersion A pointer to the location in which firmware returns the version number
+ associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] DescriptorCount A pointer to the location in which firmware returns the number of
+ descriptors or firmware images within this device.
+ @param[out] DescriptorSize A pointer to the location in which firmware returns the size, in bytes,
+ of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] PackageVersion A version number that represents all the firmware images in the device.
+ The format is vendor specific and new version must have a greater value
+ than the old version. If PackageVersion is not supported, the value is
+ 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison
+ is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates
+ that package version update is in progress.
+ @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing the
+ package version name. The buffer is allocated by this function with
+ AllocatePool(), and it is the caller's responsibility to free it with a call
+ to FreePool().
+
+ @retval EFI_SUCCESS The device was successfully updated with the new image.
+ @retval EFI_BUFFER_TOO_SMALL The ImageInfo buffer was too small. The current buffer size
+ needed to hold the image(s) information is returned in ImageInfoSize.
+ @retval EFI_INVALID_PARAMETER ImageInfoSize is NULL.
+ @retval EFI_DEVICE_ERROR Valid information could not be returned. Possible corrupted image.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetImageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN OUT UINTN *ImageInfoSize,
+ IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ OUT UINT32 *DescriptorVersion,
+ OUT UINT8 *DescriptorCount,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName
+ );
+
+/**
+ Retrieves a copy of the current firmware image of the device.
+
+ This function allows a copy of the current firmware image to be created and saved.
+ The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
+ The number is between 1 and DescriptorCount.
+ @param[in,out] Image Points to the buffer where the current image is copied to.
+ @param[in,out] ImageSize On entry, points to the size of the buffer pointed to by Image, in bytes.
+ On return, points to the length of the image, in bytes.
+
+ @retval EFI_SUCCESS The device was successfully updated with the new image.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to hold the
+ image. The current buffer size needed to hold the image is returned
+ in ImageSize.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_NOT_FOUND The current image is not copied to the buffer.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN OUT VOID *Image,
+ IN OUT UINTN *ImageSize
+ );
+
+/**
+ Updates the firmware image of the device.
+
+ This function updates the hardware with the new firmware image.
+ This function returns EFI_UNSUPPORTED if the firmware image is not updatable.
+ If the firmware image is updatable, the function should perform the following minimal validations
+ before proceeding to do the firmware image update.
+ - Validate the image authentication if image has attribute
+ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns
+ EFI_SECURITY_VIOLATION if the validation fails.
+ - Validate the image is a supported image for this device. The function returns EFI_ABORTED if
+ the image is unsupported. The function can optionally provide more detailed information on
+ why the image is not a supported image.
+ - Validate the data from VendorCode if not null. Image validation must be performed before
+ VendorCode data validation. VendorCode data is ignored or considered invalid if image
+ validation failed. The function returns EFI_ABORTED if the data is invalid.
+
+ VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if
+ the caller did not specify the policy or use the default policy. As an example, vendor can implement
+ a policy to allow an option to force a firmware image update when the abort reason is due to the new
+ firmware image version is older than the current firmware image version or bad image checksum.
+ Sensitive operations such as those wiping the entire firmware image and render the device to be
+ non-functional should be encoded in the image itself rather than passed with the VendorCode.
+ AbortReason enables vendor to have the option to provide a more detailed description of the abort
+ reason to the caller.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
+ The number is between 1 and DescriptorCount.
+ @param[in] Image Points to the new image.
+ @param[in] ImageSize Size of the new image in bytes.
+ @param[in] VendorCode This enables vendor to implement vendor-specific firmware image update policy.
+ Null indicates the caller did not specify the policy or use the default policy.
+ @param[in] Progress A function used by the driver to report the progress of the firmware update.
+ @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
+ details for the aborted operation. The buffer is allocated by this function
+ with AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+
+ @retval EFI_SUCCESS The device was successfully updated with the new image.
+ @retval EFI_ABORTED The operation is aborted.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpSetImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
+ OUT CHAR16 **AbortReason
+ );
+
+/**
+ Checks if the firmware image is valid for the device.
+
+ This function allows firmware update application to validate the firmware image without
+ invoking the SetImage() first.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
+ The number is between 1 and DescriptorCount.
+ @param[in] Image Points to the new image.
+ @param[in] ImageSize Size of the new image in bytes.
+ @param[out] ImageUpdatable Indicates if the new image is valid for update. It also provides,
+ if available, additional information if the image is invalid.
+
+ @retval EFI_SUCCESS The image was successfully checked.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpCheckImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *ImageUpdatable
+ );
+
+/**
+ Returns information about the firmware package.
+
+ This function returns package information.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[out] PackageVersion A version number that represents all the firmware images in the device.
+ The format is vendor specific and new version must have a greater value
+ than the old version. If PackageVersion is not supported, the value is
+ 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version
+ comparison is to be performed using PackageVersionName. A value of
+ 0xFFFFFFFD indicates that package version update is in progress.
+ @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing
+ the package version name. The buffer is allocated by this function with
+ AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+ @param[out] PackageVersionNameMaxLen The maximum length of package version name if device supports update of
+ package version name. A value of 0 indicates the device does not support
+ update of package version name. Length is the number of Unicode characters,
+ including the terminating null character.
+ @param[out] AttributesSupported Package attributes that are supported by this device. See 'Package Attribute
+ Definitions' for possible returned values of this parameter. A value of 1
+ indicates the attribute is supported and the current setting value is
+ indicated in AttributesSetting. A value of 0 indicates the attribute is not
+ supported and the current setting value in AttributesSetting is meaningless.
+ @param[out] AttributesSetting Package attributes. See 'Package Attribute Definitions' for possible returned
+ values of this parameter
+
+ @retval EFI_SUCCESS The package information was successfully returned.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName,
+ OUT UINT32 *PackageVersionNameMaxLen,
+ OUT UINT64 *AttributesSupported,
+ OUT UINT64 *AttributesSetting
+ );
+
+/**
+ Updates information about the firmware package.
+
+ This function updates package information.
+ This function returns EFI_UNSUPPORTED if the package information is not updatable.
+ VendorCode enables vendor to implement vendor-specific package information update policy.
+ Null if the caller did not specify this policy or use the default policy.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] Image Points to the authentication image.
+ Null if authentication is not required.
+ @param[in] ImageSize Size of the authentication image in bytes.
+ 0 if authentication is not required.
+ @param[in] VendorCode This enables vendor to implement vendor-specific firmware
+ image update policy.
+ Null indicates the caller did not specify this policy or use
+ the default policy.
+ @param[in] PackageVersion The new package version.
+ @param[in] PackageVersionName A pointer to the new null-terminated Unicode string representing
+ the package version name.
+ The string length is equal to or less than the value returned in
+ PackageVersionNameMaxLen.
+
+ @retval EFI_SUCCESS The device was successfully updated with the new package
+ information.
+ @retval EFI_INVALID_PARAMETER The PackageVersionName length is longer than the value
+ returned in PackageVersionNameMaxLen.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpSetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN UINT32 PackageVersion,
+ IN CONST CHAR16 *PackageVersionName
+ );
+
+#endif
+
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf
new file mode 100644
index 0000000000..55797cf132
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf
@@ -0,0 +1,71 @@
+## @file
+# Microcode FMP update driver.
+#
+# Produce FMP instance to update Microcode.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# 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 = 0x00010005
+ BASE_NAME = MicrocodeUpdateDxe
+ MODULE_UNI_FILE = MicrocodeUpdateDxe.uni
+ FILE_GUID = 0565365C-2FE1-4F88-B3BE-624C04623A20
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MicrocodeFmpMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ MicrocodeUpdate.h
+ MicrocodeFmp.c
+ MicrocodeUpdate.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ UefiLib
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ MicrocodeFlashAccessLib
+
+[Guids]
+ gMicrocodeFmpImageTypeIdGuid ## CONSUMES ## GUID
+
+[Protocols]
+ gEfiFirmwareManagementProtocolGuid ## PRODUCES
+ gEfiMpServiceProtocolGuid ## CONSUMES
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES
+
+[Depex]
+ gEfiVariableArchProtocolGuid AND
+ gEfiMpServiceProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ MicrocodeUpdateDxeExtra.uni
+
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni
new file mode 100644
index 0000000000..1b0d4941dc
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Microcode FMP update driver.
+//
+// Produce FMP instance to update Microcode.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Microcode FMP update driver."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Produce FMP instance to update Microcode."
diff --git a/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni
new file mode 100644
index 0000000000..b667f12f5c
--- /dev/null
+++ b/Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// MicrocodeUpdateDxe Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"MicrocodeUpdate DXE Driver"
+
+