+++ /dev/null
-/** @file\r
- SetImage instance to update Microcode.\r
-\r
- Caution: This module requires additional review when modified.\r
- This module will have external input - capsule image.\r
- This external input must be validated carefully to avoid security issue like\r
- buffer overflow, integer overflow.\r
-\r
- MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.\r
-\r
- Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "MicrocodeUpdate.h"\r
-\r
-/**\r
- Get Microcode Region.\r
-\r
- @param[out] MicrocodePatchAddress The address of Microcode\r
- @param[out] MicrocodePatchRegionSize The region size of Microcode\r
-\r
- @retval TRUE The Microcode region is returned.\r
- @retval FALSE No Microcode region.\r
-**/\r
-BOOLEAN\r
-GetMicrocodeRegion (\r
- OUT VOID **MicrocodePatchAddress,\r
- OUT UINTN *MicrocodePatchRegionSize\r
- )\r
-{\r
- *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);\r
- *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);\r
-\r
- if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/**\r
- Get Microcode update signature of currently loaded Microcode update.\r
-\r
- @return Microcode signature.\r
-\r
-**/\r
-UINT32\r
-GetCurrentMicrocodeSignature (\r
- VOID\r
- )\r
-{\r
- UINT64 Signature;\r
-\r
- AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);\r
- AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
- Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);\r
- return (UINT32)RShiftU64(Signature, 32);\r
-}\r
-\r
-/**\r
- Get current processor signature.\r
-\r
- @return current processor signature.\r
-**/\r
-UINT32\r
-GetCurrentProcessorSignature (\r
- VOID\r
- )\r
-{\r
- UINT32 RegEax;\r
- AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
- return RegEax;\r
-}\r
-\r
-/**\r
- Get current platform ID.\r
-\r
- @return current platform ID.\r
-**/\r
-UINT8\r
-GetCurrentPlatformId (\r
- VOID\r
- )\r
-{\r
- UINT8 PlatformId;\r
-\r
- PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);\r
- return PlatformId;\r
-}\r
-\r
-/**\r
- Load new Microcode.\r
-\r
- @param[in] Address The address of new Microcode.\r
-\r
- @return Loaded Microcode signature.\r
-\r
-**/\r
-UINT32\r
-LoadMicrocode (\r
- IN UINT64 Address\r
- )\r
-{\r
- AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);\r
- return GetCurrentMicrocodeSignature();\r
-}\r
-\r
-/**\r
- Load Microcode on an Application Processor.\r
- The function prototype for invoking a function on an Application Processor.\r
-\r
- @param[in,out] Buffer The pointer to private data buffer.\r
-**/\r
-VOID\r
-EFIAPI\r
-MicrocodeLoadAp (\r
- IN OUT VOID *Buffer\r
- )\r
-{\r
- MICROCODE_LOAD_BUFFER *MicrocodeLoadBuffer;\r
-\r
- MicrocodeLoadBuffer = Buffer;\r
- MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);\r
-}\r
-\r
-/**\r
- Load new Microcode on this processor\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] CpuIndex The index of the processor.\r
- @param[in] Address The address of new Microcode.\r
-\r
- @return Loaded Microcode signature.\r
-\r
-**/\r
-UINT32\r
-LoadMicrocodeOnThis (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN UINTN CpuIndex,\r
- IN UINT64 Address\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_MP_SERVICES_PROTOCOL *MpService;\r
- MICROCODE_LOAD_BUFFER MicrocodeLoadBuffer;\r
-\r
- if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {\r
- return LoadMicrocode (Address);\r
- } else {\r
- MpService = MicrocodeFmpPrivate->MpService;\r
- MicrocodeLoadBuffer.Address = Address;\r
- MicrocodeLoadBuffer.Revision = 0;\r
- Status = MpService->StartupThisAP (\r
- MpService,\r
- MicrocodeLoadAp,\r
- CpuIndex,\r
- NULL,\r
- 0,\r
- &MicrocodeLoadBuffer,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
- return MicrocodeLoadBuffer.Revision;\r
- }\r
-}\r
-\r
-/**\r
- Collect processor information.\r
- The function prototype for invoking a function on an Application Processor.\r
-\r
- @param[in,out] Buffer The pointer to private data buffer.\r
-**/\r
-VOID\r
-EFIAPI\r
-CollectProcessorInfo (\r
- IN OUT VOID *Buffer\r
- )\r
-{\r
- PROCESSOR_INFO *ProcessorInfo;\r
-\r
- ProcessorInfo = Buffer;\r
- ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();\r
- ProcessorInfo->PlatformId = GetCurrentPlatformId();\r
- ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();\r
-}\r
-\r
-/**\r
- Get current Microcode information.\r
-\r
- The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)\r
- in MicrocodeFmpPrivate must be initialized.\r
-\r
- The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)\r
- in MicrocodeFmpPrivate may not be avaiable in this function.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.\r
- @param[out] ImageDescriptor Microcode ImageDescriptor\r
- @param[out] MicrocodeInfo Microcode information\r
-\r
- @return Microcode count\r
-**/\r
-UINTN\r
-GetMicrocodeInfo (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN UINTN DescriptorCount, OPTIONAL\r
- OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL\r
- OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL\r
- )\r
-{\r
- VOID *MicrocodePatchAddress;\r
- UINTN MicrocodePatchRegionSize;\r
- CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
- UINTN MicrocodeEnd;\r
- UINTN TotalSize;\r
- UINTN Count;\r
- UINT64 ImageAttributes;\r
- BOOLEAN IsInUse;\r
- EFI_STATUS Status;\r
- UINT32 AttemptStatus;\r
- UINTN TargetCpuIndex;\r
-\r
- MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
- MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
-\r
- DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));\r
-\r
- Count = 0;\r
-\r
- MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;\r
- MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
- do {\r
- if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {\r
- //\r
- // It is the microcode header. It is not the padding data between microcode patches\r
- // becasue the padding data should not include 0x00000001 and it should be the repeated\r
- // byte format (like 0xXYXYXYXY....).\r
- //\r
- if (MicrocodeEntryPoint->DataSize == 0) {\r
- TotalSize = 2048;\r
- } else {\r
- TotalSize = MicrocodeEntryPoint->TotalSize;\r
- }\r
-\r
- TargetCpuIndex = (UINTN)-1;\r
- Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);\r
- if (!EFI_ERROR(Status)) {\r
- IsInUse = TRUE;\r
- ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
- MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;\r
- } else {\r
- IsInUse = FALSE;\r
- }\r
-\r
- if (ImageDescriptor != NULL && DescriptorCount > Count) {\r
- ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);\r
- CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);\r
- ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
- ImageDescriptor[Count].ImageIdName = NULL;\r
- ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;\r
- ImageDescriptor[Count].VersionName = NULL;\r
- ImageDescriptor[Count].Size = TotalSize;\r
- ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;\r
- if (IsInUse) {\r
- ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;\r
- }\r
- ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;\r
- ImageDescriptor[Count].AttributesSetting = ImageAttributes;\r
- ImageDescriptor[Count].Compatibilities = 0;\r
- ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback\r
- ImageDescriptor[Count].LastAttemptVersion = 0;\r
- ImageDescriptor[Count].LastAttemptStatus = 0;\r
- ImageDescriptor[Count].HardwareInstance = 0;\r
- }\r
- if (MicrocodeInfo != NULL && DescriptorCount > Count) {\r
- MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;\r
- MicrocodeInfo[Count].TotalSize = TotalSize;\r
- MicrocodeInfo[Count].InUse = IsInUse;\r
- }\r
- } else {\r
- //\r
- // It is the padding data between the microcode patches for microcode patches alignment.\r
- // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
- // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
- // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
- // find the next possible microcode patch header.\r
- //\r
- MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
- continue;\r
- }\r
-\r
- Count++;\r
- ASSERT(Count < 0xFF);\r
-\r
- //\r
- // Get the next patch.\r
- //\r
- MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
- } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
-\r
- return Count;\r
-}\r
-\r
-/**\r
- Return matched processor information.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] ProcessorSignature The processor signature to be matched\r
- @param[in] ProcessorFlags The processor flags to be matched\r
- @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
- On output, the index of target CPU which matches the Microcode.\r
-\r
- @return matched processor information.\r
-**/\r
-PROCESSOR_INFO *\r
-GetMatchedProcessor (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN UINT32 ProcessorSignature,\r
- IN UINT32 ProcessorFlags,\r
- IN OUT UINTN *TargetCpuIndex\r
- )\r
-{\r
- UINTN Index;\r
-\r
- if (*TargetCpuIndex != (UINTN)-1) {\r
- Index = *TargetCpuIndex;\r
- if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
- ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
- return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
- } else {\r
- return NULL;\r
- }\r
- }\r
-\r
- for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {\r
- if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
- ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
- *TargetCpuIndex = Index;\r
- return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
- }\r
- }\r
- return NULL;\r
-}\r
-\r
-/**\r
- Verify Microcode.\r
-\r
- Caution: This function may receive untrusted input.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] Image The Microcode image buffer.\r
- @param[in] ImageSize The size of Microcode image buffer in bytes.\r
- @param[in] TryLoad Try to load Microcode or not.\r
- @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
- @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
- details for the aborted operation. The buffer is allocated by this function\r
- with AllocatePool(), and it is the caller's responsibility to free it with a\r
- call to FreePool().\r
- @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
- On output, the index of target CPU which matches the Microcode.\r
-\r
- @retval EFI_SUCCESS The Microcode image passes verification.\r
- @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupted.\r
- @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.\r
- @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.\r
- @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.\r
-**/\r
-EFI_STATUS\r
-VerifyMicrocode (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN VOID *Image,\r
- IN UINTN ImageSize,\r
- IN BOOLEAN TryLoad,\r
- OUT UINT32 *LastAttemptStatus,\r
- OUT CHAR16 **AbortReason, OPTIONAL\r
- IN OUT UINTN *TargetCpuIndex\r
- )\r
-{\r
- UINTN Index;\r
- CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
- UINTN TotalSize;\r
- UINTN DataSize;\r
- UINT32 CurrentRevision;\r
- PROCESSOR_INFO *ProcessorInfo;\r
- UINT32 InCompleteCheckSum32;\r
- UINT32 CheckSum32;\r
- UINTN ExtendedTableLength;\r
- UINT32 ExtendedTableCount;\r
- CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
- CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
- BOOLEAN CorrectMicrocode;\r
-\r
- //\r
- // Check HeaderVersion\r
- //\r
- MicrocodeEntryPoint = Image;\r
- if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");\r
- }\r
- return EFI_INCOMPATIBLE_VERSION;\r
- }\r
- //\r
- // Check LoaderRevision\r
- //\r
- if (MicrocodeEntryPoint->LoaderRevision != 0x1) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");\r
- }\r
- return EFI_INCOMPATIBLE_VERSION;\r
- }\r
- //\r
- // Check TotalSize\r
- //\r
- if (MicrocodeEntryPoint->DataSize == 0) {\r
- TotalSize = 2048;\r
- } else {\r
- TotalSize = MicrocodeEntryPoint->TotalSize;\r
- }\r
- if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
- }\r
- return EFI_VOLUME_CORRUPTED;\r
- }\r
- if ((TotalSize & (SIZE_1KB - 1)) != 0) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize is not multiples of 1024 bytes (1 KBytes)\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
- }\r
- return EFI_VOLUME_CORRUPTED;\r
- }\r
- if (TotalSize != ImageSize) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize not equal to ImageSize\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
- }\r
- return EFI_VOLUME_CORRUPTED;\r
- }\r
- //\r
- // Check DataSize\r
- //\r
- if (MicrocodeEntryPoint->DataSize == 0) {\r
- DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);\r
- } else {\r
- DataSize = MicrocodeEntryPoint->DataSize;\r
- }\r
- if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
- }\r
- return EFI_VOLUME_CORRUPTED;\r
- }\r
- if ((DataSize & 0x3) != 0) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize is not multiples of DWORDs\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
- }\r
- return EFI_VOLUME_CORRUPTED;\r
- }\r
- //\r
- // Check CheckSum32\r
- //\r
- CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));\r
- if (CheckSum32 != 0) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");\r
- }\r
- return EFI_VOLUME_CORRUPTED;\r
- }\r
- InCompleteCheckSum32 = CheckSum32;\r
- InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
- InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;\r
- InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;\r
-\r
- //\r
- // Check ProcessorSignature/ProcessorFlags\r
- //\r
-\r
- ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);\r
- if (ProcessorInfo == NULL) {\r
- CorrectMicrocode = FALSE;\r
- ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));\r
- if (ExtendedTableLength != 0) {\r
- //\r
- // Extended Table exist, check if the CPU in support list\r
- //\r
- ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER));\r
- //\r
- // Calculate Extended Checksum\r
- //\r
- if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) == 0)) {\r
- CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
- if (CheckSum32 != 0) {\r
- //\r
- // Checksum incorrect\r
- //\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for extended table is incorrect\n"));\r
- } else {\r
- //\r
- // Checksum correct\r
- //\r
- ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
- if (ExtendedTableCount > (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - ExtendedTableCount %d is too big\n", ExtendedTableCount));\r
- } else {\r
- ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
- for (Index = 0; Index < ExtendedTableCount; Index++) {\r
- CheckSum32 = InCompleteCheckSum32;\r
- CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;\r
- CheckSum32 += ExtendedTable->ProcessorFlag;\r
- CheckSum32 += ExtendedTable->Checksum;\r
- if (CheckSum32 != 0) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for ExtendedTable entry with index 0x%x is incorrect\n", Index));\r
- } else {\r
- //\r
- // Verify Header\r
- //\r
- ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);\r
- if (ProcessorInfo != NULL) {\r
- //\r
- // Find one\r
- //\r
- CorrectMicrocode = TRUE;\r
- break;\r
- }\r
- }\r
- ExtendedTable++;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- if (!CorrectMicrocode) {\r
- if (TryLoad) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on Current ProcessorSignature/ProcessorFlags\n"));\r
- }\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessorSignature/ProcessorFlags"), L"UnsupportedProcessorSignature/ProcessorFlags");\r
- }\r
- return EFI_UNSUPPORTED;\r
- }\r
- }\r
-\r
- //\r
- // Check UpdateRevision\r
- //\r
- CurrentRevision = ProcessorInfo->MicrocodeRevision;\r
- if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||\r
- (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {\r
- if (TryLoad) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));\r
- }\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");\r
- }\r
- return EFI_INCOMPATIBLE_VERSION;\r
- }\r
-\r
- //\r
- // try load MCU\r
- //\r
- if (TryLoad) {\r
- CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));\r
- if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {\r
- DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
- if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");\r
- }\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Get next Microcode entrypoint.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] MicrocodeEntryPoint Current Microcode entrypoint\r
-\r
- @return next Microcode entrypoint.\r
-**/\r
-CPU_MICROCODE_HEADER *\r
-GetNextMicrocode (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint\r
- )\r
-{\r
- UINTN Index;\r
-\r
- for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {\r
- if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {\r
- if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {\r
- // it is last one\r
- return NULL;\r
- } else {\r
- // return next one\r
- return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
- }\r
- }\r
- }\r
-\r
- ASSERT(FALSE);\r
- return NULL;\r
-}\r
-\r
-/**\r
- Get next FIT Microcode entrypoint.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] MicrocodeEntryPoint Current Microcode entrypoint\r
-\r
- @return next FIT Microcode entrypoint.\r
-**/\r
-CPU_MICROCODE_HEADER *\r
-GetNextFitMicrocode (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint\r
- )\r
-{\r
- UINTN Index;\r
-\r
- for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
- if (MicrocodeEntryPoint == MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint) {\r
- if (Index == (UINTN) MicrocodeFmpPrivate->FitMicrocodeEntryCount - 1) {\r
- // it is last one\r
- return NULL;\r
- } else {\r
- // return next one\r
- return MicrocodeFmpPrivate->FitMicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
- }\r
- }\r
- }\r
-\r
- ASSERT(FALSE);\r
- return NULL;\r
-}\r
-\r
-/**\r
- Find empty FIT Microcode entrypoint.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] ImageSize The size of Microcode image buffer in bytes.\r
- @param[out] AvailableSize Available size of the empty FIT Microcode entrypoint.\r
-\r
- @return Empty FIT Microcode entrypoint.\r
-**/\r
-CPU_MICROCODE_HEADER *\r
-FindEmptyFitMicrocode (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN UINTN ImageSize,\r
- OUT UINTN *AvailableSize\r
- )\r
-{\r
- UINTN Index;\r
- CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
- CPU_MICROCODE_HEADER *NextMicrocodeEntryPoint;\r
- VOID *MicrocodePatchAddress;\r
- UINTN MicrocodePatchRegionSize;\r
-\r
- MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
- MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
-\r
- for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
- if (MicrocodeFmpPrivate->FitMicrocodeInfo[Index].Empty) {\r
- MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;\r
- NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);\r
- if (NextMicrocodeEntryPoint != NULL) {\r
- *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;\r
- } else {\r
- *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;\r
- }\r
- if (*AvailableSize >= ImageSize) {\r
- return MicrocodeEntryPoint;\r
- }\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/**\r
- Find unused FIT Microcode entrypoint.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] ImageSize The size of Microcode image buffer in bytes.\r
- @param[out] AvailableSize Available size of the unused FIT Microcode entrypoint.\r
-\r
- @return Unused FIT Microcode entrypoint.\r
-**/\r
-CPU_MICROCODE_HEADER *\r
-FindUnusedFitMicrocode (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN UINTN ImageSize,\r
- OUT UINTN *AvailableSize\r
- )\r
-{\r
- UINTN Index;\r
- CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
- CPU_MICROCODE_HEADER *NextMicrocodeEntryPoint;\r
- VOID *MicrocodePatchAddress;\r
- UINTN MicrocodePatchRegionSize;\r
-\r
- MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
- MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
-\r
- for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
- if (!MicrocodeFmpPrivate->FitMicrocodeInfo[Index].InUse) {\r
- MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;\r
- NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);\r
- if (NextMicrocodeEntryPoint != NULL) {\r
- *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;\r
- } else {\r
- *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;\r
- }\r
- if (*AvailableSize >= ImageSize) {\r
- return MicrocodeEntryPoint;\r
- }\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/**\r
- Get current Microcode used region size.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
-\r
- @return current Microcode used region size.\r
-**/\r
-UINTN\r
-GetCurrentMicrocodeUsedRegionSize (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
- )\r
-{\r
- if (MicrocodeFmpPrivate->DescriptorCount == 0) {\r
- return 0;\r
- }\r
-\r
- return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint\r
- + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize\r
- - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;\r
-}\r
-\r
-/**\r
- Update Microcode.\r
-\r
- @param[in] Address The flash address of Microcode.\r
- @param[in] Image The Microcode image buffer.\r
- @param[in] ImageSize The size of Microcode image buffer in bytes.\r
- @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
-\r
- @retval EFI_SUCCESS The Microcode image is updated.\r
- @retval EFI_WRITE_PROTECTED The flash device is read only.\r
-**/\r
-EFI_STATUS\r
-UpdateMicrocode (\r
- IN UINT64 Address,\r
- IN VOID *Image,\r
- IN UINTN ImageSize,\r
- OUT UINT32 *LastAttemptStatus\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
- DEBUG((DEBUG_INFO, " Address - 0x%lx,", Address));\r
- DEBUG((DEBUG_INFO, " Length - 0x%x\n", ImageSize));\r
-\r
- Status = MicrocodeFlashWrite (\r
- Address,\r
- Image,\r
- ImageSize\r
- );\r
- if (!EFI_ERROR(Status)) {\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
- } else {\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
- }\r
- return Status;\r
-}\r
-\r
-/**\r
- Update Microcode flash region with FIT.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated\r
- @param[in] Image The Microcode image buffer.\r
- @param[in] ImageSize The size of Microcode image buffer in bytes.\r
- @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
-\r
- @retval EFI_SUCCESS The Microcode image is written.\r
- @retval EFI_WRITE_PROTECTED The flash device is read only.\r
-**/\r
-EFI_STATUS\r
-UpdateMicrocodeFlashRegionWithFit (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,\r
- IN VOID *Image,\r
- IN UINTN ImageSize,\r
- OUT UINT32 *LastAttemptStatus\r
- )\r
-{\r
- VOID *MicrocodePatchAddress;\r
- UINTN MicrocodePatchRegionSize;\r
- UINTN TargetTotalSize;\r
- EFI_STATUS Status;\r
- VOID *MicrocodePatchScratchBuffer;\r
- UINT8 *ScratchBufferPtr;\r
- UINTN ScratchBufferSize;\r
- UINTN RestSize;\r
- UINTN AvailableSize;\r
- VOID *NextMicrocodeEntryPoint;\r
- VOID *EmptyFitMicrocodeEntry;\r
- VOID *UnusedFitMicrocodeEntry;\r
-\r
- DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegionWithFit: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
-\r
- MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
- MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
-\r
- MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
- if (MicrocodePatchScratchBuffer == NULL) {\r
- DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
- ScratchBufferSize = 0;\r
-\r
- //\r
- // Target data collection\r
- //\r
- TargetTotalSize = 0;\r
- AvailableSize = 0;\r
- if (TargetMicrocodeEntryPoint != NULL) {\r
- if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
- TargetTotalSize = 2048;\r
- } else {\r
- TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
- }\r
- DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));\r
- NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
- DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
- if (NextMicrocodeEntryPoint != NULL) {\r
- ASSERT ((UINTN) NextMicrocodeEntryPoint >= ((UINTN) TargetMicrocodeEntryPoint + TargetTotalSize));\r
- AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) TargetMicrocodeEntryPoint;\r
- } else {\r
- AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) TargetMicrocodeEntryPoint;\r
- }\r
- DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));\r
- ASSERT (AvailableSize >= TargetTotalSize);\r
- }\r
- //\r
- // Total Size means the Microcode size.\r
- // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.\r
- //\r
- // (1)\r
- // +------+-----------+-----+------+===================+\r
- // | MCU1 | Microcode | PAD | MCU2 | Empty |\r
- // +------+-----------+-----+------+===================+\r
- // | TotalSize |\r
- // |<-AvailableSize->|\r
- //\r
- // (2)\r
- // +------+-----------+===================+\r
- // | MCU | Microcode | Empty |\r
- // +------+-----------+===================+\r
- // | TotalSize |\r
- // |<- AvailableSize ->|\r
- //\r
-\r
- //\r
- // Update based on policy\r
- //\r
-\r
- //\r
- // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
- //\r
- if (AvailableSize >= ImageSize) {\r
- DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
- //\r
- // +------+------------+------+===================+\r
- // |Other | Old Image | ... | Empty |\r
- // +------+------------+------+===================+\r
- //\r
- // +------+---------+--+------+===================+\r
- // |Other |New Image|FF| ... | Empty |\r
- // +------+---------+--+------+===================+\r
- //\r
- // 1.1. Copy new image\r
- CopyMem (ScratchBufferPtr, Image, ImageSize);\r
- ScratchBufferSize += ImageSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- // 1.2. Pad 0xFF\r
- RestSize = AvailableSize - ImageSize;\r
- if (RestSize > 0) {\r
- SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
- ScratchBufferSize += RestSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- }\r
- Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
- return Status;\r
- }\r
-\r
- //\r
- // 2. If there is empty FIT microcode entry with enough space, use it.\r
- //\r
- EmptyFitMicrocodeEntry = FindEmptyFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);\r
- if (EmptyFitMicrocodeEntry != NULL) {\r
- DEBUG((DEBUG_INFO, "Use empty FIT microcode entry\n"));\r
- // 2.1. Copy new image\r
- CopyMem (ScratchBufferPtr, Image, ImageSize);\r
- ScratchBufferSize += ImageSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- // 2.2. Pad 0xFF\r
- RestSize = AvailableSize - ImageSize;\r
- if (RestSize > 0) {\r
- SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
- ScratchBufferSize += RestSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- }\r
- Status = UpdateMicrocode ((UINTN) EmptyFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
- if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {\r
- //\r
- // Empty old microcode.\r
- //\r
- ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
- SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);\r
- ScratchBufferSize = TargetTotalSize;\r
- ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
- }\r
- return Status;\r
- }\r
-\r
- //\r
- // 3. If there is unused microcode entry with enough space, use it.\r
- //\r
- UnusedFitMicrocodeEntry = FindUnusedFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);\r
- if (UnusedFitMicrocodeEntry != NULL) {\r
- DEBUG((DEBUG_INFO, "Use unused FIT microcode entry\n"));\r
- // 3.1. Copy new image\r
- CopyMem (ScratchBufferPtr, Image, ImageSize);\r
- ScratchBufferSize += ImageSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- // 3.2. Pad 0xFF\r
- RestSize = AvailableSize - ImageSize;\r
- if (RestSize > 0) {\r
- SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
- ScratchBufferSize += RestSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- }\r
- Status = UpdateMicrocode ((UINTN) UnusedFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
- if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {\r
- //\r
- // Empty old microcode.\r
- //\r
- ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
- SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);\r
- ScratchBufferSize = TargetTotalSize;\r
- ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
- }\r
- return Status;\r
- }\r
-\r
- //\r
- // 4. No usable FIT microcode entry.\r
- //\r
- DEBUG((DEBUG_ERROR, "No usable FIT microcode entry\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
- Status = EFI_OUT_OF_RESOURCES;\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Update Microcode flash region.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated\r
- @param[in] Image The Microcode image buffer.\r
- @param[in] ImageSize The size of Microcode image buffer in bytes.\r
- @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
-\r
- @retval EFI_SUCCESS The Microcode image is written.\r
- @retval EFI_WRITE_PROTECTED The flash device is read only.\r
-**/\r
-EFI_STATUS\r
-UpdateMicrocodeFlashRegion (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,\r
- IN VOID *Image,\r
- IN UINTN ImageSize,\r
- OUT UINT32 *LastAttemptStatus\r
- )\r
-{\r
- VOID *MicrocodePatchAddress;\r
- UINTN MicrocodePatchRegionSize;\r
- UINTN TargetTotalSize;\r
- UINTN UsedRegionSize;\r
- EFI_STATUS Status;\r
- VOID *MicrocodePatchScratchBuffer;\r
- UINT8 *ScratchBufferPtr;\r
- UINTN ScratchBufferSize;\r
- UINTN RestSize;\r
- UINTN AvailableSize;\r
- VOID *NextMicrocodeEntryPoint;\r
- MICROCODE_INFO *MicrocodeInfo;\r
- UINTN MicrocodeCount;\r
- UINTN Index;\r
-\r
- DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
-\r
- MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
- MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
-\r
- MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
- if (MicrocodePatchScratchBuffer == NULL) {\r
- DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
- ScratchBufferSize = 0;\r
-\r
- //\r
- // Target data collection\r
- //\r
- TargetTotalSize = 0;\r
- AvailableSize = 0;\r
- NextMicrocodeEntryPoint = NULL;\r
- if (TargetMicrocodeEntryPoint != NULL) {\r
- if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
- TargetTotalSize = 2048;\r
- } else {\r
- TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
- }\r
- DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));\r
- NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
- DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
- if (NextMicrocodeEntryPoint != NULL) {\r
- ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
- AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;\r
- } else {\r
- AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;\r
- }\r
- DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));\r
- ASSERT (AvailableSize >= TargetTotalSize);\r
- }\r
- UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);\r
- DEBUG((DEBUG_INFO, " UsedRegionSize - 0x%x\n", UsedRegionSize));\r
- ASSERT (UsedRegionSize >= TargetTotalSize);\r
- if (TargetMicrocodeEntryPoint != NULL) {\r
- ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
- }\r
- //\r
- // Total Size means the Microcode size.\r
- // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.\r
- //\r
- // (1)\r
- // +------+-----------+-----+------+===================+\r
- // | MCU1 | Microcode | PAD | MCU2 | Empty |\r
- // +------+-----------+-----+------+===================+\r
- // | TotalSize |\r
- // |<-AvailableSize->|\r
- // |<- UsedRegionSize ->|\r
- //\r
- // (2)\r
- // +------+-----------+===================+\r
- // | MCU | Microcode | Empty |\r
- // +------+-----------+===================+\r
- // | TotalSize |\r
- // |<- AvailableSize ->|\r
- // |<-UsedRegionSize->|\r
- //\r
-\r
- //\r
- // Update based on policy\r
- //\r
-\r
- //\r
- // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
- //\r
- if (AvailableSize >= ImageSize) {\r
- DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
- //\r
- // +------+------------+------+===================+\r
- // |Other | Old Image | ... | Empty |\r
- // +------+------------+------+===================+\r
- //\r
- // +------+---------+--+------+===================+\r
- // |Other |New Image|FF| ... | Empty |\r
- // +------+---------+--+------+===================+\r
- //\r
- // 1.1. Copy new image\r
- CopyMem (ScratchBufferPtr, Image, ImageSize);\r
- ScratchBufferSize += ImageSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- // 1.2. Pad 0xFF\r
- RestSize = AvailableSize - ImageSize;\r
- if (RestSize > 0) {\r
- SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
- ScratchBufferSize += RestSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- }\r
- Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
- return Status;\r
- }\r
-\r
- //\r
- // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.\r
- //\r
- if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {\r
- if (TargetMicrocodeEntryPoint == NULL) {\r
- DEBUG((DEBUG_INFO, "Append new microcode\n"));\r
- //\r
- // +------+------------+------+===================+\r
- // |Other1| Other |Other2| Empty |\r
- // +------+------------+------+===================+\r
- //\r
- // +------+------------+------+-----------+=======+\r
- // |Other1| Other |Other2| New Image | Empty |\r
- // +------+------------+------+-----------+=======+\r
- //\r
- Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);\r
- } else {\r
- DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));\r
- //\r
- // +------+------------+------+===================+\r
- // |Other | Old Image | ... | Empty |\r
- // +------+------------+------+===================+\r
- //\r
- // +------+---------------+------+================+\r
- // |Other | New Image | ... | Empty |\r
- // +------+---------------+------+================+\r
- //\r
- // 2.1. Copy new image\r
- CopyMem (ScratchBufferPtr, Image, ImageSize);\r
- ScratchBufferSize += ImageSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- // 2.2. Copy rest images after the old image.\r
- if (NextMicrocodeEntryPoint != 0) {\r
- RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);\r
- CopyMem (ScratchBufferPtr, NextMicrocodeEntryPoint, RestSize);\r
- ScratchBufferSize += RestSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- }\r
- Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
- }\r
- return Status;\r
- }\r
-\r
- //\r
- // 3. The new image can be put in MCU region, but not all others can be put.\r
- // So all the unused MCU is removed.\r
- //\r
- if (MicrocodePatchRegionSize >= ImageSize) {\r
- //\r
- // +------+------------+------+===================+\r
- // |Other1| Old Image |Other2| Empty |\r
- // +------+------------+------+===================+\r
- //\r
- // +-------------------------------------+--------+\r
- // | New Image | Other |\r
- // +-------------------------------------+--------+\r
- //\r
- DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));\r
-\r
- MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;\r
- MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;\r
-\r
- // 3.1. Copy new image\r
- CopyMem (ScratchBufferPtr, Image, ImageSize);\r
- ScratchBufferSize += ImageSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- // 3.2. Copy some others to rest buffer\r
- for (Index = 0; Index < MicrocodeCount; Index++) {\r
- if (!MicrocodeInfo[Index].InUse) {\r
- continue;\r
- }\r
- if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {\r
- continue;\r
- }\r
- if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {\r
- CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);\r
- ScratchBufferSize += MicrocodeInfo[Index].TotalSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- }\r
- }\r
- // 3.3. Pad 0xFF\r
- RestSize = MicrocodePatchRegionSize - ScratchBufferSize;\r
- if (RestSize > 0) {\r
- SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
- ScratchBufferSize += RestSize;\r
- ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
- }\r
- Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
- return Status;\r
- }\r
-\r
- //\r
- // 4. The new image size is bigger than the whole MCU region.\r
- //\r
- DEBUG((DEBUG_ERROR, "Microcode too big\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
- Status = EFI_OUT_OF_RESOURCES;\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Write Microcode.\r
-\r
- Caution: This function may receive untrusted input.\r
-\r
- @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
- @param[in] Image The Microcode image buffer.\r
- @param[in] ImageSize The size of Microcode image buffer in bytes.\r
- @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
- @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
- @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
- details for the aborted operation. The buffer is allocated by this function\r
- with AllocatePool(), and it is the caller's responsibility to free it with a\r
- call to FreePool().\r
-\r
- @retval EFI_SUCCESS The Microcode image is written.\r
- @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupted.\r
- @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.\r
- @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.\r
- @retval EFI_WRITE_PROTECTED The flash device is read only.\r
-**/\r
-EFI_STATUS\r
-MicrocodeWrite (\r
- IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
- IN VOID *Image,\r
- IN UINTN ImageSize,\r
- OUT UINT32 *LastAttemptVersion,\r
- OUT UINT32 *LastAttemptStatus,\r
- OUT CHAR16 **AbortReason\r
- )\r
-{\r
- EFI_STATUS Status;\r
- VOID *AlignedImage;\r
- CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint;\r
- UINTN TargetCpuIndex;\r
- UINTN TargetMicrcodeIndex;\r
-\r
- //\r
- // MCU must be 16 bytes aligned\r
- //\r
- AlignedImage = AllocateCopyPool(ImageSize, Image);\r
- if (AlignedImage == NULL) {\r
- DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));\r
- *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- TargetCpuIndex = (UINTN)-1;\r
- Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);\r
- if (EFI_ERROR(Status)) {\r
- DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));\r
- FreePool(AlignedImage);\r
- return Status;\r
- }\r
- DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));\r
- *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;\r
-\r
- DEBUG((DEBUG_INFO, " TargetCpuIndex - 0x%x\n", TargetCpuIndex));\r
- ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
- TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;\r
- DEBUG((DEBUG_INFO, " TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));\r
- if (TargetMicrcodeIndex != (UINTN)-1) {\r
- ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);\r
- TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;\r
- } else {\r
- TargetMicrocodeEntryPoint = NULL;\r
- }\r
- DEBUG((DEBUG_INFO, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));\r
-\r
- if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {\r
- Status = UpdateMicrocodeFlashRegionWithFit (\r
- MicrocodeFmpPrivate,\r
- TargetMicrocodeEntryPoint,\r
- AlignedImage,\r
- ImageSize,\r
- LastAttemptStatus\r
- );\r
- } else {\r
- Status = UpdateMicrocodeFlashRegion (\r
- MicrocodeFmpPrivate,\r
- TargetMicrocodeEntryPoint,\r
- AlignedImage,\r
- ImageSize,\r
- LastAttemptStatus\r
- );\r
- }\r
-\r
- FreePool(AlignedImage);\r
-\r
- return Status;\r
-}\r
-\r
-\r