alder_lake_bios/Lcfc/LfcPkg/ModernPreload/ModernPreloadSmm/ModernPreloadSmm.c

556 lines
16 KiB
C

/** @file
;******************************************************************************
;* Copyright (c) 2019, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "ModernPreloadSmm.h"
#include <Library/LfcSwSmiCpuRegisterLib.h>
#include <Protocol/LenovoVariable.h>
EFI_SMM_CPU_PROTOCOL *mSmmCpu;
EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
/**
Read information from the CPU save state.
@param Register Specifies the CPU register to read form the save state.
@param Width The number of bytes to read from the CPU save state.
@param CpuNum Specifies the zero-based index of the CPU save state.
@param RegisterData Upon return, this holds the CPU register value read from the save state.
@retval EFI_SUCCESS The register was read from Save State
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
@retval EFI_INVALID_PARAMTER This or Buffer is NULL.
**/
EFI_STATUS
ReadCpuRegister (
IN EFI_SMM_SAVE_STATE_REGISTER RegisterNum,
IN UINTN Width,
IN UINTN CpuNum,
OUT VOID *RegisterData
)
{
EFI_STATUS Status;
Status = mSmmCpu->ReadSaveState (
mSmmCpu,
Width,
RegisterNum,
CpuNum,
RegisterData
);
return Status;
}
/**
Write value to a CPU Save State register on the target processor.
This function abstracts the differences that whether the CPU Save State register is in the
IA32 CPU Save State Map or X64 CPU Save State Map.
This function supports writing a CPU Save State register in SMBase relocation handler.
@param RegisterNum Specifies the CPU register to write to the save state.
@param Width The number of bytes to read from the CPU save state.
@param CpuNum Specifies the zero-based index of the CPU save state.
@param RegisterData Upon entry, this holds the new CPU register value.
@retval EFI_SUCCESS The register was written to Save State.
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
@retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct.
**/
EFI_STATUS
WriteCpuRegister (
IN EFI_SMM_SAVE_STATE_REGISTER RegisterNum,
IN UINTN Width,
IN UINTN CpuNum,
IN VOID *RegisterData
)
{
EFI_STATUS Status;
Status = mSmmCpu->WriteSaveState (
mSmmCpu,
Width,
RegisterNum,
CpuNum,
RegisterData
);
return Status;
}
/**
Get TPM Lock State.
@param L05TpmLockRegister Specifies the TPM lock register.
@retval EFI_SUCCESS The register was get from save state.
@retval EFI_UNSUPPORTED The register is not defined for the Save State.
**/
EFI_STATUS
GetTpmLockState (
IN OUT EFI_L05_TPM_LOCK_REGISTER *L05TpmLockRegister
)
{
EFI_STATUS Status;
Status = EFI_SUCCESS;
LENOVO_VARIABLE_PROTOCOL *mLenovoVariable;
UINT32 DataLength;
UINT8 TpmLock;
EFI_GUID LvarTpmLockFlagGuid = LVAR_TPM_LOCK_FLAG_GUID;
mLenovoVariable = NULL;
Status = gSmst->SmmLocateProtocol (&gLenovoVariableProtocolGuid, NULL, &mLenovoVariable);
if (EFI_ERROR (Status)) {
return Status;
}
TpmLock = 0;
DataLength = sizeof (TpmLock);
//
// Get TPM Lock data
//
Status = mLenovoVariable->GetVariable (
mLenovoVariable,
&LvarTpmLockFlagGuid,
&DataLength,
&TpmLock);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get TPM Lock State
//
L05TpmLockRegister->Byte = TpmLock;
return Status;
}
/**
Set TPM Lock State.
@param L05TpmLockRegister Specifies the TPM lock register.
@retval EFI_SUCCESS The register was written from save state.
@retval EFI_UNSUPPORTED The register is not defined for the Save State.
**/
EFI_STATUS
SetTpmLockState (
IN EFI_L05_TPM_LOCK_REGISTER *L05TpmLockRegister
)
{
EFI_STATUS Status;
LENOVO_VARIABLE_PROTOCOL *mLenovoVariable;
UINT32 DataLength;
UINT8 TpmLock;
EFI_GUID LvarTpmLockFlagGuid = LVAR_TPM_LOCK_FLAG_GUID;
Status = EFI_SUCCESS;
mLenovoVariable = NULL;
Status = gSmst->SmmLocateProtocol (&gLenovoVariableProtocolGuid, NULL, &mLenovoVariable);
if (EFI_ERROR (Status)) {
return Status;
}
TpmLock = 0;
DataLength = sizeof (TpmLock);
//
// Get TPM Lock data
//
Status = mLenovoVariable->GetVariable (
mLenovoVariable,
&LvarTpmLockFlagGuid,
&DataLength,
&TpmLock
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
return Status;
}
if (L05TpmLockRegister->Byte == TpmLock) {
return EFI_SUCCESS;
}
//
// Set TPM Lock State
//
TpmLock = L05TpmLockRegister->Byte;
DataLength = sizeof (TpmLock);
Status = mLenovoVariable->SetVariable(
mLenovoVariable,
&LvarTpmLockFlagGuid,
DataLength,
&TpmLock
);
return Status;
}
/**
Set TPM Lock Done.
@param None.
@retval L05_MODERN_PRELOAD_ERROR_SUCCESS Function successful.
@retval L05_MODERN_PRELOAD_ERROR_SET_FAILED Function failed.
**/
UINT32
SetTpmLockDone (
VOID
)
{
EFI_STATUS Status;
EFI_L05_TPM_LOCK_REGISTER L05TpmLockRegister;
ZeroMem (&L05TpmLockRegister, sizeof (EFI_L05_TPM_LOCK_REGISTER));
Status = GetTpmLockState (&L05TpmLockRegister);
if (EFI_ERROR (Status)) {
return L05_MODERN_PRELOAD_ERROR_SET_FAILED;
}
L05TpmLockRegister.Bits.State = L05_TPMLOCKD_DONE;
Status = SetTpmLockState (&L05TpmLockRegister);
if (EFI_ERROR (Status)) {
return L05_MODERN_PRELOAD_ERROR_SET_FAILED;
}
return L05_MODERN_PRELOAD_ERROR_SUCCESS;
}
/**
Check TPM Lock Done.
@param None.
@retval L05_MODERN_PRELOAD_ERROR_SUCCESS TPMLOCK Done.
@retval L05_MODERN_PRELOAD_ERROR_CHECK_ACCESS Get TPMLOCK status failed.
@retval L05_MODERN_PRELOAD_ERROR_TPMLOCK_NOT_DONE TPMLOCK not Doney.
**/
UINT32
CheckTpmLockDone (
VOID
)
{
EFI_STATUS Status;
EFI_L05_TPM_LOCK_REGISTER L05TpmLockRegister;
ZeroMem (&L05TpmLockRegister, sizeof (EFI_L05_TPM_LOCK_REGISTER));
Status = GetTpmLockState (&L05TpmLockRegister);
if (EFI_ERROR (Status)) {
return L05_MODERN_PRELOAD_ERROR_CHECK_ACCESS;
}
if (L05TpmLockRegister.Bits.State == L05_TPMLOCKD_DONE) {
return L05_MODERN_PRELOAD_ERROR_SUCCESS;
}
return L05_MODERN_PRELOAD_ERROR_TPMLOCK_NOT_DONE;
}
/**
A callback function for SMM Modern Preload.
@param CpuNum CPU number
@retval EFI_SUCCESS The operation completed successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
EFIAPI
L05SmmModernPreloadCallback (
IN UINTN CpuNum
)
{
UINT32 ErrorStatus;
UINT32 Eax;
UINT32 Ebx;
EFI_STATUS Status;
ErrorStatus = L05_MODERN_PRELOAD_ERROR_CHECK_ACCESS;
CpuNum = 0;
Eax = 0;
Ebx = 0;
//
// Check function signature is valid or not
//
Status = IdentifyCpuIndexByEax (L05_MODERN_PRELOAD_SUPPORT_FUNCTION, 0xffffffff, &CpuNum);
if (EFI_ERROR (Status)) {
//[-start-211014-BAIN000051-modify]//
//#ifdef LCFC_SUPPORT
//#if defined(C970_BSH_SUPPORT)
//[-start-21119-TAMT000032-modify]//
//[-start-211203-QINGLIN0125-modify]//
//[-start-211206-OWENWU0029-modify]//
//[-start-211214-Ching000017-modify]//
#if defined(C970_BSH_SUPPORT) || defined(C770_BSH_SUPPORT) || defined(S77014_BSH_SUPPORT) || defined(S370_BSH_SUPPORT) || defined(S570_BSH_SUPPORT) || defined(S77013_BSH_SUPPORT) || defined(S77014IAH_BSH_SUPPORT)
return EFI_NOT_FOUND;
#else
return EFI_SUCCESS;
#endif
//[-end-211214-Ching000017-modify]//
//[-end-211206-OWENWU0029-modify]//
//[-end-211203-QINGLIN0125-modify]//
//[-end-21119-TAMT000032-modify]//
//[-end-211014-BAIN000051-modify]//
}
ReadCpuRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
if (Eax != L05_MODERN_PRELOAD_SUPPORT_FUNCTION) {
return EFI_UNSUPPORTED;
}
//
// Get SMI interface
//
ReadCpuRegister (EFI_SMM_SAVE_STATE_REGISTER_RBX, sizeof (UINT32), CpuNum, &Ebx);
switch (Ebx) {
case L05_MODERN_PRELOAD_SET_TPMLOCKD:
ErrorStatus = SetTpmLockDone ();
if (ErrorStatus == L05_MODERN_PRELOAD_ERROR_SUCCESS) {
ErrorStatus = CheckTpmLockDone ();
if (ErrorStatus != L05_MODERN_PRELOAD_ERROR_SUCCESS) {
ErrorStatus = L05_MODERN_PRELOAD_ERROR_SET_FAILED;
}
}
break;
case L05_MODERN_PRELOAD_CHECK_TPMLOCKD:
ErrorStatus = CheckTpmLockDone ();
break;
default:
ErrorStatus = L05_MODERN_PRELOAD_ERROR_CHECK_ACCESS;
break;
}
WriteCpuRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &ErrorStatus);
return EFI_SUCCESS;
}
/**
Init TPM Lock.
BIOS should initially set this value to "Not Done" state. Only MFG utilities can change the value.
The initial value about Bit1 and Bit0 should be 11b.
@param None.
@retval EFI_SUCCESS The operation completed successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
InitTpmLock (
VOID
)
{
EFI_STATUS Status;
EFI_L05_TPM_LOCK_REGISTER L05TpmLockRegister;
ZeroMem (&L05TpmLockRegister, sizeof (EFI_L05_TPM_LOCK_REGISTER));
Status = GetTpmLockState (&L05TpmLockRegister);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
return Status;
}
//
// [BIOS and Tool Requirements for Modern Preload Support, Version 1.00 Draft]
// 1.2 Structures definition
// BIOS should initially set this value to "Not Done" state. Only MFG utilities can change the value.
// The initial value about Bit1 and Bit0 should be 11b.
//
if ((L05TpmLockRegister.Bits.State != L05_TPMLOCKD_DONE) &&
(L05TpmLockRegister.Bits.State != L05_TPMLOCKD_NOT_DONE)) {
L05TpmLockRegister.Byte = 0xFF;
Status = SetTpmLockState (&L05TpmLockRegister);
}
return Status;
}
/**
Check TPM Lock.
BIOS are required to send different TPM commands before and after TPMLOCK Done.
If TPMLOCK is Not Done, then TPM PlatformAuth will be NULL.
If TPMLOCK is Done, then TPM PlatformAuth will be RANDOM.
@param None.
@retval EFI_SUCCESS The operation completed successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
CheckTpmLock (
VOID
)
{
EFI_STATUS Status;
EFI_L05_TPM_LOCK_REGISTER L05TpmLockRegister;
ZeroMem (&L05TpmLockRegister, sizeof (EFI_L05_TPM_LOCK_REGISTER));
Status = GetTpmLockState (&L05TpmLockRegister);
if (EFI_ERROR (Status)) {
return Status;
}
//
// [BIOS and Tool Requirements for Modern Preload Support, Version 1.00 Draft]
// 1.1 BIOS FLOW Chart
// Check TPMLOCK -> Not Done -> Continue POST
// |
// ---> Done -> Randomize PlatformAuth -> Continue POST
//
// 1.2 Structures definition
// BIOS Requirement Before and After TPMLOCK Done
// BIOS are required to send different TPM commands before and after TPMLOCK Done,
// make TPM behavior as below:
// | TPMLOCK = Not Done | TPMLOCK = Done
// ---------------------------------------------------------
// TPM PlatformAuth | NULL | RANDOM
//
if (L05TpmLockRegister.Bits.State != L05_TPMLOCKD_DONE) {
//[-start-210618-YUNLEI0103-modify]//
#ifdef LCFC_SUPPORT
PcdSet32S (PcdDxeTpmPolicy, (PcdGet32 (PcdDxeTpmPolicy) | (SKIP_TPM_REVOKE_TRUST)));
#else
PcdSet32 (PcdDxeTpmPolicy, (PcdGet32 (PcdDxeTpmPolicy) | (SKIP_TPM_REVOKE_TRUST)));
#endif
//[-end-210618-YUNLEI0103-modify]//
}
return Status;
}
/**
Modern Preload SMM entry.
Lenovo Notebook to support Modern Preload (aka Cloud Preload) Platform Key generation in MFG.
The main reason is Modern Preload Platform Key generation need TPM PlatformAuth is NULL.
@param ImageHandle The firmware allocated handle for the UEFI image.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The operation completed successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
L05ModernPreloadSmmEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_L05_SMM_SW_SMI_INTERFACE_PROTOCOL *L05SwSmiPtr;
mSmmCpu = NULL;
mSmmVariable = NULL;
L05SwSmiPtr = NULL;
//
// Locate SMM CPU protocol for CPU save state manipulation
//
Status = gSmst->SmmLocateProtocol (
&gEfiSmmCpuProtocolGuid,
NULL,
&mSmmCpu
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Locate SMM Variable protocol
//
Status = gSmst->SmmLocateProtocol (
&gEfiSmmVariableProtocolGuid,
NULL,
&mSmmVariable
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// [BIOS and Tool Requirements for Modern Preload Support, Version 1.00 Draft]
// 1.2 Structures definition
// BIOS should initially set this value to "Not Done" state. Only MFG utilities can change the value.
// The initial value about Bit1 and Bit0 should be 11b.
//
InitTpmLock ();
//
// [BIOS and Tool Requirements for Modern Preload Support, Version 1.00 Draft]
// 1.1 BIOS FLOW Chart
// Check TPMLOCK -> Not Done -> Continue POST
// |
// ---> Done -> Randomize PlatformAuth -> Continue POST
//
// 1.2 Structures definition
// BIOS Requirement Before and After TPMLOCK Done
// BIOS are required to send different TPM commands before and after TPMLOCK Done,
// make TPM behavior as below:
// | TPMLOCK = Not Done | TPMLOCK = Done
// ---------------------------------------------------------
// TPM PlatformAuth | NULL | RANDOM
//
CheckTpmLock ();
//
// Register Software SMI function with L05SwSmi Driver
//
Status = gSmst->SmmLocateProtocol (
&gEfiL05SmmSwSmiInterfaceProtocolGuid,
NULL,
&L05SwSmiPtr
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = L05SwSmiPtr->RegisterCallbackFunction (
L05SwSmiPtr,
L05_SECURITY_SW_SMI,
FeatureCallbackType,
L05SmmModernPreloadCallback
);
if (EFI_ERROR (Status)) {
return Status;
}
return Status;
}