From 38c2cbb9354d7f58e48f9f649f23eb9bd0d3cfca Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Thu, 27 Apr 2017 11:22:26 +0800 Subject: UefiCpuPkg: Move to new location Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../MicrocodeFlashAccessLibNull.c | 42 + .../MicrocodeFlashAccessLibNull.inf | 40 + .../MicrocodeFlashAccessLibNull.uni | 21 + .../MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc | 33 + .../MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf | 32 + .../Feature/Capsule/MicrocodeCapsulePdb/Readme.md | 20 + .../MicrocodeCapsuleTxt/Microcode/Microcode.inf | 27 + .../MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc | 39 + .../MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf | 32 + .../Feature/Capsule/MicrocodeCapsuleTxt/Readme.md | 33 + .../Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c | 748 ++++++++++++++++ .../Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c | 981 +++++++++++++++++++++ .../Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h | 494 +++++++++++ .../MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf | 71 ++ .../MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni | 21 + .../MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni | 20 + 16 files changed, 2654 insertions(+) create mode 100644 Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.c create mode 100644 Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf create mode 100644 Core/UefiCpuPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.uni create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsulePdb/Readme.md create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Microcode/Microcode.inf create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeCapsuleTxt/Readme.md create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni create mode 100644 Core/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni (limited to 'Core/UefiCpuPkg/Feature') 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.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include + +/** + 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.
+# 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.
+// +// 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.
+# +# 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 = + PLATFORM_GUID = 6875FD33-602E-4EF9-9DF2-8BA7D8B7A7AF + PLATFORM_VERSION = 0.1 +# +# Uncomment the following line and update with your platform pkg name +# +# FLASH_DEFINITION = /MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf +# +# Uncomment the following line and update with your platform pkg name +# +# OUTPUT_DIRECTORY = Build/ + 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.
+# +# 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)//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 `/MicrocodeUpdatePdb`. + +2) Uncomment and update `FILE DATA` statement in `/MicrocodeUpdatePdb/MicrocodeCapsulePdb.fdf` with path to a Microcode PDB file. The PDB file can placed in `/MicrocodeUpdatePdb` or any other path. + +`FILE DATA = ` + +Uncomment and update `PLATFORM_NAME`, `FLASH_DEFINITION`, `OUTPUT_DIRECTORY` section in `/MicrocodeUpdatePdb/MicrocodeCapsulePdb.dsc` with . + + PLATFORM_NAME = + FLASH_DEFINITION = /MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf + OUTPUT_DIRECTORY = Build/ + +3) Use EDK II build tools to generate the Microcode FMP Capsule + +`build -p /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.
+# 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.
+# +# 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 = + PLATFORM_GUID = 6875FD33-602E-4EF9-9DF2-8BA7D8B7A7AF + PLATFORM_VERSION = 0.1 +# +# Uncomment the following line and update with your platform pkg name +# +# FLASH_DEFINITION = /MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf +# +# Uncomment the following line and update with your platform pkg name +# +# OUTPUT_DIRECTORY = Build/ + SUPPORTED_ARCHITECTURES = IA32|X64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + +[Components] +# +# Uncomment the following line and update with path to Microcode INF file +# +# /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.
+# +# 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 `/MicrocodeUpdateTxt` + +2) Copy microcode TXT file to`/MicrocodeUpdateTxt/Microcode` + +3) Uncomment and update statement in `[Sources]` section of `/MicrocodeUpdateTxt/Microcode/Microcode.inf` with name of Microcode TXT file copied in previous step. + + [Sources] + + +Uncomment and update `FILE DATA` statement in `/MicrocodeUpdateTxt/MicrocodeCapsuleTxt.fdf` with path to a Microcode MCB file. The MCB file is placed in `$(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/IA32//MicrocodeUpdateTxt/Microcode/Microcode/OUTPUT/`. + +`FILE DATA = ` + +Uncomment and update `PLATFORM_NAME`, `FLASH_DEFINITION`, `OUTPUT_DIRECTORY` section in `/MicrocodeUpdateTxt/MicrocodeCapsuleTxt.dsc` with . + + PLATFORM_NAME = + FLASH_DEFINITION = /MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf + OUTPUT_DIRECTORY = Build/ + +Uncomment and update statement in `Components` section of `/MicrocodeUpdateTxt/MicrocodeCapsuleTxt.dsc` with path to a Microcode INF file. + + [Components] + + +4) Use EDK II build tools to generate the Microcode FMP Capsule + +`build -p /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.
+ 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.
+ 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.
+ 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 + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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.
+# 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.
+// +// 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.
+// +// 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" + + -- cgit v1.2.3