1882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/** @file
2882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  SetImage instance to update Microcode.
3882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
4882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Caution: This module requires additional review when modified.
5882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  This module will have external input - capsule image.
6882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  This external input must be validated carefully to avoid security issue like
7882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  buffer overflow, integer overflow.
8882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
9882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.
10882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
11882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
12882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  This program and the accompanying materials
13882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  are licensed and made available under the terms and conditions of the BSD License
14882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  which accompanies this distribution.  The full text of the license may be found at
15882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  http://opensource.org/licenses/bsd-license.php
16882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
17882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
20882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
21882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
22882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao#include "MicrocodeUpdate.h"
23882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
24882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
25882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Get Microcode Region.
26882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
27882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @param[out] MicrocodePatchAddress      The address of Microcode
28882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @param[out] MicrocodePatchRegionSize   The region size of Microcode
29882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
30882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @retval TRUE   The Microcode region is returned.
31882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @retval FALSE  No Microcode region.
32882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
33882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoBOOLEAN
34882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoGetMicrocodeRegion (
352ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  OUT VOID     **MicrocodePatchAddress,
362ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  OUT UINTN    *MicrocodePatchRegionSize
37882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
38882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
392ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);
402ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);
41882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
422ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {
43882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return FALSE;
44882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
45882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
46882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return TRUE;
47882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
48882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
49882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
50882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Get Microcode update signature of currently loaded Microcode update.
51882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
52882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @return  Microcode signature.
53882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
54882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
55882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoUINT32
56882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoGetCurrentMicrocodeSignature (
57882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  VOID
58882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
59882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
60882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINT64 Signature;
61882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
62882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);
63882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
64882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);
65882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return (UINT32)RShiftU64(Signature, 32);
66882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
67882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
68882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
69882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Get current processor signature.
70882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
71882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @return current processor signature.
72882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
73882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoUINT32
74882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoGetCurrentProcessorSignature (
75882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  VOID
76882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
77882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
78882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINT32                                  RegEax;
79882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
80882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return RegEax;
81882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
82882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
83882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
84882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Get current platform ID.
85882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
86882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @return current platform ID.
87882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
88882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoUINT8
89882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoGetCurrentPlatformId (
90882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  VOID
91882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
92882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
93882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINT8                                   PlatformId;
94882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
95882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);
96882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return PlatformId;
97882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
98882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
99882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
100882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Load new Microcode.
101882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
102882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @param[in] Address  The address of new Microcode.
103882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
104882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @return  Loaded Microcode signature.
105882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
106882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
107882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoUINT32
108882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoLoadMicrocode (
109882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  IN UINT64  Address
110882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
111882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
112882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);
113882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return GetCurrentMicrocodeSignature();
114882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
115882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
116882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
11731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  Load Microcode on an Application Processor.
11831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  The function prototype for invoking a function on an Application Processor.
11931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
12031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in,out] Buffer  The pointer to private data buffer.
12131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao**/
12231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoVOID
12331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoEFIAPI
12431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoMicrocodeLoadAp (
12531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN OUT VOID  *Buffer
12631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  )
12731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao{
12831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  MICROCODE_LOAD_BUFFER                *MicrocodeLoadBuffer;
12931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
13031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  MicrocodeLoadBuffer = Buffer;
13131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);
13231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao}
13331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
13431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao/**
13531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  Load new Microcode on this processor
1362ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
13731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
13831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  CpuIndex                   The index of the processor.
13931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  Address                    The address of new Microcode.
14031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
14131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @return  Loaded Microcode signature.
1422ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
1432ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao**/
14431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoUINT32
14531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoLoadMicrocodeOnThis (
14631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
14731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN  UINTN                       CpuIndex,
14831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN  UINT64                      Address
1492ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  )
1502ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao{
15131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  EFI_STATUS                           Status;
15231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  EFI_MP_SERVICES_PROTOCOL             *MpService;
15331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  MICROCODE_LOAD_BUFFER                MicrocodeLoadBuffer;
1542ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
15531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {
15631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    return LoadMicrocode (Address);
15731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  } else {
15831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    MpService = MicrocodeFmpPrivate->MpService;
15931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    MicrocodeLoadBuffer.Address = Address;
16031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    MicrocodeLoadBuffer.Revision = 0;
16131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    Status = MpService->StartupThisAP (
16231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                          MpService,
16331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                          MicrocodeLoadAp,
16431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                          CpuIndex,
16531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                          NULL,
16631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                          0,
16731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                          &MicrocodeLoadBuffer,
16831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                          NULL
16931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                          );
17031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    ASSERT_EFI_ERROR(Status);
17131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    return MicrocodeLoadBuffer.Revision;
1722ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  }
17331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao}
17431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
17531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao/**
17631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  Collect processor information.
17731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  The function prototype for invoking a function on an Application Processor.
17831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
17931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in,out] Buffer  The pointer to private data buffer.
18031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao**/
18131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoVOID
18231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoEFIAPI
18331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoCollectProcessorInfo (
18431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN OUT VOID  *Buffer
18531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  )
18631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao{
18731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  PROCESSOR_INFO  *ProcessorInfo;
18831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
18931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  ProcessorInfo = Buffer;
19031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();
19131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  ProcessorInfo->PlatformId = GetCurrentPlatformId();
19231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();
1932ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao}
1942ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
1952ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao/**
196882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Get current Microcode information.
197882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
19831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
19931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  in MicrocodeFmpPrivate must be initialized.
20031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
20131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
20231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  in MicrocodeFmpPrivate may not be avaiable in this function.
2032ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
2042ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]   MicrocodeFmpPrivate        The Microcode driver private data
2052ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]   DescriptorCount            The count of Microcode ImageDescriptor allocated.
2062ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[out]  ImageDescriptor            Microcode ImageDescriptor
2072ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[out]  MicrocodeInfo              Microcode information
208882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
209882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @return Microcode count
210882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
211882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoUINTN
212882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoGetMicrocodeInfo (
2132ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN  MICROCODE_FMP_PRIVATE_DATA     *MicrocodeFmpPrivate,
2142ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN  UINTN                          DescriptorCount,  OPTIONAL
215882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR  *ImageDescriptor, OPTIONAL
2162ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  OUT MICROCODE_INFO                 *MicrocodeInfo    OPTIONAL
217882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
218882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
2192ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  VOID                                    *MicrocodePatchAddress;
2202ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UINTN                                   MicrocodePatchRegionSize;
221882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
222882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINTN                                   MicrocodeEnd;
223882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINTN                                   TotalSize;
224882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINTN                                   Count;
225882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINT64                                  ImageAttributes;
2262ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  BOOLEAN                                 IsInUse;
22731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  EFI_STATUS                              Status;
22831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  UINT32                                  AttemptStatus;
22931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  UINTN                                   TargetCpuIndex;
230882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
2312ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
2322ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
2332ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
2342ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));
235882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
236882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Count = 0;
237882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
2382ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;
239882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
240882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  do {
241882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {
242882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      //
243882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // It is the microcode header. It is not the padding data between microcode patches
244882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // becasue the padding data should not include 0x00000001 and it should be the repeated
245882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // byte format (like 0xXYXYXYXY....).
246882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      //
247882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      if (MicrocodeEntryPoint->DataSize == 0) {
248882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        TotalSize = 2048;
249882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      } else {
250882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        TotalSize = MicrocodeEntryPoint->TotalSize;
251882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      }
252882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
25331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      TargetCpuIndex = (UINTN)-1;
25431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);
25531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      if (!EFI_ERROR(Status)) {
25631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        IsInUse = TRUE;
25731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
25831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;
25931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      } else {
26031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        IsInUse = FALSE;
26131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      }
2622ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
263882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      if (ImageDescriptor != NULL && DescriptorCount > Count) {
264882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);
265882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);
266882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;
267882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].ImageIdName = NULL;
268882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;
269882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].VersionName = NULL;
270882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].Size = TotalSize;
271882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;
2722ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        if (IsInUse) {
273882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao          ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;
274882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        }
275882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;
276882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].AttributesSetting = ImageAttributes;
277882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].Compatibilities = 0;
278882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback
279882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].LastAttemptVersion = 0;
280882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].LastAttemptStatus = 0;
281882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        ImageDescriptor[Count].HardwareInstance = 0;
282882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      }
2832ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      if (MicrocodeInfo != NULL && DescriptorCount > Count) {
2842ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;
2852ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        MicrocodeInfo[Count].TotalSize = TotalSize;
2862ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        MicrocodeInfo[Count].InUse = IsInUse;
2872ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      }
288882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    } else {
289882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      //
290882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // It is the padding data between the microcode patches for microcode patches alignment.
291882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // Because the microcode patch is the multiple of 1-KByte, the padding data should not
292882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
293882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
294882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // find the next possible microcode patch header.
295882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      //
296882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
297882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      continue;
298882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
299882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
300882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    Count++;
301882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    ASSERT(Count < 0xFF);
302882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
303882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    //
304882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    // Get the next patch.
305882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    //
306882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
307882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
308882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
309882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return Count;
310882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
311882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
312882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
31331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  Return matched processor information.
31431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
31531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
31631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  ProcessorSignature         The processor signature to be matched
31731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  ProcessorFlags             The processor flags to be matched
31831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
31931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                                         On output, the index of target CPU which matches the Microcode.
32031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
32131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @return matched processor information.
32231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao**/
32331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoPROCESSOR_INFO *
32431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen YaoGetMatchedProcessor (
32531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
32631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN UINT32                      ProcessorSignature,
32731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN UINT32                      ProcessorFlags,
32831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN OUT UINTN                   *TargetCpuIndex
32931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  )
33031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao{
33131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  UINTN  Index;
33231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
33331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  if (*TargetCpuIndex != (UINTN)-1) {
33431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    Index = *TargetCpuIndex;
33531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
33631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
33731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      return &MicrocodeFmpPrivate->ProcessorInfo[Index];
33831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    } else {
33931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      return NULL;
34031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    }
34131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  }
34231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
34331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
34431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
34531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
34631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      *TargetCpuIndex = Index;
34731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      return &MicrocodeFmpPrivate->ProcessorInfo[Index];
34831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    }
34931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  }
35031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  return NULL;
35131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao}
35231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
35331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao/**
354882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Verify Microcode.
355882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
356882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Caution: This function may receive untrusted input.
357882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
35831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
35931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  Image                      The Microcode image buffer.
36031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
36131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  TryLoad                    Try to load Microcode or not.
36231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
36331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[out] AbortReason                A pointer to a pointer to a null-terminated string providing more
36431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                                         details for the aborted operation. The buffer is allocated by this function
36531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                                         with AllocatePool(), and it is the caller's responsibility to free it with a
36631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                                         call to FreePool().
36731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
36831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                                         On output, the index of target CPU which matches the Microcode.
369882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
370882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @retval EFI_SUCCESS               The Microcode image passes verification.
371882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.
372882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.
373882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @retval EFI_UNSUPPORTED           The Microcode ProcessorSignature or ProcessorFlags is incorrect.
374882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.
375882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
376882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoEFI_STATUS
377882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoVerifyMicrocode (
37831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
37931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN  VOID                        *Image,
38031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN  UINTN                       ImageSize,
38131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN  BOOLEAN                     TryLoad,
38231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  OUT UINT32                      *LastAttemptStatus,
38331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  OUT CHAR16                      **AbortReason,   OPTIONAL
38431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN OUT UINTN                    *TargetCpuIndex
385882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
386882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
387882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINTN                                   Index;
388882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
389882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINTN                                   TotalSize;
390882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINTN                                   DataSize;
391882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINT32                                  CurrentRevision;
39231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  PROCESSOR_INFO                          *ProcessorInfo;
393882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINT32                                  CheckSum32;
394882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINTN                                   ExtendedTableLength;
395882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINT32                                  ExtendedTableCount;
396882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  CPU_MICROCODE_EXTENDED_TABLE            *ExtendedTable;
397882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  CPU_MICROCODE_EXTENDED_TABLE_HEADER     *ExtendedTableHeader;
398882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  BOOLEAN                                 CorrectMicrocode;
399882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
400882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
401882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  // Check HeaderVersion
402882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
403882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  MicrocodeEntryPoint = Image;
404882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
405882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));
406882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
407882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (AbortReason != NULL) {
408882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");
409882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
410882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return EFI_INCOMPATIBLE_VERSION;
411882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
412882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
413882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  // Check LoaderRevision
414882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
415882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (MicrocodeEntryPoint->LoaderRevision != 0x1) {
416882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));
417882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
418882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (AbortReason != NULL) {
419882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");
420882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
421882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return EFI_INCOMPATIBLE_VERSION;
422882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
423882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
424882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  // Check Size
425882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
426882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (MicrocodeEntryPoint->DataSize == 0) {
427882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    TotalSize = 2048;
428882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  } else {
429882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    TotalSize = MicrocodeEntryPoint->TotalSize;
430882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
431882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {
432882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));
433882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
434882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (AbortReason != NULL) {
435882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
436882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
437882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return EFI_VOLUME_CORRUPTED;
438882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
439882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (TotalSize != ImageSize) {
440882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on TotalSize\n"));
441882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
442882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (AbortReason != NULL) {
443882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
444882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
445882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return EFI_VOLUME_CORRUPTED;
446882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
447882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
448882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  // Check CheckSum32
449882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
450882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (MicrocodeEntryPoint->DataSize == 0) {
451882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);
452882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  } else {
453882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DataSize = MicrocodeEntryPoint->DataSize;
454882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
455882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {
456882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));
457882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
458882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (AbortReason != NULL) {
459882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
460882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
461882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return EFI_VOLUME_CORRUPTED;
462882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
463882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if ((DataSize & 0x3) != 0) {
464882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize not aligned\n"));
465882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
466882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (AbortReason != NULL) {
467882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
468882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
469882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return EFI_VOLUME_CORRUPTED;
470882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
471882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));
472882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (CheckSum32 != 0) {
473882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));
474882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
475882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (AbortReason != NULL) {
476882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");
477882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
478882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return EFI_VOLUME_CORRUPTED;
479882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
480882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
481882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
482882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  // Check ProcessorSignature/ProcessorFlags
483882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
48431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
48531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);
48631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  if (ProcessorInfo == NULL) {
48731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    CorrectMicrocode = FALSE;
488882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));
489882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (ExtendedTableLength != 0) {
490882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      //
491882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // Extended Table exist, check if the CPU in support list
492882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      //
493882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER));
494882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      //
495882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      // Calculate Extended Checksum
496882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      //
497882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) != 0)) {
498882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
499882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        if (CheckSum32 == 0) {
500882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao          //
501882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao          // Checksum correct
502882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao          //
503882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao          ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
504882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao          if (ExtendedTableCount <= (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {
505882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao            ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
506882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao            for (Index = 0; Index < ExtendedTableCount; Index++) {
507882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao              CheckSum32 = CalculateSum32((UINT32 *)ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));
508882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao              if (CheckSum32 == 0) {
509882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao                //
510882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao                // Verify Header
511882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao                //
51231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);
51331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao                if (ProcessorInfo != NULL) {
514882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao                  //
515882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao                  // Find one
516882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao                  //
517882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao                  CorrectMicrocode = TRUE;
518882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao                  break;
519882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao                }
520882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao              }
521882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao              ExtendedTable++;
522882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao            }
523882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao          }
524882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        }
525882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      }
526882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
527882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (!CorrectMicrocode) {
5282ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      if (TryLoad) {
5292ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));
5302ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      }
531882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
532882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      if (AbortReason != NULL) {
53331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");
534882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      }
535882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      return EFI_UNSUPPORTED;
536882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
537882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
538882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
539882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
540882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  // Check UpdateRevision
541882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
54231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  CurrentRevision = ProcessorInfo->MicrocodeRevision;
54331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||
54431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {
5452ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    if (TryLoad) {
5462ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));
5472ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    }
548882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
549882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (AbortReason != NULL) {
550882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");
551882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
552882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return EFI_INCOMPATIBLE_VERSION;
553882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
554882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
555882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
556882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  // try load MCU
557882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
558882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (TryLoad) {
55931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));
560882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {
561882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));
562882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;
563882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      if (AbortReason != NULL) {
564882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao        *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");
565882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      }
566882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      return EFI_SECURITY_VIOLATION;
567882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
568882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
569882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
570882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return EFI_SUCCESS;
571882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
572882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
573882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
5742ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  Get next Microcode entrypoint.
575882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
5762ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
5772ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]  MicrocodeEntryPoint        Current Microcode entrypoint
5782ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
5792ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @return next Microcode entrypoint.
5802ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao**/
5812ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen YaoCPU_MICROCODE_HEADER *
5822ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen YaoGetNextMicrocode (
5832ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
5842ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint
5852ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  )
5862ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao{
5872ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UINTN                                   Index;
5882ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
5892ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
5902ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {
5912ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {
5922ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        // it is last one
5932ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        return NULL;
594882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      } else {
5952ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        // return next one
5962ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;
597882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao      }
598882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
5992ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  }
600882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
6012ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  ASSERT(FALSE);
602882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return NULL;
603882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
604882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
605882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
606882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Get current Microcode used region size.
607882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
6082ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
6092ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
610882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @return current Microcode used region size.
611882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
612882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoUINTN
613882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoGetCurrentMicrocodeUsedRegionSize (
6142ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate
615882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
616882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
6172ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  if (MicrocodeFmpPrivate->DescriptorCount == 0) {
618882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return 0;
619882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
620882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
6212ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint
6222ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao         + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize
6232ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao         - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;
624882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
625882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
626882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
627882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Update Microcode.
628882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
629882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @param[in]   Address            The flash address of Microcode.
630882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @param[in]   Image              The Microcode image buffer.
631882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @param[in]   ImageSize          The size of Microcode image buffer in bytes.
632882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @param[out]  LastAttemptStatus  The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
633882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
634882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @retval EFI_SUCCESS           The Microcode image is updated.
635882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  @retval EFI_WRITE_PROTECTED   The flash device is read only.
636882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
637882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoEFI_STATUS
638882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoUpdateMicrocode (
639882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  IN UINT64   Address,
640882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  IN VOID     *Image,
641882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  IN UINTN    ImageSize,
642882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  OUT UINT32  *LastAttemptStatus
643882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
644882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
645882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  EFI_STATUS  Status;
646882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
647882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  DEBUG((DEBUG_INFO, "PlatformUpdate:"));
648882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  DEBUG((DEBUG_INFO, "  Address - 0x%lx,", Address));
649882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  DEBUG((DEBUG_INFO, "  Legnth - 0x%x\n", ImageSize));
650882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
651882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  Status = MicrocodeFlashWrite (
652882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao             Address,
653882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao             Image,
654882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao             ImageSize
655882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao             );
656882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (!EFI_ERROR(Status)) {
657882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
658882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  } else {
659882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
660882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
661882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return Status;
662882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
663882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
664882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao/**
6652ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  Update Microcode flash region.
666882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
6672ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
66831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  @param[in]  TargetMicrocodeEntryPoint  Target Microcode entrypoint to be updated
6692ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]  Image                      The Microcode image buffer.
6702ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
6712ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
672882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
6732ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @retval EFI_SUCCESS             The Microcode image is written.
6742ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @retval EFI_WRITE_PROTECTED     The flash device is read only.
675882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao**/
676882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen YaoEFI_STATUS
6772ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen YaoUpdateMicrocodeFlashRegion (
6782ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN  MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
67931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  IN  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint,
6802ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN  VOID                                    *Image,
6812ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN  UINTN                                   ImageSize,
6822ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  OUT UINT32                                  *LastAttemptStatus
683882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  )
684882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao{
6852ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  VOID                                    *MicrocodePatchAddress;
6862ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UINTN                                   MicrocodePatchRegionSize;
68731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  UINTN                                   TargetTotalSize;
688882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  UINTN                                   UsedRegionSize;
6892ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  EFI_STATUS                              Status;
6902ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  VOID                                    *MicrocodePatchScratchBuffer;
6912ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UINT8                                   *ScratchBufferPtr;
6922ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UINTN                                   ScratchBufferSize;
6932ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UINTN                                   RestSize;
6942ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UINTN                                   AvailableSize;
6952ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  VOID                                    *NextMicrocodeEntryPoint;
6962ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  MICROCODE_INFO                          *MicrocodeInfo;
6972ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UINTN                                   MicrocodeCount;
6982ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UINTN                                   Index;
6992ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
7002ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));
701882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
7022ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
7032ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
7042ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
7052ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);
7062ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  if (MicrocodePatchScratchBuffer == NULL) {
7072ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));
7082ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
7092ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    return EFI_OUT_OF_RESOURCES;
710882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
7112ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  ScratchBufferPtr = MicrocodePatchScratchBuffer;
7122ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  ScratchBufferSize = 0;
713882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
7142ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
71531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  // Target data collection
7162ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
71731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  TargetTotalSize = 0;
7182ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  AvailableSize = 0;
7192ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  NextMicrocodeEntryPoint = NULL;
72031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  if (TargetMicrocodeEntryPoint != NULL) {
72131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    if (TargetMicrocodeEntryPoint->DataSize == 0) {
72231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      TargetTotalSize = 2048;
723882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    } else {
72431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;
725882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    }
72631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    DEBUG((DEBUG_INFO, "  TargetTotalSize - 0x%x\n", TargetTotalSize));
72731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);
7282ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    DEBUG((DEBUG_INFO, "  NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));
7292ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    if (NextMicrocodeEntryPoint != NULL) {
73031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
73131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;
7322ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    } else {
73331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;
7342ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    }
7352ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    DEBUG((DEBUG_INFO, "  AvailableSize - 0x%x\n", AvailableSize));
7362ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  }
73731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  ASSERT (AvailableSize >= TargetTotalSize);
7382ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);
7392ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  DEBUG((DEBUG_INFO, "  UsedRegionSize - 0x%x\n", UsedRegionSize));
74031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  ASSERT (UsedRegionSize >= TargetTotalSize);
74131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  if (TargetMicrocodeEntryPoint != NULL) {
74231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
7432ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  }
7442ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
7452ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // Total Size means the Microcode data size.
74631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.
7472ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
7482ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // (1)
7492ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // +------+-----------+-----+------+===================+
7502ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // | MCU1 | Microcode | PAD | MCU2 |      Empty        |
7512ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // +------+-----------+-----+------+===================+
7522ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //        | TotalSize |
7532ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //        |<-AvailableSize->|
7542ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // |<-        UsedRegionSize     ->|
7552ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
7562ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // (2)
7572ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // +------+-----------+===================+
7582ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // | MCU  | Microcode |      Empty        |
7592ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // +------+-----------+===================+
7602ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //        | TotalSize |
7612ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //        |<-      AvailableSize        ->|
7622ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // |<-UsedRegionSize->|
7632ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
7642ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
7652ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
7662ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // Update based on policy
7672ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
7682ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
7692ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
7702ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // 1. If there is enough space to update old one in situ, replace old microcode in situ.
7712ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
7722ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  if (AvailableSize >= ImageSize) {
7732ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));
7742ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    //
7752ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // +------+------------+------+===================+
7762ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // |Other1| Old Image  |Other2|      Empty        |
7772ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // +------+------------+------+===================+
7782ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    //
7792ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // +------+---------+--+------+===================+
7802ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // |Other1|New Image|FF|Other2|      Empty        |
7812ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // +------+---------+--+------+===================+
7822ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    //
7832ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // 1.1. Copy new image
7842ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    CopyMem (ScratchBufferPtr, Image, ImageSize);
7852ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    ScratchBufferSize += ImageSize;
78631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
7872ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // 1.2. Pad 0xFF
7882ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    RestSize = AvailableSize - ImageSize;
7892ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    if (RestSize > 0) {
7902ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      SetMem (ScratchBufferPtr, RestSize, 0xFF);
7912ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      ScratchBufferSize += RestSize;
79231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
7932ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    }
79431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
7952ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    return Status;
796882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
797882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
798882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
7992ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.
8002ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
80131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {
80231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    if (TargetMicrocodeEntryPoint == NULL) {
8032ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      DEBUG((DEBUG_INFO, "Append new microcode\n"));
8042ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      //
8052ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // +------+------------+------+===================+
8062ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // |Other1|   Other    |Other2|      Empty        |
8072ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // +------+------------+------+===================+
8082ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      //
8092ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // +------+------------+------+-----------+=======+
8102ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // |Other1|   Other    |Other2| New Image | Empty |
8112ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // +------+------------+------+-----------+=======+
8122ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      //
8132ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);
8142ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    } else {
8152ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));
8162ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      //
8172ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // +------+------------+------+===================+
8182ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // |Other1| Old Image  |Other2|      Empty        |
8192ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // +------+------------+------+===================+
8202ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      //
8212ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // +------+---------------+------+================+
8222ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // |Other1|   New Image   |Other2|      Empty     |
8232ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // +------+---------------+------+================+
8242ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      //
8252ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // 2.1. Copy new image
82631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      CopyMem (ScratchBufferPtr, Image, ImageSize);
8272ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      ScratchBufferSize += ImageSize;
82831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
8292ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      // 2.2. Copy rest images after the old image.
8302ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      if (NextMicrocodeEntryPoint != 0) {
8312ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);
83231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);
8332ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        ScratchBufferSize += RestSize;
83431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
8352ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      }
83631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
8372ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    }
8382ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    return Status;
8392ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  }
8402ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
8412ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
8422ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // 3. The new image can be put in MCU region, but not all others can be put.
8432ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //    So all the unused MCU is removed.
8442ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
8452ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  if (MicrocodePatchRegionSize >= ImageSize) {
8462ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    //
8472ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // +------+------------+------+===================+
8482ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // |Other1| Old Image  |Other2|      Empty        |
8492ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // +------+------------+------+===================+
8502ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    //
8512ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // +-------------------------------------+--------+
8522ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // |        New Image                    | Other  |
8532ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // +-------------------------------------+--------+
8542ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    //
8552ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));
8562ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
8572ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;
8582ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
8592ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
8602ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // 3.1. Copy new image
86131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    CopyMem (ScratchBufferPtr, Image, ImageSize);
8622ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    ScratchBufferSize += ImageSize;
86331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
8642ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // 3.2. Copy some others to rest buffer
8652ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    for (Index = 0; Index < MicrocodeCount; Index++) {
8662ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      if (!MicrocodeInfo[Index].InUse) {
8672ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        continue;
8682ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      }
86931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {
8702ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        continue;
8712ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      }
8722ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {
8732ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);
8742ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao        ScratchBufferSize += MicrocodeInfo[Index].TotalSize;
87531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao        ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
8762ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      }
8772ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    }
8782ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    // 3.3. Pad 0xFF
8792ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    RestSize = MicrocodePatchRegionSize - ScratchBufferSize;
8802ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    if (RestSize > 0) {
8812ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      SetMem (ScratchBufferPtr, RestSize, 0xFF);
8822ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao      ScratchBufferSize += RestSize;
88331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
8842ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    }
8852ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
8862ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao    return Status;
8872ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  }
8882ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
8892ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
8902ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  // 4. The new image size is bigger than the whole MCU region.
8912ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
8922ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  DEBUG((DEBUG_ERROR, "Microcode too big\n"));
8932ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
8942ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  Status = EFI_OUT_OF_RESOURCES;
8952ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
8962ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  return Status;
8972ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao}
8982ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
8992ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao/**
9002ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  Write Microcode.
9012ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
9022ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  Caution: This function may receive untrusted input.
9032ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
9042ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]   MicrocodeFmpPrivate The Microcode driver private data
9052ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]   Image               The Microcode image buffer.
9062ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[in]   ImageSize           The size of Microcode image buffer in bytes.
9072ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[out]  LastAttemptVersion  The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
9082ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[out]  LastAttemptStatus   The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
9092ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @param[out]  AbortReason         A pointer to a pointer to a null-terminated string providing more
9102ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao                                   details for the aborted operation. The buffer is allocated by this function
9112ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao                                   with AllocatePool(), and it is the caller's responsibility to free it with a
9122ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao                                   call to FreePool().
9132ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
9142ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @retval EFI_SUCCESS               The Microcode image is written.
9152ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.
9162ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.
9172ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.
9182ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  @retval EFI_WRITE_PROTECTED       The flash device is read only.
9192ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao**/
9202ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen YaoEFI_STATUS
9212ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen YaoMicrocodeWrite (
9222ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN  MICROCODE_FMP_PRIVATE_DATA   *MicrocodeFmpPrivate,
9232ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN  VOID                         *Image,
9242ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  IN  UINTN                        ImageSize,
9252ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  OUT UINT32                       *LastAttemptVersion,
9262ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  OUT UINT32                       *LastAttemptStatus,
9272ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  OUT CHAR16                       **AbortReason
9282ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  )
9292ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao{
9302ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  EFI_STATUS                              Status;
9312ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  VOID                                    *AlignedImage;
93231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint;
93331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  UINTN                                   TargetCpuIndex;
93431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  UINTN                                   TargetMicrcodeIndex;
9352ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao
9362ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  //
937882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  // MCU must be 16 bytes aligned
938882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  //
939882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  AlignedImage = AllocateCopyPool(ImageSize, Image);
940882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (AlignedImage == NULL) {
941882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));
942882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
943882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return EFI_OUT_OF_RESOURCES;
944882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
945882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
946882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;
94731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  TargetCpuIndex = (UINTN)-1;
94831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);
949882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  if (EFI_ERROR(Status)) {
950882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));
951882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    FreePool(AlignedImage);
952882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao    return Status;
953882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  }
954882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));
955882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
95631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  DEBUG((DEBUG_INFO, "  TargetCpuIndex - 0x%x\n", TargetCpuIndex));
95731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
95831d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;
95931d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  DEBUG((DEBUG_INFO, "  TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));
96031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  if (TargetMicrcodeIndex != (UINTN)-1) {
96131d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);
96231d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;
96331d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  } else {
96431d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao    TargetMicrocodeEntryPoint = NULL;
96531d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  }
96631d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao  DEBUG((DEBUG_INFO, "  TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));
96731d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao
9682ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao  Status = UpdateMicrocodeFlashRegion(
9692ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao             MicrocodeFmpPrivate,
97031d060d94e65c41ccca2b68f7908c0c3b4ac3df4Jiewen Yao             TargetMicrocodeEntryPoint,
9712ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao             AlignedImage,
9722ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao             ImageSize,
9732ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao             LastAttemptStatus
9742ed658240c1f3ca10aa65dbbf74f4cf297145d8cJiewen Yao             );
975882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
976882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  FreePool(AlignedImage);
977882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
978882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao  return Status;
979882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao}
980882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
981882668595c32e9e0adeaaf0bd0062f88b464fc18Jiewen Yao
982