}\r
\r
Status = MicrocodeWrite(MicrocodeFmpPrivate, (VOID *)Image, ImageSize, &MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, &MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus, AbortReason);\r
- DEBUG((DEBUG_INFO, "SetImage - LastAttemp Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));\r
+ DEBUG((DEBUG_INFO, "SetImage - LastAttempt Version - 0x%x, Status - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));\r
VarStatus = gRT->SetVariable(\r
MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME,\r
&gEfiCallerIdGuid,\r
sizeof(MicrocodeFmpPrivate->LastAttempt),\r
&MicrocodeFmpPrivate->LastAttempt\r
);\r
- DEBUG((DEBUG_INFO, "SetLastAttemp - %r\n", VarStatus));\r
+ DEBUG((DEBUG_INFO, "SetLastAttempt - %r\n", VarStatus));\r
\r
if (!EFI_ERROR(Status)) {\r
InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);\r
return EFI_UNSUPPORTED;\r
}\r
\r
+/**\r
+ Sort FIT microcode entries based upon MicrocodeEntryPoint, from low to high.\r
+\r
+ @param[in] MicrocodeFmpPrivate private data structure to be initialized.\r
+\r
+**/\r
+VOID\r
+SortFitMicrocodeInfo (\r
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
+ )\r
+{\r
+ FIT_MICROCODE_INFO *FitMicrocodeEntry;\r
+ FIT_MICROCODE_INFO *NextFitMicrocodeEntry;\r
+ FIT_MICROCODE_INFO TempFitMicrocodeEntry;\r
+ FIT_MICROCODE_INFO *FitMicrocodeEntryEnd;\r
+\r
+ FitMicrocodeEntry = MicrocodeFmpPrivate->FitMicrocodeInfo;\r
+ NextFitMicrocodeEntry = FitMicrocodeEntry + 1;\r
+ FitMicrocodeEntryEnd = MicrocodeFmpPrivate->FitMicrocodeInfo + MicrocodeFmpPrivate->FitMicrocodeEntryCount;\r
+ while (FitMicrocodeEntry < FitMicrocodeEntryEnd) {\r
+ while (NextFitMicrocodeEntry < FitMicrocodeEntryEnd) {\r
+ if (FitMicrocodeEntry->MicrocodeEntryPoint > NextFitMicrocodeEntry->MicrocodeEntryPoint) {\r
+ CopyMem (&TempFitMicrocodeEntry, FitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));\r
+ CopyMem (FitMicrocodeEntry, NextFitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));\r
+ CopyMem (NextFitMicrocodeEntry, &TempFitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));\r
+ }\r
+\r
+ NextFitMicrocodeEntry = NextFitMicrocodeEntry + 1;\r
+ }\r
+\r
+ FitMicrocodeEntry = FitMicrocodeEntry + 1;\r
+ NextFitMicrocodeEntry = FitMicrocodeEntry + 1;\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize FIT microcode information.\r
+\r
+ @param[in] MicrocodeFmpPrivate private data structure to be initialized.\r
+\r
+ @return EFI_SUCCESS FIT microcode information is initialized.\r
+ @return EFI_OUT_OF_RESOURCES No enough resource for the initialization.\r
+ @return EFI_DEVICE_ERROR There is something wrong in FIT microcode entry.\r
+**/\r
+EFI_STATUS\r
+InitializeFitMicrocodeInfo (\r
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
+ )\r
+{\r
+ UINT64 FitPointer;\r
+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;\r
+ UINT32 EntryNum;\r
+ UINT32 MicrocodeEntryNum;\r
+ UINT32 Index;\r
+ UINTN Address;\r
+ VOID *MicrocodePatchAddress;\r
+ UINTN MicrocodePatchRegionSize;\r
+ FIT_MICROCODE_INFO *FitMicrocodeInfo;\r
+ FIT_MICROCODE_INFO *FitMicrocodeInfoNext;\r
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
+ CPU_MICROCODE_HEADER *MicrocodeEntryPointNext;\r
+ UINTN FitMicrocodeIndex;\r
+ MICROCODE_INFO *MicrocodeInfo;\r
+ UINTN MicrocodeIndex;\r
+\r
+ if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {\r
+ FreePool (MicrocodeFmpPrivate->FitMicrocodeInfo);\r
+ MicrocodeFmpPrivate->FitMicrocodeInfo = NULL;\r
+ MicrocodeFmpPrivate->FitMicrocodeEntryCount = 0;\r
+ }\r
+\r
+ FitPointer = *(UINT64 *) (UINTN) FIT_POINTER_ADDRESS;\r
+ if ((FitPointer == 0) ||\r
+ (FitPointer == 0xFFFFFFFFFFFFFFFF) ||\r
+ (FitPointer == 0xEEEEEEEEEEEEEEEE)) {\r
+ //\r
+ // No FIT table.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *) (UINTN) FitPointer;\r
+ if ((FitEntry[0].Type != FIT_TYPE_00_HEADER) ||\r
+ (FitEntry[0].Address != FIT_TYPE_00_SIGNATURE)) {\r
+ //\r
+ // Invalid FIT table, treat it as no FIT table.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;\r
+\r
+ //\r
+ // Calculate microcode entry number.\r
+ //\r
+ MicrocodeEntryNum = 0;\r
+ for (Index = 0; Index < EntryNum; Index++) {\r
+ if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {\r
+ MicrocodeEntryNum++;\r
+ }\r
+ }\r
+ if (MicrocodeEntryNum == 0) {\r
+ //\r
+ // No FIT microcode entry.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Allocate buffer.\r
+ //\r
+ MicrocodeFmpPrivate->FitMicrocodeInfo = AllocateZeroPool (MicrocodeEntryNum * sizeof (FIT_MICROCODE_INFO));\r
+ if (MicrocodeFmpPrivate->FitMicrocodeInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ MicrocodeFmpPrivate->FitMicrocodeEntryCount = MicrocodeEntryNum;\r
+\r
+ MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
+ MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
+\r
+ //\r
+ // Collect microcode entry info.\r
+ //\r
+ MicrocodeEntryNum = 0;\r
+ for (Index = 0; Index < EntryNum; Index++) {\r
+ if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {\r
+ Address = (UINTN) FitEntry[Index].Address;\r
+ if ((Address < (UINTN) MicrocodePatchAddress) ||\r
+ (Address >= ((UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize))) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "InitializeFitMicrocodeInfo - Address (0x%x) is not in Microcode Region\n",\r
+ Address\r
+ ));\r
+ goto ErrorExit;\r
+ }\r
+ FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[MicrocodeEntryNum];\r
+ FitMicrocodeInfo->MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) Address;\r
+ if ((*(UINT32 *) Address) == 0xFFFFFFFF) {\r
+ //\r
+ // It is the empty slot as long as the first dword is 0xFFFF_FFFF.\r
+ //\r
+ FitMicrocodeInfo->Empty = TRUE;\r
+ } else {\r
+ FitMicrocodeInfo->Empty = FALSE;\r
+ }\r
+ MicrocodeEntryNum++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Every microcode should have a FIT microcode entry.\r
+ //\r
+ for (MicrocodeIndex = 0; MicrocodeIndex < MicrocodeFmpPrivate->DescriptorCount; MicrocodeIndex++) {\r
+ MicrocodeInfo = &MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex];\r
+ for (FitMicrocodeIndex = 0; FitMicrocodeIndex < MicrocodeFmpPrivate->FitMicrocodeEntryCount; FitMicrocodeIndex++) {\r
+ FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex];\r
+ if (MicrocodeInfo->MicrocodeEntryPoint == FitMicrocodeInfo->MicrocodeEntryPoint) {\r
+ FitMicrocodeInfo->TotalSize = MicrocodeInfo->TotalSize;\r
+ FitMicrocodeInfo->InUse = MicrocodeInfo->InUse;\r
+ break;\r
+ }\r
+ }\r
+ if (FitMicrocodeIndex >= MicrocodeFmpPrivate->FitMicrocodeEntryCount) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "InitializeFitMicrocodeInfo - There is no FIT microcode entry for Microcode (0x%x)\n",\r
+ MicrocodeInfo->MicrocodeEntryPoint\r
+ ));\r
+ goto ErrorExit;\r
+ }\r
+ }\r
+\r
+ SortFitMicrocodeInfo (MicrocodeFmpPrivate);\r
+\r
+ //\r
+ // Check overlap.\r
+ //\r
+ for (FitMicrocodeIndex = 0; FitMicrocodeIndex < MicrocodeFmpPrivate->FitMicrocodeEntryCount - 1; FitMicrocodeIndex++) {\r
+ FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex];\r
+ MicrocodeEntryPoint = FitMicrocodeInfo->MicrocodeEntryPoint;\r
+ FitMicrocodeInfoNext = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex + 1];\r
+ MicrocodeEntryPointNext = FitMicrocodeInfoNext->MicrocodeEntryPoint;\r
+ if ((MicrocodeEntryPoint >= MicrocodeEntryPointNext) ||\r
+ ((FitMicrocodeInfo->TotalSize != 0) &&\r
+ ((UINTN) MicrocodeEntryPoint + FitMicrocodeInfo->TotalSize) >\r
+ (UINTN) MicrocodeEntryPointNext)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "InitializeFitMicrocodeInfo - There is overlap between FIT microcode entries (0x%x 0x%x)\n",\r
+ MicrocodeEntryPoint,\r
+ MicrocodeEntryPointNext\r
+ ));\r
+ goto ErrorExit;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+ FreePool (MicrocodeFmpPrivate->FitMicrocodeInfo);\r
+ MicrocodeFmpPrivate->FitMicrocodeInfo = NULL;\r
+ MicrocodeFmpPrivate->FitMicrocodeEntryCount = 0;\r
+ return EFI_DEVICE_ERROR;\r
+}\r
+\r
/**\r
Initialize Processor Microcode Index.\r
\r
\r
@param[in] MicrocodeFmpPrivate private data structure to be initialized.\r
\r
- @return EFI_SUCCESS Microcode Descriptor is initialized.\r
+ @return EFI_SUCCESS Microcode Descriptor is initialized.\r
+ @return EFI_OUT_OF_RESOURCES No enough resource for the initialization.\r
**/\r
EFI_STATUS\r
InitializeMicrocodeDescriptor (\r
IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
)\r
{\r
- UINT8 CurrentMicrocodeCount;\r
+ EFI_STATUS Status;\r
+ UINT8 CurrentMicrocodeCount;\r
\r
CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, 0, NULL, NULL);\r
\r
if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {\r
MicrocodeFmpPrivate->MicrocodeInfo = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));\r
if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {\r
+ FreePool (MicrocodeFmpPrivate->ImageDescriptor);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
}\r
\r
InitializedProcessorMicrocodeIndex (MicrocodeFmpPrivate);\r
\r
+ Status = InitializeFitMicrocodeInfo (MicrocodeFmpPrivate);\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool (MicrocodeFmpPrivate->ImageDescriptor);\r
+ FreePool (MicrocodeFmpPrivate->MicrocodeInfo);\r
+ DEBUG((DEBUG_ERROR, "InitializeFitMicrocodeInfo - %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
return EFI_SUCCESS;\r
}\r
\r
\r
@param[in] MicrocodeFmpPrivate private data structure to be initialized.\r
\r
- @return EFI_SUCCESS private data is initialized.\r
+ @return EFI_SUCCESS Processor information is initialized.\r
+ @return EFI_OUT_OF_RESOURCES No enough resource for the initialization.\r
**/\r
EFI_STATUS\r
InitializeProcessorInfo (\r
PROCESSOR_INFO *ProcessorInfo;\r
MICROCODE_INFO *MicrocodeInfo;\r
EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor;\r
+ FIT_MICROCODE_INFO *FitMicrocodeInfo;\r
\r
DEBUG ((DEBUG_INFO, "ProcessorInfo:\n"));\r
DEBUG ((DEBUG_INFO, " ProcessorCount - 0x%x\n", MicrocodeFmpPrivate->ProcessorCount));\r
DEBUG((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", ImageDescriptor[Index].LastAttemptStatus));\r
DEBUG((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", ImageDescriptor[Index].HardwareInstance));\r
}\r
+\r
+ if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {\r
+ DEBUG ((DEBUG_INFO, "FitMicrocodeInfo:\n"));\r
+ FitMicrocodeInfo = MicrocodeFmpPrivate->FitMicrocodeInfo;\r
+ DEBUG ((DEBUG_INFO, " FitMicrocodeEntryCount - 0x%x\n", MicrocodeFmpPrivate->FitMicrocodeEntryCount));\r
+ for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " FitMicrocodeInfo[0x%x] - 0x%08x, 0x%08x, (0x%x, 0x%x)\n",\r
+ Index,\r
+ FitMicrocodeInfo[Index].MicrocodeEntryPoint,\r
+ FitMicrocodeInfo[Index].TotalSize,\r
+ FitMicrocodeInfo[Index].InUse,\r
+ FitMicrocodeInfo[Index].Empty\r
+ ));\r
+ }\r
+ }\r
}\r
\r
/**\r
&VarSize,\r
&MicrocodeFmpPrivate->LastAttempt\r
);\r
- DEBUG((DEBUG_INFO, "GetLastAttemp - %r\n", VarStatus));\r
- DEBUG((DEBUG_INFO, "GetLastAttemp Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));\r
+ DEBUG((DEBUG_INFO, "GetLastAttempt - %r\n", VarStatus));\r
+ DEBUG((DEBUG_INFO, "GetLastAttempt Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));\r
\r
Result = GetMicrocodeRegion(&MicrocodeFmpPrivate->MicrocodePatchAddress, &MicrocodeFmpPrivate->MicrocodePatchRegionSize);\r
if (!Result) {\r
\r
Status = InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);\r
if (EFI_ERROR(Status)) {\r
+ FreePool (MicrocodeFmpPrivate->ProcessorInfo);\r
DEBUG((DEBUG_ERROR, "InitializeMicrocodeDescriptor - %r\n", Status));\r
return Status;\r
}\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 corrupt.\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
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
if (AbortReason != NULL) {\r
- *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");\r
+ *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessorSignature/ProcessorFlags"), L"UnsupportedProcessorSignature/ProcessorFlags");\r
}\r
return EFI_UNSUPPORTED;\r
}\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
\r
DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
DEBUG((DEBUG_INFO, " Address - 0x%lx,", Address));\r
- DEBUG((DEBUG_INFO, " Legnth - 0x%x\n", ImageSize));\r
+ DEBUG((DEBUG_INFO, " Length - 0x%x\n", ImageSize));\r
\r
Status = MicrocodeFlashWrite (\r
Address,\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
AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;\r
}\r
DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));\r
+ ASSERT (AvailableSize >= TargetTotalSize);\r
}\r
- ASSERT (AvailableSize >= TargetTotalSize);\r
UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);\r
DEBUG((DEBUG_INFO, " UsedRegionSize - 0x%x\n", UsedRegionSize));\r
ASSERT (UsedRegionSize >= TargetTotalSize);\r
ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
}\r
//\r
- // Total Size means the Microcode data size.\r
- // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.\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
DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
//\r
// +------+------------+------+===================+\r
- // |Other1| Old Image |Other2| Empty |\r
+ // |Other | Old Image | ... | Empty |\r
// +------+------------+------+===================+\r
//\r
// +------+---------+--+------+===================+\r
- // |Other1|New Image|FF|Other2| Empty |\r
+ // |Other |New Image|FF| ... | Empty |\r
// +------+---------+--+------+===================+\r
//\r
// 1.1. Copy new image\r
DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));\r
//\r
// +------+------------+------+===================+\r
- // |Other1| Old Image |Other2| Empty |\r
+ // |Other | Old Image | ... | Empty |\r
// +------+------------+------+===================+\r
//\r
// +------+---------------+------+================+\r
- // |Other1| New Image |Other2| Empty |\r
+ // |Other | New Image | ... | Empty |\r
// +------+---------------+------+================+\r
//\r
// 2.1. Copy new image\r
// 2.2. Copy rest images after the old image.\r
if (NextMicrocodeEntryPoint != 0) {\r
RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);\r
- CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);\r
+ CopyMem (ScratchBufferPtr, NextMicrocodeEntryPoint, RestSize);\r
ScratchBufferSize += RestSize;\r
ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
}\r
call to FreePool().\r
\r
@retval EFI_SUCCESS The Microcode image is written.\r
- @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.\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
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;\r
TargetCpuIndex = (UINTN)-1;\r
Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);\r
if (EFI_ERROR(Status)) {\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
}\r
DEBUG((DEBUG_INFO, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));\r
\r
- Status = UpdateMicrocodeFlashRegion(\r
- MicrocodeFmpPrivate,\r
- TargetMicrocodeEntryPoint,\r
- AlignedImage,\r
- ImageSize,\r
- LastAttemptStatus\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