/** @file
  Software Guard Extensions Library for PEI and DXE modules

@copyright
 Copyright (c) 2015 - 2018 Intel Corporation. All rights reserved
 This software and associated documentation (if any) is furnished
 under a license and may only be used or copied in accordance
 with the terms of the license. Except as permitted by the
 license, no part of this software or documentation may be
 reproduced, stored in a retrieval system, or transmitted in any
 form or by any means without the express written consent of
 Intel Corporation.
 This file contains an 'Intel Peripheral Driver' and is uniquely
 identified as "Intel Reference Module" and is licensed for Intel
 CPUs and chipsets under the terms of your license agreement with
 Intel or your vendor. This file may be modified by the user, subject
 to additional terms of the license agreement.

@par Specification Reference:
**/

#include <Uefi.h>
#include <PiPei.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
#ifdef SGX_SUPPORT
#include <Private/Library/SoftwareGuardLib.h>
#endif
#include <Library/CpuPlatformLib.h>
#include <Library/CpuMailboxLib.h>
#include <Library/CpuPolicyLib.h>
#include "CpuDataStruct.h"
#include <CpuRegs.h>
#include <Private/CpuInitDataHob.h>
#include <Private/Library/CpuCommonLib.h>
#include <Library/HobLib.h>
#include <Register/Cpuid.h>
#include <Register/Msr.h>
#ifdef SGX_SUPPORT
GLOBAL_REMOVE_IF_UNREFERENCED CPU_INIT_DATA_HOB      *mCpuInitDataHob;
GLOBAL_REMOVE_IF_UNREFERENCED SI_CPU_POLICY_PPI      *gSiCpuPolicyPpi = NULL;
GLOBAL_REMOVE_IF_UNREFERENCED SOFTWARE_GUARD_CONFIG  *mSoftwareGuardConfiger  = NULL;
GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS   mPrmrrBase = 0;
GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS   mPrmrrMask = 0;
///
/// Function declarations
///

  
/**
  Check on the processor if SGX is supported.

  @dot
    digraph G {
      subgraph cluster_c0 {
        node [shape = box];
          b1[label="Read CPUID(EAX=7,ECX=0):EBX[2] \nto check SGX feature" fontsize=12 style=filled color=lightblue];
          b2[label="Return TRUE" fontsize=12 style=filled color=lightblue];
          b3[label="Return FALSE" fontsize=12 style=filled color=lightblue];

        node [shape = ellipse];
          e1[label="Start" fontsize=12 style=filled color=lightblue];
          e2[label="End" fontsize=12 style=filled color=lightblue];

        node [shape = diamond,style=filled,color=lightblue];
          d1[label="Are SGX feature supported and \nPRMRR configuration enabled" fontsize=12];

        label = "IsSgxSupported Flow"; fontsize=15; fontcolor=black; color=lightblue;
        e1 -> b1
        b1 -> d1
        d1 -> b2 [label="Yes" fontsize=9]
        d1 -> b3 [label="No" fontsize=9]
        b2 -> e2
        b3 -> e2

      }
    }
  @enddot

  @retval TRUE  if SGX supported
  @retval FALSE if SGX is not supported
**/

/**
  Check if SGX patch can be loaded. Patch can be loaded if all
  of these conditions are met
  - 1: EnableSgx policy was set to enable
  - 2: SGX feature is supported by CPU
  - 3: PRM was successfully allocated and PRMRRs were set

  @dot
    digraph G {
      subgraph cluster_c0 {
        node [shape = box];
          b1[label="Return TRUE" fontsize=12 style=filled color=lightblue];
          b2[label="Return FALSE" fontsize=12 style=filled color=lightblue];

        node [shape = ellipse];
          e1[label="Start" fontsize=12 style=filled color=lightblue];
          e2[label="End" fontsize=12 style=filled color=lightblue];

        node [shape = diamond,style=filled,color=lightblue];
          d1[label="Are the\n IsBiosLoadSgxPatch (),\n IsSgxSupported (),\n and IsPrmrrAlreadySet ()\n all eqaul to TRUE" fontsize=12];

        label = "IsSgxPreconditionsMet Flow"; fontsize=15; fontcolor=black; color=lightblue;
        e1 -> d1
        d1 -> b1 [label="Yes" fontsize=9]
        d1 -> b2 [label="No" fontsize=9]
        b1 -> e2
        b2 -> e2

      }
    }
  @enddot

  @retval TRUE  if all conditions are met
  @retval FALSE if at least one of the condtions is not met
**/
BOOLEAN
IsSgxPreconditionsMet (
  VOID
  )
{
  return (IsSgxSupported() && IsPrmrrAlreadySet());
}

/**
  Return TRUE if SGX in Feature Control MSR was set
  IA32_FEATURE_CONTROL MSR(3Ah) [18] == 1

  @retval TRUE if SGX in Feature Control MSR was set.
  @retval FALSE if SGX in Feature Control MSR was not set.
**/
BOOLEAN
IsSgxFeatureCtrlSet (
  VOID
  )
{
  MSR_IA32_FEATURE_CONTROL_REGISTER Msr;

  Msr.Uint64 = AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL);

  return (BOOLEAN) (Msr.Bits.SgxEnable == 1);
}

/**
  Update Software Guard Epochs

  @dot
    digraph G {
      subgraph cluster_c0 {
        node [shape = box];
          b1[label="[Debug] EpochUpdate: EPOCH0 and EPOCH1" fontsize=12 style=filled color=lightblue];
          b2[label="Update the value of SgxEpoch0 to MSR_IA32_SGXOWNEREPOCH0" fontsize=12 style=filled color=lightblue];
          b3[label="Update the value of SgxEpoch1 to MSR_IA32_SGXOWNEREPOCH1" fontsize=12 style=filled color=lightblue];

        node [shape = ellipse];
          e1[label="Start" fontsize=12 style=filled color=lightblue];
          e2[label="End" fontsize=12 style=filled color=lightblue];

        node [shape = diamond,style=filled,color=lightblue];
          d1[label="IsSgxPresent" fontsize=12];

        label = "EpochUpdate Flow"; fontsize=15; fontcolor=black; color=lightblue;
        e1 -> d1
        d1 -> e2 [label="Yes" fontsize=9]
        d1 -> b1 [label="No" fontsize=9]
        b1 -> b2
        b2 -> b3
        b3 -> e2

      }
    }
  @enddot

  @param[in] SoftwareGuardConfig The Security Policy instance

 **/
VOID
EpochUpdate (
  IN  SI_CPU_POLICY_PPI    *SiCpuPolicyPpi
  )
{
  EFI_STATUS                    Status;
  UINT64                        mSgxEpoch0;
  UINT64                        mSgxEpoch1;  
  
  ///
  /// Check if SGX wasn't already enabled by reading CPUID.(EAX=12,ECX=0):EAX[0]
  /// If SGX wasn't enabled yet EAX==0, otherwise EAX==1
  ///
  mSgxEpoch0 = 0;
  mSgxEpoch1 = 0;

 
  if (!IsSgxPresent() && ((AsmReadMsr64 (MSR_PRMRR_VALID_CONFIG) ==0xe0))) {
    ///
    ///Get the setup values for SGX EPOCH 
    ///

    Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *)SiCpuPolicyPpi, &gSoftwareGuardConfigGuid , (VOID *)&mSoftwareGuardConfiger);
    DEBUG((DEBUG_ERROR,"Getconfig block for Softwareguard = %r\n",Status));
    ASSERT_EFI_ERROR (Status);

    if (!EFI_ERROR (Status)) {
      mSgxEpoch0 = mSoftwareGuardConfiger->SgxEpoch0;
      mSgxEpoch1 = mSoftwareGuardConfiger->SgxEpoch1;
    } else {
      DEBUG ((EFI_D_ERROR, "EpochUpdate:Couldn't read configuration values from configblock, using default values\n"));
    }
    
    DEBUG ((DEBUG_INFO, "EpochUpdate: updating EPOCH keys 0x%016llX and 0x%016llX\n",mSgxEpoch0,mSgxEpoch1));
    AsmWriteMsr64(MSR_SKYLAKE_SGXOWNER0, mSgxEpoch0);
    AsmWriteMsr64(MSR_SKYLAKE_SGXOWNER1, mSgxEpoch1);
  }
}

/**
  Return TRUE if BIOS need to load SGX patch.
  Can be set by setup option.

  @param[in] PPI CPU policy configuration

  @retval TRUE  BIOS load SGX patch.
  @retval FALSE BIOS doesn't load SGX patch.
**/
BOOLEAN
IsSgxPolicyEnabled (
  VOID
  )
{
  EFI_STATUS            Status;
  CPU_SECURITY_PREMEM_CONFIG *CpuSecurityPreMemConfig;
  SOFTWARE_GUARD_CONFIG *SoftwareGuardConfig;
  
  Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *)gSiCpuPolicyPpi, &gCpuSecurityPreMemConfigGuid , (VOID *)&CpuSecurityPreMemConfig);
  ASSERT_EFI_ERROR (Status);

  
  Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *)gSiCpuPolicyPpi, &gSoftwareGuardConfigGuid , (VOID *)&SoftwareGuardConfig);
  ASSERT_EFI_ERROR (Status);
  if (SoftwareGuardConfig->SvPolicyEnable == TRUE) {
	  if (((SoftwareGuardConfig->SkipSgxPatch == FALSE) && (SoftwareGuardConfig->SkipPrmrr == FALSE)) ||
		  ((SoftwareGuardConfig->SkipSgxPatch == FALSE) && (SoftwareGuardConfig->SkipPrmrr == TRUE))) {
		  return TRUE;
	  }
	  return FALSE;
  }
  else {
	 
	  return (CpuSecurityPreMemConfig->EnableSgx == 1) ? TRUE : FALSE;
	  
  }

}

/**
  Activation of SGX feature after patch load via BIOS_UPGD_TRIG (MSR 0x7a)
**/
VOID
ActivateSgxFeature (
  VOID
  )
{
  BOOLEAN  IsBspInt;

  IsBspInt = IsBsp ();
  ///
  /// If BIT0 in MSR_IA32_BIOS_ENBL_XU is set then SGX is pending activation
  ///
  if (AsmReadMsr64 (MSR_IA32_BIOS_ENBL_XU )& BIT0) {
    if (IsBspInt) {
      DEBUG ((DEBUG_INFO, "ActivateSgxFeature: Enabling SGX feature\n"));
    }
    ///
    /// If SGX is pending activation, attempts to activate SGX, otherwise ignored.
    /// As part of the activation, the processor may perform certain checks.
    ///
    AsmWriteMsr64(MSR_IA32_BIOS_ENBL_XU, 1);
    ///
    /// In case of a successful activation, clear the SGX_Pending_Activation bit,
    /// otherwise the bit doesn't change
    ///
    if (AsmReadMsr64 (MSR_IA32_BIOS_ENBL_XU )& BIT0) {
      if (IsBspInt) {
        DEBUG ((DEBUG_ERROR, "ActivateSgxFeature: SGX activation failed\n"));
      }
    } else {
      if (IsBspInt) {
        DEBUG ((DEBUG_INFO, "ActivateSgxFeature: SGX activation was successful\n"));
      }
    }
  }
  ///
  /// If BIT0 in MSR_IA32_BIOS_ENBL_XU is 0, SGX is not pending activation
  ///
  else {
    if (IsBspInt) {
      DEBUG ((DEBUG_INFO, "ActivateSgxFeature: SGX feature is deactivated on this thread\n"));
    }
  }

  if (IsBspInt && IsSgxPresent ()) {
    DEBUG ((DEBUG_INFO, "ActivateSgxFeature:: SGX feature was successfully loaded and activated\n"));
  }
}

/**
  Check if SGX present.
  Presence of feature is detectable by reading CPUID.(EAX=12,
  ECX=0):EAX[0].

  @retval TRUE  - SGX is present on the system
  @retval FALSE - SGX is not present on the system
**/
BOOLEAN
IsSgxPresent (
  VOID
  )
{
  EFI_CPUID_REGISTER Cpuid;

  ///
  /// Presence of SGX feature is detectable by reading CPUID.(EAX=12, ECX=0):EAX[0]
  ///
  AsmCpuidEx (CPUID_SGX_ENABLED, 0, &Cpuid.RegEax, 0, 0, 0);
  if (Cpuid.RegEax == 0) {
    return FALSE;
  }
  return TRUE;
}

/**
  Check if PRM configuration for SGX was approved by MCHECK.

  @retval TRUE  - PRM configuration was approved by MCHECK
  @retval FALSE - PRM configuration was not approved by MCHECK
**/
BOOLEAN
IsPrmApproved (
  VOID
  )
{
  ///
  /// Check if PRM configuration was approved by MCHECK
  ///
  if (!(AsmReadMsr64(MSR_PRMRR_PHYS_MASK) & B_MSR_PRMRR_VALID_BIT)){
    if (IsBsp()) {
      DEBUG ((DEBUG_INFO, "---SGX--- get valid bit11 from mPrmrrMask, still clear at 0  :0x%x \n",AsmReadMsr64 (MSR_PRMRR_PHYS_MASK)));
      DEBUG ((DEBUG_ERROR, "PrmApproved: PRM configuration was rejected by MCHECK, SGX is not enabled\n"));
    }
    return FALSE;
  } 
    if (IsBsp()) {
      DEBUG ((DEBUG_INFO, "---SGX--- get valid bit11 from mPrmrrMask, already set to 1  :0x%x\n",AsmReadMsr64 (MSR_PRMRR_PHYS_MASK)));
    }
  return TRUE;
}

/**
  Initialize SGX PRMRR core MSRs, PRMRR base and mask will be 
  read from the UNCORE PRMRR MSRs that were already set in MRC 
**/
VOID
InitializeCorePrmrr (
  VOID
  )
{
  EFI_HOB_GUID_TYPE             *GuidHob;
  EFI_PHYSICAL_ADDRESS          mPrmrrSize;
  BOOLEAN                       IsBspVal;

  IsBspVal = IsBsp();

  if (IsBspVal) {
    DEBUG ((DEBUG_INFO, "---SGX--- Start InitializeCorePrmrr\n"));
  }

  if (IsPrmrrAlreadySet()) {
    return;
  }

  ///
  /// The lock bit on MSR 0x1F5 will be set later by the microcode
  ///  
  if (mPrmrrBase == 0) {
    //
    // Get the memory base for prmmrr from the memory initialization via GUID
    //
    if (IsBspVal) {
      DEBUG ((DEBUG_INFO, "---SGX--- mPrmrrBase is 0\n"));
    }
    GuidHob = GetFirstGuidHob(&gPrmrrAddrDataGuid);
    if (GuidHob == NULL) {
      if (IsBspVal) {
        DEBUG ((DEBUG_INFO, "InitializeCorePrmrr:ERROR: PRMRR BASE global guid gPrmrrAddrDataGuid not found\n"));
        ASSERT_EFI_ERROR (1);
      }
    } 
    else 
    {
      mPrmrrBase = *(EFI_PHYSICAL_ADDRESS *)GET_GUID_HOB_DATA (GuidHob);
      if (IsBspVal) {
        DEBUG ((DEBUG_INFO, "---SGX--- mPrmrrBase: 0x%x \n",mPrmrrBase));
      }
    }

    //
    // Get the size reserved from memory initialization via GUID
    //
    GuidHob = GetFirstGuidHob(&gPrmrrSizeHobGuid);
    if (GuidHob == NULL) {
      if (IsBspVal) {
        DEBUG ((DEBUG_INFO, "InitializeCorePrmrr:ERROR: PRMRR SIZE global guid gPrmrrSizeHobGuid not found\n"));
        ASSERT_EFI_ERROR (1);
      }
    } else {
      mPrmrrSize = *(EFI_PHYSICAL_ADDRESS *)GET_GUID_HOB_DATA (GuidHob);
      mPrmrrMask = V_MSR_PRMRR_MASK & (~((UINT64) (mPrmrrSize - 1)));
      
      if (IsBspVal) {
        DEBUG ((DEBUG_INFO, "---SGX--- mPrmrrSize: 0x%x \n",mPrmrrSize));
        DEBUG ((DEBUG_INFO, "---SGX--- mPrmrrMask: 0x%x \n",mPrmrrMask));
      }
    }
  }

  if (IsBspVal) {
    DEBUG ((DEBUG_INFO, "InitializeCorePrmrr:PRMRR BASE - 0x%016llX PRMRR MASK - 0x%016llX\n" ,mPrmrrBase ,mPrmrrMask));
  }

  ///
  /// Set the PRMRR base and mask MSRs and set PRMRR mask lock bit if we got memory allocated.
  ///
  if(mPrmrrBase) {
    if (!(AsmReadMsr64 (MSR_PRMRR_PHYS_MASK) & B_MSR_PRMRR_PHYS_MASK_LOCK)) 
    {
      if (IsBspVal) {
        DEBUG ((DEBUG_INFO, "---SGX--- get lock bit10 from mPrmrrMask before write,should be 0 :0x%x \n",AsmReadMsr64 (MSR_PRMRR_PHYS_MASK)));
      }
      AsmWriteMsr64(MSR_PRMRR_PHYS_BASE, mPrmrrBase | CACHE_WRITEBACK);
      AsmWriteMsr64(MSR_PRMRR_PHYS_MASK, mPrmrrMask | B_MSR_PRMRR_PHYS_MASK_LOCK);

      if (IsBspVal) {
        DEBUG ((DEBUG_INFO, "---SGX--- get lock bit10 from mPrmrrMask after write,should be 1 :0x%x \n",AsmReadMsr64 (MSR_PRMRR_PHYS_MASK)));
        DEBUG ((DEBUG_INFO, "InitializePrm: successfully ended \n"));
      }
    }
    if (IsBspVal) {
      DEBUG ((DEBUG_INFO, "---SGX--- get lock bit10 from mPrmrrMask should now set to 1 :0x%x \n",AsmReadMsr64 (MSR_PRMRR_PHYS_MASK)));
    }
  }
}

/**
  Enable/Disable SGX in the processor.
  To enable the SGX, System BIOS must set bit 18 in 
  IA32_FEATURE_CONTROL MSR. This function will assert if 
  IA32_FEATURE_CONTROL MSR is locked and bit 18 wasn't set
**/
VOID
EnableSgxFeature (
  VOID
  )
{
  MSR_IA32_FEATURE_CONTROL_REGISTER Msr;

/**
  Check if all of these conditions are met
  - EnableSgx policy was set to enable 
  - SGX feature is supported by CPU
  - PRM was successfully allocated and PRMRRs were set
**/ 

  if (IsSgxPreconditionsMet ()) {
    Msr.Uint64 = AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL);
    Msr.Bits.SgxEnable = 1;

    ///
    /// Check the Feature Lock Bit.
    /// If it is already set, which indicates we are executing POST
    /// due to a warm RESET (i.e., PWRGOOD was not de-asserted).
    ///
    if (Msr.Bits.Lock == 0) {
      AsmWriteMsr64 (MSR_IA32_FEATURE_CONTROL, Msr.Uint64);
    }
  }
}


/**
  Enable/Disable SGX Debug Mode via SGX_DEBUG_MODE (MSR 0x503)

  @param[in] SgxDebugMode : SgxDebugMode SGX Policy instance
**/
VOID
SgxDebugMode (
  IN  UINT8    SgxDebugMode
  )
{
  if ((SgxDebugMode == 1)) {
    if ((AsmReadMsr64 (MSR_IA32_DEBUG_INTERFACE) & B_DEBUG_INTERFACE_ENABLE) && (AsmReadMsr64 (MSR_IA32_DEBUG_INTERFACE) & B_DEBUG_INTERFACE_LOCK)) {
      ///
      /// Enable SGX Debug Mode. Set the Non Production Key (MSR 0x503.Bit0)
      ///
      DEBUG ((DEBUG_INFO, "Enabling SGX Debug Mode\n"));
      AsmWriteMsr64 (MSR_IA32_SGX_DEBUG_MODE, (AsmReadMsr64(MSR_IA32_SGX_DEBUG_MODE) | B_MSR_IA32_SGX_DEBUG_MODE_NPK_REQUEST));
    }
  } else {
      if ((AsmReadMsr64 (MSR_IA32_DEBUG_INTERFACE) & B_DEBUG_INTERFACE_ENABLE) && (AsmReadMsr64 (MSR_IA32_DEBUG_INTERFACE) & B_DEBUG_INTERFACE_LOCK)) {
        ///
        /// Disable SGX Debug Mode. Clear the Non Production Key (MSR 0x503.Bit0)
        ///
        DEBUG ((DEBUG_INFO, "Disabling SGX Debug Mode\n"));
        AsmWriteMsr64 (MSR_IA32_SGX_DEBUG_MODE, (AsmReadMsr64(MSR_IA32_SGX_DEBUG_MODE) & ~B_MSR_IA32_SGX_DEBUG_MODE_NPK_REQUEST));
      }
  }
}

/**
  Check if SGX should be activated on this thread.
  User can set it via setup options.

  @param[in] SoftwareGuardConfig The Security Policy instance

  @retval TRUE  - SGX needs to be set on this thread
  @retval FALSE - SGX should not be set on this thread
**/
BOOLEAN
IsSgxActivatedOnThread (
  IN  SOFTWARE_GUARD_CONFIG    *SoftwareGuardConfig
  )
{
  UINT32                ThreadIndex;
  ThreadIndex = 0x1;
  ///
  /// Set the bit that represents this thread
  ///
  ThreadIndex = ThreadIndex << GetCpuApicId ();

  ///
  /// If SGX is disabled on this thread
  ///
  if ((SoftwareGuardConfig->SelectiveEnableSgx & ThreadIndex) == 0) {
    return FALSE;
  }
  return TRUE;
}

/**
  SGX Launch Control Configuration.
  Reconfiguration of SGX Launch Control via IA32_SGXLEPUBKEYHASHn MSR.
**/

VOID
SgxLaunchControlConfiguration(
  VOID
  )
{
  if(IsBsp()){
    DEBUG((DEBUG_INFO,"SgxLaunchControlConfiguration\n"));
  }

  //
  //If LCP mode is true configure the SgxLEKeyHash MSR's from policy
  //
  if (mSoftwareGuardConfiger->SgxLcp == SGX_LCP_LOCKED) {
    AsmWriteMsr64(MSR_IA32_SGXLEPUBKEYHASH0, mSoftwareGuardConfiger->SgxLePubKeyHash0);
    AsmWriteMsr64(MSR_IA32_SGXLEPUBKEYHASH1, mSoftwareGuardConfiger->SgxLePubKeyHash1);
    AsmWriteMsr64(MSR_IA32_SGXLEPUBKEYHASH2, mSoftwareGuardConfiger->SgxLePubKeyHash2);
    AsmWriteMsr64(MSR_IA32_SGXLEPUBKEYHASH3, mSoftwareGuardConfiger->SgxLePubKeyHash3);
  }
}

/**
  Enable SGX Launch Control.
  Sets BIT17 of IA32_FEATURE_CONTROL MSR to enable unlock runtime reconfiguration of
  SGX Launch Control via IA32_SGXLEPUBKEYHASHn MSR.
**/
VOID
EnableSgxLaunchControlFeature (
  VOID
  )
{
  MSR_IA32_FEATURE_CONTROL_REGISTER Msr;
  EFI_CPUID_REGISTER                Cpuid = { 0, 0, 0, 0 };

  if (IsBsp ()) { 
    DEBUG ((DEBUG_INFO, "EnableSgxLaunchControlFeature\n")); 
  }

  ///
  /// Verify processor supports SGX Launch Control Configuration
  ///
  AsmCpuidEx (
    CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS,
    0,
    &Cpuid.RegEax,
    &Cpuid.RegEbx,
    &Cpuid.RegEcx,
    &Cpuid.RegEdx
    );

  if (Cpuid.RegEcx & BIT30) {
    if(mSoftwareGuardConfiger->SgxLcp == SGX_LCP_UNLOCKED){
      Msr.Uint64 = AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL);
      Msr.Bits.SgxLaunchControlEnable = 1;

      ///
      /// Check the Feature Lock Bit.
      /// If it is already set, which indicates we are executing POST
      /// due to a warm RESET (i.e., PWRGOOD was not de-asserted).
      ///
      if (Msr.Bits.Lock == 0) {
        AsmWriteMsr64 (MSR_IA32_FEATURE_CONTROL, Msr.Uint64);
      }
      if(IsBsp()){
        DEBUG((DEBUG_INFO,"SGX Launch Control Configuration is in unlocked mode\n"));
      }
  
    }else {
      if(IsBsp()){
        DEBUG((DEBUG_INFO,"SGX Launch Control Configuration is in locked mode\n"));
      }
    }
  } else {
    if (IsBsp ()) {
      DEBUG ((DEBUG_ERROR, "SGX Launch Control Configuration is not supported.\n"));
    }
  }
}


/**
  Perform SGX initialization by logical processor.

  @param[in] IsBspInt  - Is BSP the executing thread
**/
VOID
SgxInitializationByLogicalProcessorPrePatchLoad (
  IN  SI_CPU_POLICY_PPI    *SiCpuPolicyPpi
  )
{
  CPU_CONFIG                   *CpuConfig = NULL;
  EFI_STATUS                   Status;

  Status = GetConfigBlock ((VOID *) SiCpuPolicyPpi, &gCpuConfigGuid, (VOID *) &CpuConfig);
  ASSERT_EFI_ERROR (Status);

  Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *)SiCpuPolicyPpi, &gSoftwareGuardConfigGuid , (VOID *)&mSoftwareGuardConfiger);
  ASSERT_EFI_ERROR (Status);
 
  if (IsBsp()) {
    DEBUG ((DEBUG_INFO, "SgxInitializationByLogicalProcessorPrePatchLoad\n"));
  }
  
  ///
  /// 1) If supported, Enable SGX feature
  /// 2) Lock feature control MSR
  ///
  if (IsSgxSupported ()) {
    EnableSgxFeature ();
  }

  EnableSgxLaunchControlFeature();
  
  if (IsBsp() && IsSgxPreconditionsMet ()) {
    ///
    /// Set the new EPOCHs value for BSP
    ///
    EpochUpdate(SiCpuPolicyPpi);
  }
}

/**
  Perform SGX Post Patch Load initialization.
**/
VOID
SgxInitializationPostPatchLoad (
  IN  CPU_CONFIG              *CpuConfig,
  IN  SOFTWARE_GUARD_CONFIG   *SoftwareGuardConfig
  )
{
  BOOLEAN                             IsBspInt;
  IsBspInt    = IsBsp ();

  if (IsBspInt) {
    DEBUG ((DEBUG_INFO, "SgxInitializationPostPatchLoad\n"));
  }

  ///
  /// Verify SGX preconditions are met and PRM configuration was approved by MCHECK
  ///
  if (IsSgxPreconditionsMet () && IsPrmApproved ()) {
    if (CpuConfig->SvPolicyEnable == TRUE) {
      SgxLaunchControlConfiguration();
      ///
      /// For this setup option, BIOS needs to enable all SGX preconditions, except loading the XuCode and activating SGX.
      ///
      if (SoftwareGuardConfig->SkipAcpiNvs == TRUE) {
        if (IsBspInt) {
          DEBUG ((DEBUG_INFO, "SgxInitializationPostPatchLoad: SGX feature is not activated by user request, SkipAcpiNvs policy value is TRUE\n"));
        }
        return;
      }

      ///
      /// Check if we need to enable XuCode by MSR 0x7A
      ///
      if (!SoftwareGuardConfig->EnableSgx7a) {
        if (IsBspInt) {
          DEBUG ((DEBUG_INFO, "SgxInitializationPostPatchLoad: SGX feature is not activated by user request, EnableSgx7a policy value is FALSE \n"));
        }
        return;
      }
    }
  
    ///
    /// Activation of SGX feature
    ///
    ActivateSgxFeature ();
  }
}
#endif
