From 882668595c32e9e0adeaaf0bd0062f88b464fc18 Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Wed, 21 Sep 2016 11:15:03 +0800 Subject: [PATCH] UefiCpuPkg/MicrocodeUpdate: Add MicrocodeUpdate component. MicrocodeUpdate supports update Microcode region via UEFI FMP capsule. MicrocodeUpdate SetImage() will perform the Microcode version, ProcessorSignature/ProcessorFlag, and try to load microcode. If and only if the Microcode is loaded successfully, and new Microcode will be updated to system flash region. Cc: Jeff Fan Cc: Feng Tian Cc: Star Zeng Cc: Michael D Kinney Cc: Liming Gao Cc: Chao Zhang Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao Reviewed-by: Jeff Fan Reviewed-by: Michael Kinney --- .../Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c | 537 ++++++++++++ .../MicrocodeUpdateDxe/MicrocodeUpdate.c | 784 ++++++++++++++++++ .../MicrocodeUpdateDxe/MicrocodeUpdate.h | 403 +++++++++ .../MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf | 68 ++ .../MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni | 21 + .../MicrocodeUpdateDxeExtra.uni | 20 + 6 files changed, 1833 insertions(+) create mode 100644 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c create mode 100644 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c create mode 100644 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h create mode 100644 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf create mode 100644 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni create mode 100644 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c new file mode 100644 index 0000000000..df3563d879 --- /dev/null +++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c @@ -0,0 +1,537 @@ +/** @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; + EFI_STATUS Status; + + 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; + } + + Status = MicrocodeRead(ImageIndex, (VOID *)Image, ImageSize); + return Status; +} + +/** + 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(ImageIndex, (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); + } + + 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 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(NULL, 0); + + if (CurrentMicrocodeCount > MicrocodeFmpPrivate->DescriptorCount) { + if (MicrocodeFmpPrivate->ImageDescriptor != NULL) { + FreePool(MicrocodeFmpPrivate->ImageDescriptor); + MicrocodeFmpPrivate->ImageDescriptor = NULL; + } + } else { + ZeroMem(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR)); + } + + 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; + } + } + + CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->DescriptorCount); + ASSERT(CurrentMicrocodeCount == MicrocodeFmpPrivate->DescriptorCount); + + return EFI_SUCCESS; +} + +/** + 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; + + 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)); + + Status = InitializeMicrocodeDescriptor(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/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c new file mode 100644 index 0000000000..2b2d3acb6c --- /dev/null +++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c @@ -0,0 +1,784 @@ +/** @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 UINT64 *MicrocodePatchAddress, + OUT UINT64 *MicrocodePatchRegionSize + ) +{ + *MicrocodePatchAddress = PcdGet64(PcdCpuMicrocodePatchAddress); + *MicrocodePatchRegionSize = PcdGet64(PcdCpuMicrocodePatchRegionSize); + + if ((*MicrocodePatchAddress == 0) || (*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(); +} + +/** + Get current Microcode information. + + @param[out] ImageDescriptor Microcode ImageDescriptor + @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated. + + @return Microcode count +**/ +UINTN +GetMicrocodeInfo ( + OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL + IN UINTN DescriptorCount OPTIONAL + ) +{ + BOOLEAN Result; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN TotalSize; + UINTN Count; + UINT64 ImageAttributes; + UINT32 CurrentRevision; + + Result = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); + if (!Result) { + DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); + return 0; + } + DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress, MicrocodePatchRegionSize)); + + Count = 0; + CurrentRevision = GetCurrentMicrocodeSignature(); + + 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; + } + + 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 (CurrentRevision == MicrocodeEntryPoint->UpdateRevision) { + 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; + } + } 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; +} + +/** + Read Microcode. + + @param[in] ImageIndex The index of Microcode image. + @param[in, out] Image The Microcode image buffer. + @param[in, out] ImageSize The size of Microcode image buffer in bytes. + + @retval EFI_SUCCESS The Microcode image is read. + @retval EFI_NOT_FOUND The Microcode image is not found. +**/ +EFI_STATUS +MicrocodeRead ( + IN UINTN ImageIndex, + IN OUT VOID *Image, + IN OUT UINTN *ImageSize + ) +{ + BOOLEAN Result; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN TotalSize; + UINTN Count; + + Result = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); + if (!Result) { + DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); + return EFI_NOT_FOUND; + } + DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\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; + } + + } 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 EFI_NOT_FOUND; +} + +/** + Verify Microcode. + + Caution: This function may receive untrusted input. + + @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(). + + @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 VOID *Image, + IN UINTN ImageSize, + IN BOOLEAN TryLoad, + OUT UINT32 *LastAttemptStatus, + OUT CHAR16 **AbortReason + ) +{ + UINTN Index; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN TotalSize; + UINTN DataSize; + UINT32 CurrentRevision; + UINT32 CurrentProcessorSignature; + UINT8 CurrentPlatformId; + 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 + // + CorrectMicrocode = FALSE; + CurrentProcessorSignature = GetCurrentProcessorSignature(); + CurrentPlatformId = GetCurrentPlatformId(); + if ((MicrocodeEntryPoint->ProcessorSignature.Uint32 != CurrentProcessorSignature) || + ((MicrocodeEntryPoint->ProcessorFlags & (1 << CurrentPlatformId)) == 0)) { + 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 + // + if ((ExtendedTable->ProcessorSignature.Uint32 == CurrentProcessorSignature) && + (ExtendedTable->ProcessorFlag & (1 << CurrentPlatformId))) { + // + // Find one + // + CorrectMicrocode = TRUE; + break; + } + } + ExtendedTable++; + } + } + } + } + } + if (!CorrectMicrocode) { + DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n")); + *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION; + if (AbortReason != NULL) { + if (MicrocodeEntryPoint->ProcessorSignature.Uint32 != CurrentProcessorSignature) { + *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature"), L"UnsupportedProcessSignature"); + } else { + *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessorFlags"), L"UnsupportedProcessorFlags"); + } + } + return EFI_UNSUPPORTED; + } + } + + // + // Check UpdateRevision + // + CurrentRevision = GetCurrentMicrocodeSignature(); + if (MicrocodeEntryPoint->UpdateRevision < CurrentRevision) { + 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 = LoadMicrocode((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 current Microcode in used. + + @return current Microcode in used. +**/ +VOID * +GetCurrentMicrocodeInUse ( + VOID + ) +{ + BOOLEAN Result; + EFI_STATUS Status; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN TotalSize; + UINTN Count; + UINT32 AttemptStatus; + + Result = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); + if (!Result) { + DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); + return NULL; + } + DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\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; + } + Status = VerifyMicrocode(MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL); + if (!EFI_ERROR(Status)) { + return MicrocodeEntryPoint; + } + + } 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 NULL; +} + +/** + Get current Microcode used region size. + + @return current Microcode used region size. +**/ +UINTN +GetCurrentMicrocodeUsedRegionSize ( + VOID + ) +{ + BOOLEAN Result; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN TotalSize; + UINTN Count; + UINTN MicrocodeUsedEnd; + + Result = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); + if (!Result) { + DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); + return 0; + } + DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress, MicrocodePatchRegionSize)); + + MicrocodeUsedEnd = (UINTN)MicrocodePatchAddress; + 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; + } + + } 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); + MicrocodeUsedEnd = (UINTN)MicrocodeEntryPoint; + + // + // Get the next patch. + // + MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + TotalSize); + } while (((UINTN)MicrocodeEntryPoint < MicrocodeEnd)); + + return MicrocodeUsedEnd - (UINTN)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; +} + +/** + Write Microcode. + + Caution: This function may receive untrusted input. + + @param[in] ImageIndex The index of Microcode image. + @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 UINTN ImageIndex, + IN VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *LastAttemptVersion, + OUT UINT32 *LastAttemptStatus, + OUT CHAR16 **AbortReason + ) +{ + BOOLEAN Result; + EFI_STATUS Status; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *CurrentMicrocodeEntryPoint; + UINTN CurrentTotalSize; + UINTN UsedRegionSize; + VOID *AlignedImage; + + Result = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); + if (!Result) { + DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); + return EFI_NOT_FOUND; + } + + CurrentTotalSize = 0; + CurrentMicrocodeEntryPoint = GetCurrentMicrocodeInUse(); + if (CurrentMicrocodeEntryPoint != NULL) { + if (CurrentMicrocodeEntryPoint->DataSize == 0) { + CurrentTotalSize = 2048; + } else { + CurrentTotalSize = CurrentMicrocodeEntryPoint->TotalSize; + } + } + + // + // 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; + Status = VerifyMicrocode(AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n")); + FreePool(AlignedImage); + return Status; + } + DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n")); + + if (CurrentTotalSize < ImageSize) { + UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(); + if (MicrocodePatchRegionSize - UsedRegionSize >= ImageSize) { + // + // Append + // + DEBUG((DEBUG_INFO, "Append new microcode\n")); + Status = UpdateMicrocode(MicrocodePatchAddress + UsedRegionSize, AlignedImage, ImageSize, LastAttemptStatus); + } else if (MicrocodePatchRegionSize >= ImageSize) { + // + // Ignor all others and just add this one from beginning. + // + DEBUG((DEBUG_INFO, "Add new microcode from beginning\n")); + Status = UpdateMicrocode(MicrocodePatchAddress, AlignedImage, ImageSize, LastAttemptStatus); + } else { + DEBUG((DEBUG_ERROR, "Microcode too big\n")); + *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + } + } else { + // + // Replace + // + DEBUG((DEBUG_INFO, "Replace old microcode\n")); + Status = UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, AlignedImage, ImageSize, LastAttemptStatus); + } + + FreePool(AlignedImage); + + return Status; +} + + diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h new file mode 100644 index 0000000000..77e8441955 --- /dev/null +++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h @@ -0,0 +1,403 @@ +/** @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 + +#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; + +struct _MICROCODE_FMP_PRIVATE_DATA { + UINT32 Signature; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL Fmp; + EFI_HANDLE Handle; + UINT8 DescriptorCount; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + MICROCODE_FMP_LAST_ATTEMPT_VARIABLE LastAttempt; +}; + +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 current Microcode information. + + @param[out] ImageDescriptor Microcode ImageDescriptor + @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated. + + @return Microcode count +**/ +UINTN +GetMicrocodeInfo ( + OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL + IN UINTN DescriptorCount OPTIONAL + ); + +/** + Read Microcode. + + @param[in] ImageIndex The index of Microcode image. + @param[in, out] Image The Microcode image buffer. + @param[in, out] ImageSize The size of Microcode image buffer in bytes. + + @retval EFI_SUCCESS The Microcode image is read. + @retval EFI_NOT_FOUND The Microcode image is not found. +**/ +EFI_STATUS +MicrocodeRead ( + IN UINTN ImageIndex, + IN OUT VOID *Image, + IN OUT UINTN *ImageSize + ); + +/** + Write Microcode. + + @param[in] ImageIndex The index of Microcode image. + @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 UINTN ImageIndex, + IN VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *LastAttemptVersion, + OUT UINT32 *LastAttemptStatus, + OUT CHAR16 **AbortReason + ); + +/** + 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/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf new file mode 100644 index 0000000000..437d300d7b --- /dev/null +++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf @@ -0,0 +1,68 @@ +## @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] + 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 + +[Protocols] + gEfiFirmwareManagementProtocolGuid ## SOMTIMES_PRODUCE + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES + +[Depex] + gEfiVariableArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + MicrocodeUpdateDxeExtra.uni + diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni new file mode 100644 index 0000000000..1b0d4941dc --- /dev/null +++ b/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/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni new file mode 100644 index 0000000000..b667f12f5c --- /dev/null +++ b/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" + + -- 2.39.2