]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
IntelSiliconPkg/MicrocodeUpdate: Fix incorrect checksum issue
[mirror_edk2.git] / IntelSiliconPkg / Feature / Capsule / MicrocodeUpdateDxe / MicrocodeUpdate.c
CommitLineData
88266859
JY
1/** @file\r
2 SetImage instance to update Microcode.\r
3\r
4 Caution: This module requires additional review when modified.\r
5 This module will have external input - capsule image.\r
6 This external input must be validated carefully to avoid security issue like\r
7 buffer overflow, integer overflow.\r
8\r
9 MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.\r
10\r
1db271df 11 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
88266859
JY
12 This program and the accompanying materials\r
13 are licensed and made available under the terms and conditions of the BSD License\r
14 which accompanies this distribution. The full text of the license may be found at\r
15 http://opensource.org/licenses/bsd-license.php\r
16\r
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
19\r
20**/\r
21\r
22#include "MicrocodeUpdate.h"\r
23\r
24/**\r
25 Get Microcode Region.\r
26\r
27 @param[out] MicrocodePatchAddress The address of Microcode\r
28 @param[out] MicrocodePatchRegionSize The region size of Microcode\r
29\r
30 @retval TRUE The Microcode region is returned.\r
31 @retval FALSE No Microcode region.\r
32**/\r
33BOOLEAN\r
34GetMicrocodeRegion (\r
2ed65824
JY
35 OUT VOID **MicrocodePatchAddress,\r
36 OUT UINTN *MicrocodePatchRegionSize\r
88266859
JY
37 )\r
38{\r
2ed65824
JY
39 *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);\r
40 *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);\r
88266859 41\r
2ed65824 42 if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {\r
88266859
JY
43 return FALSE;\r
44 }\r
45\r
46 return TRUE;\r
47}\r
48\r
49/**\r
50 Get Microcode update signature of currently loaded Microcode update.\r
51\r
52 @return Microcode signature.\r
53\r
54**/\r
55UINT32\r
56GetCurrentMicrocodeSignature (\r
57 VOID\r
58 )\r
59{\r
60 UINT64 Signature;\r
61\r
62 AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);\r
63 AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
64 Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);\r
65 return (UINT32)RShiftU64(Signature, 32);\r
66}\r
67\r
68/**\r
69 Get current processor signature.\r
70\r
71 @return current processor signature.\r
72**/\r
73UINT32\r
74GetCurrentProcessorSignature (\r
75 VOID\r
76 )\r
77{\r
78 UINT32 RegEax;\r
79 AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
80 return RegEax;\r
81}\r
82\r
83/**\r
84 Get current platform ID.\r
85\r
86 @return current platform ID.\r
87**/\r
88UINT8\r
89GetCurrentPlatformId (\r
90 VOID\r
91 )\r
92{\r
93 UINT8 PlatformId;\r
94\r
95 PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);\r
96 return PlatformId;\r
97}\r
98\r
99/**\r
100 Load new Microcode.\r
101\r
102 @param[in] Address The address of new Microcode.\r
103\r
104 @return Loaded Microcode signature.\r
105\r
106**/\r
107UINT32\r
108LoadMicrocode (\r
109 IN UINT64 Address\r
110 )\r
111{\r
112 AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);\r
113 return GetCurrentMicrocodeSignature();\r
114}\r
115\r
2ed65824 116/**\r
31d060d9
JY
117 Load Microcode on an Application Processor.\r
118 The function prototype for invoking a function on an Application Processor.\r
119\r
120 @param[in,out] Buffer The pointer to private data buffer.\r
121**/\r
122VOID\r
123EFIAPI\r
124MicrocodeLoadAp (\r
125 IN OUT VOID *Buffer\r
126 )\r
127{\r
128 MICROCODE_LOAD_BUFFER *MicrocodeLoadBuffer;\r
129\r
130 MicrocodeLoadBuffer = Buffer;\r
131 MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);\r
132}\r
133\r
134/**\r
135 Load new Microcode on this processor\r
2ed65824 136\r
31d060d9
JY
137 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
138 @param[in] CpuIndex The index of the processor.\r
139 @param[in] Address The address of new Microcode.\r
140\r
141 @return Loaded Microcode signature.\r
2ed65824 142\r
2ed65824 143**/\r
31d060d9
JY
144UINT32\r
145LoadMicrocodeOnThis (\r
146 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
147 IN UINTN CpuIndex,\r
148 IN UINT64 Address\r
2ed65824
JY
149 )\r
150{\r
31d060d9
JY
151 EFI_STATUS Status;\r
152 EFI_MP_SERVICES_PROTOCOL *MpService;\r
153 MICROCODE_LOAD_BUFFER MicrocodeLoadBuffer;\r
2ed65824 154\r
31d060d9
JY
155 if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {\r
156 return LoadMicrocode (Address);\r
157 } else {\r
158 MpService = MicrocodeFmpPrivate->MpService;\r
159 MicrocodeLoadBuffer.Address = Address;\r
160 MicrocodeLoadBuffer.Revision = 0;\r
161 Status = MpService->StartupThisAP (\r
162 MpService,\r
163 MicrocodeLoadAp,\r
164 CpuIndex,\r
165 NULL,\r
166 0,\r
167 &MicrocodeLoadBuffer,\r
168 NULL\r
169 );\r
170 ASSERT_EFI_ERROR(Status);\r
171 return MicrocodeLoadBuffer.Revision;\r
2ed65824 172 }\r
31d060d9
JY
173}\r
174\r
175/**\r
176 Collect processor information.\r
177 The function prototype for invoking a function on an Application Processor.\r
178\r
179 @param[in,out] Buffer The pointer to private data buffer.\r
180**/\r
181VOID\r
182EFIAPI\r
183CollectProcessorInfo (\r
184 IN OUT VOID *Buffer\r
185 )\r
186{\r
187 PROCESSOR_INFO *ProcessorInfo;\r
188\r
189 ProcessorInfo = Buffer;\r
190 ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();\r
191 ProcessorInfo->PlatformId = GetCurrentPlatformId();\r
192 ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();\r
2ed65824
JY
193}\r
194\r
88266859
JY
195/**\r
196 Get current Microcode information.\r
197\r
31d060d9
JY
198 The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)\r
199 in MicrocodeFmpPrivate must be initialized.\r
200\r
201 The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)\r
202 in MicrocodeFmpPrivate may not be avaiable in this function.\r
2ed65824
JY
203\r
204 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
205 @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.\r
206 @param[out] ImageDescriptor Microcode ImageDescriptor\r
207 @param[out] MicrocodeInfo Microcode information\r
88266859
JY
208\r
209 @return Microcode count\r
210**/\r
211UINTN\r
212GetMicrocodeInfo (\r
2ed65824
JY
213 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
214 IN UINTN DescriptorCount, OPTIONAL\r
88266859 215 OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL\r
2ed65824 216 OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL\r
88266859
JY
217 )\r
218{\r
2ed65824
JY
219 VOID *MicrocodePatchAddress;\r
220 UINTN MicrocodePatchRegionSize;\r
88266859
JY
221 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
222 UINTN MicrocodeEnd;\r
223 UINTN TotalSize;\r
224 UINTN Count;\r
225 UINT64 ImageAttributes;\r
2ed65824 226 BOOLEAN IsInUse;\r
31d060d9
JY
227 EFI_STATUS Status;\r
228 UINT32 AttemptStatus;\r
229 UINTN TargetCpuIndex;\r
88266859 230\r
2ed65824
JY
231 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
232 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
233\r
234 DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));\r
88266859
JY
235\r
236 Count = 0;\r
88266859 237\r
2ed65824 238 MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;\r
88266859
JY
239 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
240 do {\r
241 if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {\r
242 //\r
243 // It is the microcode header. It is not the padding data between microcode patches\r
244 // becasue the padding data should not include 0x00000001 and it should be the repeated\r
245 // byte format (like 0xXYXYXYXY....).\r
246 //\r
247 if (MicrocodeEntryPoint->DataSize == 0) {\r
248 TotalSize = 2048;\r
249 } else {\r
250 TotalSize = MicrocodeEntryPoint->TotalSize;\r
251 }\r
252\r
31d060d9
JY
253 TargetCpuIndex = (UINTN)-1;\r
254 Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);\r
255 if (!EFI_ERROR(Status)) {\r
256 IsInUse = TRUE;\r
257 ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
258 MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;\r
259 } else {\r
260 IsInUse = FALSE;\r
261 }\r
2ed65824 262\r
88266859
JY
263 if (ImageDescriptor != NULL && DescriptorCount > Count) {\r
264 ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);\r
265 CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);\r
266 ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
267 ImageDescriptor[Count].ImageIdName = NULL;\r
268 ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;\r
269 ImageDescriptor[Count].VersionName = NULL;\r
270 ImageDescriptor[Count].Size = TotalSize;\r
271 ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;\r
2ed65824 272 if (IsInUse) {\r
88266859
JY
273 ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;\r
274 }\r
275 ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;\r
276 ImageDescriptor[Count].AttributesSetting = ImageAttributes;\r
277 ImageDescriptor[Count].Compatibilities = 0;\r
278 ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback\r
279 ImageDescriptor[Count].LastAttemptVersion = 0;\r
280 ImageDescriptor[Count].LastAttemptStatus = 0;\r
281 ImageDescriptor[Count].HardwareInstance = 0;\r
282 }\r
2ed65824
JY
283 if (MicrocodeInfo != NULL && DescriptorCount > Count) {\r
284 MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;\r
285 MicrocodeInfo[Count].TotalSize = TotalSize;\r
286 MicrocodeInfo[Count].InUse = IsInUse;\r
287 }\r
88266859
JY
288 } else {\r
289 //\r
290 // It is the padding data between the microcode patches for microcode patches alignment.\r
291 // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
292 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
293 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
294 // find the next possible microcode patch header.\r
295 //\r
296 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
297 continue;\r
298 }\r
299\r
300 Count++;\r
301 ASSERT(Count < 0xFF);\r
302\r
303 //\r
304 // Get the next patch.\r
305 //\r
306 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
307 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
308\r
309 return Count;\r
310}\r
311\r
31d060d9
JY
312/**\r
313 Return matched processor information.\r
314\r
315 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
316 @param[in] ProcessorSignature The processor signature to be matched\r
317 @param[in] ProcessorFlags The processor flags to be matched\r
318 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
319 On output, the index of target CPU which matches the Microcode.\r
320\r
321 @return matched processor information.\r
322**/\r
323PROCESSOR_INFO *\r
324GetMatchedProcessor (\r
325 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
326 IN UINT32 ProcessorSignature,\r
327 IN UINT32 ProcessorFlags,\r
328 IN OUT UINTN *TargetCpuIndex\r
329 )\r
330{\r
331 UINTN Index;\r
332\r
333 if (*TargetCpuIndex != (UINTN)-1) {\r
334 Index = *TargetCpuIndex;\r
335 if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
336 ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
337 return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
338 } else {\r
339 return NULL;\r
340 }\r
341 }\r
342\r
343 for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {\r
344 if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
345 ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
346 *TargetCpuIndex = Index;\r
347 return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
348 }\r
349 }\r
350 return NULL;\r
351}\r
352\r
88266859
JY
353/**\r
354 Verify Microcode.\r
355\r
356 Caution: This function may receive untrusted input.\r
357\r
31d060d9
JY
358 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
359 @param[in] Image The Microcode image buffer.\r
360 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
361 @param[in] TryLoad Try to load Microcode or not.\r
362 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
363 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
364 details for the aborted operation. The buffer is allocated by this function\r
365 with AllocatePool(), and it is the caller's responsibility to free it with a\r
366 call to FreePool().\r
367 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
368 On output, the index of target CPU which matches the Microcode.\r
88266859
JY
369\r
370 @retval EFI_SUCCESS The Microcode image passes verification.\r
e9179788 371 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupted.\r
88266859
JY
372 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.\r
373 @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.\r
374 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.\r
375**/\r
376EFI_STATUS\r
377VerifyMicrocode (\r
31d060d9
JY
378 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
379 IN VOID *Image,\r
380 IN UINTN ImageSize,\r
381 IN BOOLEAN TryLoad,\r
382 OUT UINT32 *LastAttemptStatus,\r
383 OUT CHAR16 **AbortReason, OPTIONAL\r
384 IN OUT UINTN *TargetCpuIndex\r
88266859
JY
385 )\r
386{\r
387 UINTN Index;\r
388 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
389 UINTN TotalSize;\r
390 UINTN DataSize;\r
391 UINT32 CurrentRevision;\r
31d060d9 392 PROCESSOR_INFO *ProcessorInfo;\r
5170327b 393 UINT32 InCompleteCheckSum32;\r
88266859
JY
394 UINT32 CheckSum32;\r
395 UINTN ExtendedTableLength;\r
396 UINT32 ExtendedTableCount;\r
397 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
398 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
399 BOOLEAN CorrectMicrocode;\r
400\r
401 //\r
402 // Check HeaderVersion\r
403 //\r
404 MicrocodeEntryPoint = Image;\r
405 if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\r
406 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));\r
407 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
408 if (AbortReason != NULL) {\r
409 *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");\r
410 }\r
411 return EFI_INCOMPATIBLE_VERSION;\r
412 }\r
413 //\r
414 // Check LoaderRevision\r
415 //\r
416 if (MicrocodeEntryPoint->LoaderRevision != 0x1) {\r
417 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));\r
418 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
419 if (AbortReason != NULL) {\r
420 *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");\r
421 }\r
422 return EFI_INCOMPATIBLE_VERSION;\r
423 }\r
424 //\r
1db271df 425 // Check TotalSize\r
88266859
JY
426 //\r
427 if (MicrocodeEntryPoint->DataSize == 0) {\r
428 TotalSize = 2048;\r
429 } else {\r
430 TotalSize = MicrocodeEntryPoint->TotalSize;\r
431 }\r
432 if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {\r
433 DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));\r
434 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
435 if (AbortReason != NULL) {\r
436 *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
437 }\r
438 return EFI_VOLUME_CORRUPTED;\r
439 }\r
1db271df
SZ
440 if ((TotalSize & (SIZE_1KB - 1)) != 0) {\r
441 DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize is not multiples of 1024 bytes (1 KBytes)\n"));\r
442 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
443 if (AbortReason != NULL) {\r
444 *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
445 }\r
446 return EFI_VOLUME_CORRUPTED;\r
447 }\r
88266859 448 if (TotalSize != ImageSize) {\r
2ad34f65 449 DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize not equal to ImageSize\n"));\r
88266859
JY
450 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
451 if (AbortReason != NULL) {\r
452 *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
453 }\r
454 return EFI_VOLUME_CORRUPTED;\r
455 }\r
456 //\r
1db271df 457 // Check DataSize\r
88266859
JY
458 //\r
459 if (MicrocodeEntryPoint->DataSize == 0) {\r
460 DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);\r
461 } else {\r
462 DataSize = MicrocodeEntryPoint->DataSize;\r
463 }\r
464 if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {\r
465 DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));\r
466 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
467 if (AbortReason != NULL) {\r
468 *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
469 }\r
470 return EFI_VOLUME_CORRUPTED;\r
471 }\r
472 if ((DataSize & 0x3) != 0) {\r
1db271df 473 DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize is not multiples of DWORDs\n"));\r
88266859
JY
474 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
475 if (AbortReason != NULL) {\r
476 *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
477 }\r
478 return EFI_VOLUME_CORRUPTED;\r
479 }\r
1db271df
SZ
480 //\r
481 // Check CheckSum32\r
482 //\r
88266859
JY
483 CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));\r
484 if (CheckSum32 != 0) {\r
485 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));\r
486 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
487 if (AbortReason != NULL) {\r
488 *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");\r
489 }\r
490 return EFI_VOLUME_CORRUPTED;\r
491 }\r
5170327b
CC
492 InCompleteCheckSum32 = CheckSum32;\r
493 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
494 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;\r
495 InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;\r
88266859
JY
496\r
497 //\r
498 // Check ProcessorSignature/ProcessorFlags\r
499 //\r
31d060d9
JY
500\r
501 ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);\r
502 if (ProcessorInfo == NULL) {\r
503 CorrectMicrocode = FALSE;\r
88266859
JY
504 ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));\r
505 if (ExtendedTableLength != 0) {\r
506 //\r
507 // Extended Table exist, check if the CPU in support list\r
508 //\r
509 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER));\r
510 //\r
511 // Calculate Extended Checksum\r
512 //\r
3bd91ae2 513 if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) == 0)) {\r
88266859 514 CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
2ad34f65
HW
515 if (CheckSum32 != 0) {\r
516 //\r
517 // Checksum incorrect\r
518 //\r
519 DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for extended table is incorrect\n"));\r
520 } else {\r
88266859
JY
521 //\r
522 // Checksum correct\r
523 //\r
524 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
2ad34f65 525 if (ExtendedTableCount > (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {\r
f635b138 526 DEBUG((DEBUG_ERROR, "VerifyMicrocode - ExtendedTableCount %d is too big\n", ExtendedTableCount));\r
2ad34f65 527 } else {\r
88266859
JY
528 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
529 for (Index = 0; Index < ExtendedTableCount; Index++) {\r
5170327b
CC
530 CheckSum32 = InCompleteCheckSum32;\r
531 CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;\r
532 CheckSum32 += ExtendedTable->ProcessorFlag;\r
533 CheckSum32 += ExtendedTable->Checksum;\r
2ad34f65
HW
534 if (CheckSum32 != 0) {\r
535 DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for ExtendedTable entry with index 0x%x is incorrect\n", Index));\r
536 } else {\r
88266859
JY
537 //\r
538 // Verify Header\r
539 //\r
31d060d9
JY
540 ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);\r
541 if (ProcessorInfo != NULL) {\r
88266859
JY
542 //\r
543 // Find one\r
544 //\r
545 CorrectMicrocode = TRUE;\r
546 break;\r
547 }\r
548 }\r
549 ExtendedTable++;\r
550 }\r
551 }\r
552 }\r
553 }\r
554 }\r
555 if (!CorrectMicrocode) {\r
2ed65824 556 if (TryLoad) {\r
2ad34f65 557 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on Current ProcessorSignature/ProcessorFlags\n"));\r
2ed65824 558 }\r
88266859
JY
559 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
560 if (AbortReason != NULL) {\r
e9179788 561 *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessorSignature/ProcessorFlags"), L"UnsupportedProcessorSignature/ProcessorFlags");\r
88266859
JY
562 }\r
563 return EFI_UNSUPPORTED;\r
564 }\r
565 }\r
566\r
567 //\r
568 // Check UpdateRevision\r
569 //\r
31d060d9
JY
570 CurrentRevision = ProcessorInfo->MicrocodeRevision;\r
571 if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||\r
572 (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {\r
2ed65824
JY
573 if (TryLoad) {\r
574 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));\r
575 }\r
88266859
JY
576 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
577 if (AbortReason != NULL) {\r
578 *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");\r
579 }\r
580 return EFI_INCOMPATIBLE_VERSION;\r
581 }\r
582\r
583 //\r
584 // try load MCU\r
585 //\r
586 if (TryLoad) {\r
31d060d9 587 CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));\r
88266859
JY
588 if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {\r
589 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));\r
590 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
591 if (AbortReason != NULL) {\r
592 *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");\r
593 }\r
594 return EFI_SECURITY_VIOLATION;\r
595 }\r
596 }\r
597\r
598 return EFI_SUCCESS;\r
599}\r
600\r
2ed65824
JY
601/**\r
602 Get next Microcode entrypoint.\r
88266859 603\r
2ed65824
JY
604 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
605 @param[in] MicrocodeEntryPoint Current Microcode entrypoint\r
606\r
607 @return next Microcode entrypoint.\r
608**/\r
609CPU_MICROCODE_HEADER *\r
610GetNextMicrocode (\r
611 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
612 IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint\r
613 )\r
614{\r
615 UINTN Index;\r
616\r
617 for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {\r
618 if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {\r
619 if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {\r
620 // it is last one\r
621 return NULL;\r
88266859 622 } else {\r
2ed65824
JY
623 // return next one\r
624 return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
88266859 625 }\r
88266859 626 }\r
2ed65824 627 }\r
88266859 628\r
2ed65824 629 ASSERT(FALSE);\r
88266859
JY
630 return NULL;\r
631}\r
632\r
e9179788
SZ
633/**\r
634 Get next FIT Microcode entrypoint.\r
635\r
636 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
637 @param[in] MicrocodeEntryPoint Current Microcode entrypoint\r
638\r
639 @return next FIT Microcode entrypoint.\r
640**/\r
641CPU_MICROCODE_HEADER *\r
642GetNextFitMicrocode (\r
643 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
644 IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint\r
645 )\r
646{\r
647 UINTN Index;\r
648\r
649 for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
650 if (MicrocodeEntryPoint == MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint) {\r
651 if (Index == (UINTN) MicrocodeFmpPrivate->FitMicrocodeEntryCount - 1) {\r
652 // it is last one\r
653 return NULL;\r
654 } else {\r
655 // return next one\r
656 return MicrocodeFmpPrivate->FitMicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
657 }\r
658 }\r
659 }\r
660\r
661 ASSERT(FALSE);\r
662 return NULL;\r
663}\r
664\r
665/**\r
666 Find empty FIT Microcode entrypoint.\r
667\r
668 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
669 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
670 @param[out] AvailableSize Available size of the empty FIT Microcode entrypoint.\r
671\r
672 @return Empty FIT Microcode entrypoint.\r
673**/\r
674CPU_MICROCODE_HEADER *\r
675FindEmptyFitMicrocode (\r
676 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
677 IN UINTN ImageSize,\r
678 OUT UINTN *AvailableSize\r
679 )\r
680{\r
681 UINTN Index;\r
682 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
683 CPU_MICROCODE_HEADER *NextMicrocodeEntryPoint;\r
684 VOID *MicrocodePatchAddress;\r
685 UINTN MicrocodePatchRegionSize;\r
686\r
687 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
688 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
689\r
690 for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
691 if (MicrocodeFmpPrivate->FitMicrocodeInfo[Index].Empty) {\r
692 MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;\r
693 NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);\r
694 if (NextMicrocodeEntryPoint != NULL) {\r
695 *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;\r
696 } else {\r
697 *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;\r
698 }\r
699 if (*AvailableSize >= ImageSize) {\r
700 return MicrocodeEntryPoint;\r
701 }\r
702 }\r
703 }\r
704\r
705 return NULL;\r
706}\r
707\r
708/**\r
709 Find unused FIT Microcode entrypoint.\r
710\r
711 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
712 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
713 @param[out] AvailableSize Available size of the unused FIT Microcode entrypoint.\r
714\r
715 @return Unused FIT Microcode entrypoint.\r
716**/\r
717CPU_MICROCODE_HEADER *\r
718FindUnusedFitMicrocode (\r
719 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
720 IN UINTN ImageSize,\r
721 OUT UINTN *AvailableSize\r
722 )\r
723{\r
724 UINTN Index;\r
725 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
726 CPU_MICROCODE_HEADER *NextMicrocodeEntryPoint;\r
727 VOID *MicrocodePatchAddress;\r
728 UINTN MicrocodePatchRegionSize;\r
729\r
730 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
731 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
732\r
733 for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
734 if (!MicrocodeFmpPrivate->FitMicrocodeInfo[Index].InUse) {\r
735 MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;\r
736 NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);\r
737 if (NextMicrocodeEntryPoint != NULL) {\r
738 *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;\r
739 } else {\r
740 *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;\r
741 }\r
742 if (*AvailableSize >= ImageSize) {\r
743 return MicrocodeEntryPoint;\r
744 }\r
745 }\r
746 }\r
747\r
748 return NULL;\r
749}\r
750\r
88266859
JY
751/**\r
752 Get current Microcode used region size.\r
753\r
2ed65824
JY
754 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
755\r
88266859
JY
756 @return current Microcode used region size.\r
757**/\r
758UINTN\r
759GetCurrentMicrocodeUsedRegionSize (\r
2ed65824 760 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
88266859
JY
761 )\r
762{\r
2ed65824 763 if (MicrocodeFmpPrivate->DescriptorCount == 0) {\r
88266859
JY
764 return 0;\r
765 }\r
88266859 766\r
2ed65824
JY
767 return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint\r
768 + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize\r
769 - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;\r
88266859
JY
770}\r
771\r
772/**\r
773 Update Microcode.\r
774\r
775 @param[in] Address The flash address of Microcode.\r
776 @param[in] Image The Microcode image buffer.\r
777 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
778 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
779\r
780 @retval EFI_SUCCESS The Microcode image is updated.\r
781 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
782**/\r
783EFI_STATUS\r
784UpdateMicrocode (\r
785 IN UINT64 Address,\r
786 IN VOID *Image,\r
787 IN UINTN ImageSize,\r
788 OUT UINT32 *LastAttemptStatus\r
789 )\r
790{\r
791 EFI_STATUS Status;\r
792\r
793 DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
794 DEBUG((DEBUG_INFO, " Address - 0x%lx,", Address));\r
e9179788 795 DEBUG((DEBUG_INFO, " Length - 0x%x\n", ImageSize));\r
88266859
JY
796\r
797 Status = MicrocodeFlashWrite (\r
798 Address,\r
799 Image,\r
800 ImageSize\r
801 );\r
802 if (!EFI_ERROR(Status)) {\r
803 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
804 } else {\r
805 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
806 }\r
807 return Status;\r
808}\r
809\r
e9179788
SZ
810/**\r
811 Update Microcode flash region with FIT.\r
812\r
813 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
814 @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated\r
815 @param[in] Image The Microcode image buffer.\r
816 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
817 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
818\r
819 @retval EFI_SUCCESS The Microcode image is written.\r
820 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
821**/\r
822EFI_STATUS\r
823UpdateMicrocodeFlashRegionWithFit (\r
824 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
825 IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,\r
826 IN VOID *Image,\r
827 IN UINTN ImageSize,\r
828 OUT UINT32 *LastAttemptStatus\r
829 )\r
830{\r
831 VOID *MicrocodePatchAddress;\r
832 UINTN MicrocodePatchRegionSize;\r
833 UINTN TargetTotalSize;\r
834 EFI_STATUS Status;\r
835 VOID *MicrocodePatchScratchBuffer;\r
836 UINT8 *ScratchBufferPtr;\r
837 UINTN ScratchBufferSize;\r
838 UINTN RestSize;\r
839 UINTN AvailableSize;\r
840 VOID *NextMicrocodeEntryPoint;\r
841 VOID *EmptyFitMicrocodeEntry;\r
842 VOID *UnusedFitMicrocodeEntry;\r
843\r
844 DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegionWithFit: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
845\r
846 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
847 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
848\r
849 MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
850 if (MicrocodePatchScratchBuffer == NULL) {\r
851 DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
852 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
853 return EFI_OUT_OF_RESOURCES;\r
854 }\r
855 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
856 ScratchBufferSize = 0;\r
857\r
858 //\r
859 // Target data collection\r
860 //\r
861 TargetTotalSize = 0;\r
862 AvailableSize = 0;\r
863 if (TargetMicrocodeEntryPoint != NULL) {\r
864 if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
865 TargetTotalSize = 2048;\r
866 } else {\r
867 TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
868 }\r
869 DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));\r
870 NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
871 DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
872 if (NextMicrocodeEntryPoint != NULL) {\r
873 ASSERT ((UINTN) NextMicrocodeEntryPoint >= ((UINTN) TargetMicrocodeEntryPoint + TargetTotalSize));\r
874 AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) TargetMicrocodeEntryPoint;\r
875 } else {\r
876 AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) TargetMicrocodeEntryPoint;\r
877 }\r
878 DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));\r
879 ASSERT (AvailableSize >= TargetTotalSize);\r
880 }\r
881 //\r
882 // Total Size means the Microcode size.\r
883 // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.\r
884 //\r
885 // (1)\r
886 // +------+-----------+-----+------+===================+\r
887 // | MCU1 | Microcode | PAD | MCU2 | Empty |\r
888 // +------+-----------+-----+------+===================+\r
889 // | TotalSize |\r
890 // |<-AvailableSize->|\r
891 //\r
892 // (2)\r
893 // +------+-----------+===================+\r
894 // | MCU | Microcode | Empty |\r
895 // +------+-----------+===================+\r
896 // | TotalSize |\r
897 // |<- AvailableSize ->|\r
898 //\r
899\r
900 //\r
901 // Update based on policy\r
902 //\r
903\r
904 //\r
905 // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
906 //\r
907 if (AvailableSize >= ImageSize) {\r
908 DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
909 //\r
910 // +------+------------+------+===================+\r
911 // |Other | Old Image | ... | Empty |\r
912 // +------+------------+------+===================+\r
913 //\r
914 // +------+---------+--+------+===================+\r
915 // |Other |New Image|FF| ... | Empty |\r
916 // +------+---------+--+------+===================+\r
917 //\r
918 // 1.1. Copy new image\r
919 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
920 ScratchBufferSize += ImageSize;\r
921 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
922 // 1.2. Pad 0xFF\r
923 RestSize = AvailableSize - ImageSize;\r
924 if (RestSize > 0) {\r
925 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
926 ScratchBufferSize += RestSize;\r
927 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
928 }\r
929 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
930 return Status;\r
931 }\r
932\r
933 //\r
934 // 2. If there is empty FIT microcode entry with enough space, use it.\r
935 //\r
936 EmptyFitMicrocodeEntry = FindEmptyFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);\r
937 if (EmptyFitMicrocodeEntry != NULL) {\r
938 DEBUG((DEBUG_INFO, "Use empty FIT microcode entry\n"));\r
939 // 2.1. Copy new image\r
940 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
941 ScratchBufferSize += ImageSize;\r
942 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
943 // 2.2. Pad 0xFF\r
944 RestSize = AvailableSize - ImageSize;\r
945 if (RestSize > 0) {\r
946 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
947 ScratchBufferSize += RestSize;\r
948 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
949 }\r
950 Status = UpdateMicrocode ((UINTN) EmptyFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
951 if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {\r
952 //\r
953 // Empty old microcode.\r
954 //\r
955 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
956 SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);\r
957 ScratchBufferSize = TargetTotalSize;\r
958 ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;\r
959 UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
960 }\r
961 return Status;\r
962 }\r
963\r
964 //\r
965 // 3. If there is unused microcode entry with enough space, use it.\r
966 //\r
967 UnusedFitMicrocodeEntry = FindUnusedFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);\r
968 if (UnusedFitMicrocodeEntry != NULL) {\r
969 DEBUG((DEBUG_INFO, "Use unused FIT microcode entry\n"));\r
970 // 3.1. Copy new image\r
971 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
972 ScratchBufferSize += ImageSize;\r
973 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
974 // 3.2. Pad 0xFF\r
975 RestSize = AvailableSize - ImageSize;\r
976 if (RestSize > 0) {\r
977 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
978 ScratchBufferSize += RestSize;\r
979 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
980 }\r
981 Status = UpdateMicrocode ((UINTN) UnusedFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
982 if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {\r
983 //\r
984 // Empty old microcode.\r
985 //\r
986 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
987 SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);\r
988 ScratchBufferSize = TargetTotalSize;\r
989 ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;\r
990 UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
991 }\r
992 return Status;\r
993 }\r
994\r
995 //\r
996 // 4. No usable FIT microcode entry.\r
997 //\r
998 DEBUG((DEBUG_ERROR, "No usable FIT microcode entry\n"));\r
999 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
1000 Status = EFI_OUT_OF_RESOURCES;\r
1001\r
1002 return Status;\r
1003}\r
1004\r
88266859 1005/**\r
2ed65824 1006 Update Microcode flash region.\r
88266859 1007\r
2ed65824 1008 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
31d060d9 1009 @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated\r
2ed65824
JY
1010 @param[in] Image The Microcode image buffer.\r
1011 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
1012 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
88266859 1013\r
2ed65824
JY
1014 @retval EFI_SUCCESS The Microcode image is written.\r
1015 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
88266859
JY
1016**/\r
1017EFI_STATUS\r
2ed65824
JY
1018UpdateMicrocodeFlashRegion (\r
1019 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
31d060d9 1020 IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,\r
2ed65824
JY
1021 IN VOID *Image,\r
1022 IN UINTN ImageSize,\r
1023 OUT UINT32 *LastAttemptStatus\r
88266859
JY
1024 )\r
1025{\r
2ed65824
JY
1026 VOID *MicrocodePatchAddress;\r
1027 UINTN MicrocodePatchRegionSize;\r
31d060d9 1028 UINTN TargetTotalSize;\r
88266859 1029 UINTN UsedRegionSize;\r
2ed65824
JY
1030 EFI_STATUS Status;\r
1031 VOID *MicrocodePatchScratchBuffer;\r
1032 UINT8 *ScratchBufferPtr;\r
1033 UINTN ScratchBufferSize;\r
1034 UINTN RestSize;\r
1035 UINTN AvailableSize;\r
1036 VOID *NextMicrocodeEntryPoint;\r
1037 MICROCODE_INFO *MicrocodeInfo;\r
1038 UINTN MicrocodeCount;\r
1039 UINTN Index;\r
1040\r
1041 DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
88266859 1042\r
2ed65824
JY
1043 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
1044 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
1045\r
1046 MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
1047 if (MicrocodePatchScratchBuffer == NULL) {\r
1048 DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
1049 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
1050 return EFI_OUT_OF_RESOURCES;\r
88266859 1051 }\r
2ed65824
JY
1052 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
1053 ScratchBufferSize = 0;\r
88266859 1054\r
2ed65824 1055 //\r
31d060d9 1056 // Target data collection\r
2ed65824 1057 //\r
31d060d9 1058 TargetTotalSize = 0;\r
2ed65824
JY
1059 AvailableSize = 0;\r
1060 NextMicrocodeEntryPoint = NULL;\r
31d060d9
JY
1061 if (TargetMicrocodeEntryPoint != NULL) {\r
1062 if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
1063 TargetTotalSize = 2048;\r
88266859 1064 } else {\r
31d060d9 1065 TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
88266859 1066 }\r
31d060d9
JY
1067 DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));\r
1068 NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
2ed65824
JY
1069 DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
1070 if (NextMicrocodeEntryPoint != NULL) {\r
31d060d9
JY
1071 ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
1072 AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;\r
2ed65824 1073 } else {\r
31d060d9 1074 AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;\r
2ed65824
JY
1075 }\r
1076 DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));\r
e9179788 1077 ASSERT (AvailableSize >= TargetTotalSize);\r
2ed65824 1078 }\r
2ed65824
JY
1079 UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);\r
1080 DEBUG((DEBUG_INFO, " UsedRegionSize - 0x%x\n", UsedRegionSize));\r
31d060d9
JY
1081 ASSERT (UsedRegionSize >= TargetTotalSize);\r
1082 if (TargetMicrocodeEntryPoint != NULL) {\r
1083 ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
2ed65824
JY
1084 }\r
1085 //\r
e9179788
SZ
1086 // Total Size means the Microcode size.\r
1087 // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.\r
2ed65824
JY
1088 //\r
1089 // (1)\r
1090 // +------+-----------+-----+------+===================+\r
1091 // | MCU1 | Microcode | PAD | MCU2 | Empty |\r
1092 // +------+-----------+-----+------+===================+\r
1093 // | TotalSize |\r
1094 // |<-AvailableSize->|\r
1095 // |<- UsedRegionSize ->|\r
1096 //\r
1097 // (2)\r
1098 // +------+-----------+===================+\r
1099 // | MCU | Microcode | Empty |\r
1100 // +------+-----------+===================+\r
1101 // | TotalSize |\r
1102 // |<- AvailableSize ->|\r
1103 // |<-UsedRegionSize->|\r
1104 //\r
1105\r
1106 //\r
1107 // Update based on policy\r
1108 //\r
1109\r
1110 //\r
1111 // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
1112 //\r
1113 if (AvailableSize >= ImageSize) {\r
1114 DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
1115 //\r
1116 // +------+------------+------+===================+\r
e9179788 1117 // |Other | Old Image | ... | Empty |\r
2ed65824
JY
1118 // +------+------------+------+===================+\r
1119 //\r
1120 // +------+---------+--+------+===================+\r
e9179788 1121 // |Other |New Image|FF| ... | Empty |\r
2ed65824
JY
1122 // +------+---------+--+------+===================+\r
1123 //\r
1124 // 1.1. Copy new image\r
1125 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
1126 ScratchBufferSize += ImageSize;\r
31d060d9 1127 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1128 // 1.2. Pad 0xFF\r
1129 RestSize = AvailableSize - ImageSize;\r
1130 if (RestSize > 0) {\r
1131 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
1132 ScratchBufferSize += RestSize;\r
31d060d9 1133 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824 1134 }\r
31d060d9 1135 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
2ed65824 1136 return Status;\r
88266859
JY
1137 }\r
1138\r
2ed65824
JY
1139 //\r
1140 // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.\r
1141 //\r
31d060d9
JY
1142 if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {\r
1143 if (TargetMicrocodeEntryPoint == NULL) {\r
2ed65824
JY
1144 DEBUG((DEBUG_INFO, "Append new microcode\n"));\r
1145 //\r
1146 // +------+------------+------+===================+\r
1147 // |Other1| Other |Other2| Empty |\r
1148 // +------+------------+------+===================+\r
1149 //\r
1150 // +------+------------+------+-----------+=======+\r
1151 // |Other1| Other |Other2| New Image | Empty |\r
1152 // +------+------------+------+-----------+=======+\r
1153 //\r
1154 Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);\r
1155 } else {\r
1156 DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));\r
1157 //\r
1158 // +------+------------+------+===================+\r
e9179788 1159 // |Other | Old Image | ... | Empty |\r
2ed65824
JY
1160 // +------+------------+------+===================+\r
1161 //\r
1162 // +------+---------------+------+================+\r
e9179788 1163 // |Other | New Image | ... | Empty |\r
2ed65824
JY
1164 // +------+---------------+------+================+\r
1165 //\r
1166 // 2.1. Copy new image\r
31d060d9 1167 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
2ed65824 1168 ScratchBufferSize += ImageSize;\r
31d060d9 1169 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1170 // 2.2. Copy rest images after the old image.\r
1171 if (NextMicrocodeEntryPoint != 0) {\r
1172 RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);\r
e9179788 1173 CopyMem (ScratchBufferPtr, NextMicrocodeEntryPoint, RestSize);\r
2ed65824 1174 ScratchBufferSize += RestSize;\r
31d060d9 1175 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824 1176 }\r
31d060d9 1177 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
2ed65824
JY
1178 }\r
1179 return Status;\r
1180 }\r
1181\r
1182 //\r
1183 // 3. The new image can be put in MCU region, but not all others can be put.\r
1184 // So all the unused MCU is removed.\r
1185 //\r
1186 if (MicrocodePatchRegionSize >= ImageSize) {\r
1187 //\r
1188 // +------+------------+------+===================+\r
1189 // |Other1| Old Image |Other2| Empty |\r
1190 // +------+------------+------+===================+\r
1191 //\r
1192 // +-------------------------------------+--------+\r
1193 // | New Image | Other |\r
1194 // +-------------------------------------+--------+\r
1195 //\r
1196 DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));\r
1197\r
1198 MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;\r
1199 MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;\r
1200\r
1201 // 3.1. Copy new image\r
31d060d9 1202 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
2ed65824 1203 ScratchBufferSize += ImageSize;\r
31d060d9 1204 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1205 // 3.2. Copy some others to rest buffer\r
1206 for (Index = 0; Index < MicrocodeCount; Index++) {\r
1207 if (!MicrocodeInfo[Index].InUse) {\r
1208 continue;\r
1209 }\r
31d060d9 1210 if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {\r
2ed65824
JY
1211 continue;\r
1212 }\r
1213 if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {\r
1214 CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);\r
1215 ScratchBufferSize += MicrocodeInfo[Index].TotalSize;\r
31d060d9 1216 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1217 }\r
1218 }\r
1219 // 3.3. Pad 0xFF\r
1220 RestSize = MicrocodePatchRegionSize - ScratchBufferSize;\r
1221 if (RestSize > 0) {\r
1222 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
1223 ScratchBufferSize += RestSize;\r
31d060d9 1224 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1225 }\r
1226 Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
1227 return Status;\r
1228 }\r
1229\r
1230 //\r
1231 // 4. The new image size is bigger than the whole MCU region.\r
1232 //\r
1233 DEBUG((DEBUG_ERROR, "Microcode too big\n"));\r
1234 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
1235 Status = EFI_OUT_OF_RESOURCES;\r
1236\r
1237 return Status;\r
1238}\r
1239\r
1240/**\r
1241 Write Microcode.\r
1242\r
1243 Caution: This function may receive untrusted input.\r
1244\r
1245 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
1246 @param[in] Image The Microcode image buffer.\r
1247 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
1248 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
1249 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
1250 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
1251 details for the aborted operation. The buffer is allocated by this function\r
1252 with AllocatePool(), and it is the caller's responsibility to free it with a\r
1253 call to FreePool().\r
1254\r
1255 @retval EFI_SUCCESS The Microcode image is written.\r
e9179788 1256 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupted.\r
2ed65824
JY
1257 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.\r
1258 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.\r
1259 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
1260**/\r
1261EFI_STATUS\r
1262MicrocodeWrite (\r
1263 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
1264 IN VOID *Image,\r
1265 IN UINTN ImageSize,\r
1266 OUT UINT32 *LastAttemptVersion,\r
1267 OUT UINT32 *LastAttemptStatus,\r
1268 OUT CHAR16 **AbortReason\r
1269 )\r
1270{\r
1271 EFI_STATUS Status;\r
1272 VOID *AlignedImage;\r
31d060d9
JY
1273 CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint;\r
1274 UINTN TargetCpuIndex;\r
1275 UINTN TargetMicrcodeIndex;\r
2ed65824 1276\r
88266859
JY
1277 //\r
1278 // MCU must be 16 bytes aligned\r
1279 //\r
1280 AlignedImage = AllocateCopyPool(ImageSize, Image);\r
1281 if (AlignedImage == NULL) {\r
1282 DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));\r
1283 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
1284 return EFI_OUT_OF_RESOURCES;\r
1285 }\r
1286\r
31d060d9
JY
1287 TargetCpuIndex = (UINTN)-1;\r
1288 Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);\r
88266859
JY
1289 if (EFI_ERROR(Status)) {\r
1290 DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));\r
1291 FreePool(AlignedImage);\r
1292 return Status;\r
1293 }\r
1294 DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));\r
e9179788 1295 *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;\r
88266859 1296\r
31d060d9
JY
1297 DEBUG((DEBUG_INFO, " TargetCpuIndex - 0x%x\n", TargetCpuIndex));\r
1298 ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
1299 TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;\r
1300 DEBUG((DEBUG_INFO, " TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));\r
1301 if (TargetMicrcodeIndex != (UINTN)-1) {\r
1302 ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);\r
1303 TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;\r
1304 } else {\r
1305 TargetMicrocodeEntryPoint = NULL;\r
1306 }\r
1307 DEBUG((DEBUG_INFO, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));\r
1308\r
e9179788
SZ
1309 if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {\r
1310 Status = UpdateMicrocodeFlashRegionWithFit (\r
1311 MicrocodeFmpPrivate,\r
1312 TargetMicrocodeEntryPoint,\r
1313 AlignedImage,\r
1314 ImageSize,\r
1315 LastAttemptStatus\r
1316 );\r
1317 } else {\r
1318 Status = UpdateMicrocodeFlashRegion (\r
1319 MicrocodeFmpPrivate,\r
1320 TargetMicrocodeEntryPoint,\r
1321 AlignedImage,\r
1322 ImageSize,\r
1323 LastAttemptStatus\r
1324 );\r
1325 }\r
88266859
JY
1326\r
1327 FreePool(AlignedImage);\r
1328\r
1329 return Status;\r
1330}\r
1331\r
1332\r