summaryrefslogtreecommitdiff
path: root/Core/EM/OemActivation/SmmOemActivation.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/EM/OemActivation/SmmOemActivation.c')
-rw-r--r--Core/EM/OemActivation/SmmOemActivation.c491
1 files changed, 491 insertions, 0 deletions
diff --git a/Core/EM/OemActivation/SmmOemActivation.c b/Core/EM/OemActivation/SmmOemActivation.c
new file mode 100644
index 0000000..df9502d
--- /dev/null
+++ b/Core/EM/OemActivation/SmmOemActivation.c
@@ -0,0 +1,491 @@
+//****************************************************************************
+//****************************************************************************
+//** **
+//** (C)Copyright 1985-2012, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone (770)-246-8600 **
+//** **
+//****************************************************************************
+//****************************************************************************
+
+//*****************************************************************************
+// $Header: /Alaska/SOURCE/Modules/OemActivation/SmmOemActivation.c 6 6/14/13 9:48a Vyacheslava $
+//
+// $Revision: 6 $
+//
+// $Date: 6/14/13 9:48a $
+//*****************************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Modules/OemActivation/SmmOemActivation.c $
+//
+// 6 6/14/13 9:48a Vyacheslava
+// [TAG] EIP125798
+// [Category] Improvement
+// [Description] Added security check for Runtime injection of Product
+// Key through SMI
+//
+// 5 5/22/12 4:31p Vyacheslava
+// The OA3MSDMvariable variable has improper GUID.
+//
+// 4 4/27/12 2:41p Vyacheslava
+//
+// 3 4/20/12 2:43p Vyacheslava
+// There is additional pointer to MSDM ACPI will be added to XSDT for each
+// time AFU used to inject the product key. This issue is only actual if
+// there is empty product key in the in the firmware.
+//
+// 2 1/31/12 11:46a Vyacheslava
+// Changed SMM SW Context pointer according with changes in the
+// SmmChildDispatcher.
+//
+// 1 1/12/12 9:36a Vyacheslava
+// Separated to the module part.
+//
+//
+//
+//*****************************************************************************
+//<AMI_FHDR_START>
+//
+// Name: SmmOemActivation.c
+//
+// Description: This part of code allows to update ACPI in the OS Runtime through
+// the SW SMI for OEM Activation without rebooting the system.
+//
+//<AMI_FHDR_END>
+//*****************************************************************************
+
+
+#include <AmiDxeLib.h>
+#include <AmiSmm.h>
+#include "OemActivation.h"
+#include <AmiHobs.h>
+
+#if PI_SPECIFICATION_VERSION<0x0001000A
+ #include <Protocol/SmmSwDispatch.h>
+ #include <Protocol/SmmControl.h>
+#else
+ #include <Protocol/SmmSwDispatch2.h>
+ #include <Protocol/SmmControl2.h>
+ #include <Protocol/SmmCpu.h>
+#endif
+
+//---------------------------------------------------------------------------
+
+static EFI_PHYSICAL_ADDRESS gTsegAddress_ = 0;
+static UINT32 gTsegSize_ = 0;
+
+//---------------------------------------------------------------------------
+
+
+//<AMI_PHDR_START>
+//--------------------------------------------------------------------------
+//
+// Procedure: GetTsegVar
+//
+// Description: This function stores TSEG address and size.
+//
+// Input: VOID
+//
+// Output: VOID
+//
+//--------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID GetTsegVar(VOID)
+{
+ EFI_STATUS Status;
+ EFI_GUID CpuInfoHobGuid = AMI_CPUINFO_HOB_GUID;
+ EFI_GUID HobListGuid = HOB_LIST_GUID;
+ CPUINFO_HOB *CpuInfoHob = (CPUINFO_HOB*)GetEfiConfigurationTable(pST,&HobListGuid);
+
+ if (CpuInfoHob == NULL)
+ return;
+
+ Status = FindNextHobByGuid(&CpuInfoHobGuid,&CpuInfoHob);
+ if (EFI_ERROR(Status))
+ return;
+
+ gTsegAddress_ = CpuInfoHob->TsegAddress;
+ gTsegSize_ = CpuInfoHob->TsegSize;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: CheckAddressRange
+//
+// Description: Check address range to avoid TSEG area.
+//
+// Input:
+// Address - starting address
+// Range - length of the area
+//
+// Output:
+// EFI_SUCCESS - Access granted
+// EFI_SECURITY_VIOLATION - Access denied!
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS CheckAddressRange( IN UINT8 *Address, IN UINTN Range )
+{
+ // if TSEG variables are not initialized then do not validate the access.
+ if ( gTsegAddress_ == 0 || gTsegSize_ == 0 )
+ return EFI_SUCCESS;
+
+ if ( ((EFI_PHYSICAL_ADDRESS)Address >= gTsegAddress_) &&
+ ((EFI_PHYSICAL_ADDRESS)Address <= (gTsegAddress_ + gTsegSize_)) )
+ return EFI_SECURITY_VIOLATION;
+
+ if ( (((EFI_PHYSICAL_ADDRESS)Address + Range) >= gTsegAddress_) &&
+ (((EFI_PHYSICAL_ADDRESS)Address + Range) <= (gTsegAddress_ + gTsegSize_)) )
+ return EFI_SECURITY_VIOLATION;
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: ChsumTbl
+//
+// Description: This function calculates a checksum of table starting at
+// TblStart of length BytesCount and returns the checksum value.
+//
+// Input:
+// *TblStart - Starting address of the memory area to checksum.
+// BytesCount - Length in bytes of the memory area to checksum.
+//
+// Output:
+// Checksum value starting from TblStart and ending at TblStart + BytesCount.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8 ChsumTbl( IN UINT8* TblStart, IN UINT32 BytesCount )
+{
+ UINT8 Result = *TblStart;
+ UINTN i;
+
+ for ( i = 1; i < BytesCount; i++ )
+ Result += TblStart[i];
+ return 0 - Result;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: Oa3UpdateAcpiTable
+//
+// Description: This function will update ACPI table for OA3.
+//
+// Input: ProductKey - pointer to the Product Key
+//
+// Output: EFI_STATUS
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS Oa3UpdateAcpiTable( IN UINT8 *ProductKey )
+{
+ EFI_STATUS Status;
+ EFI_OA3_MSDM_STRUCTURE MsdmVariable = {0};
+ EFI_GUID AmiGlobalVariableGuid = AMI_GLOBAL_VARIABLE_GUID;
+ UINTN Size = sizeof(EFI_OA3_MSDM_STRUCTURE);
+ EFI_ACPI_MSDM_TABLE *MsdmTable;
+ ACPI_HDR *AcpiHdr;
+ UINT8 *Ptr;
+ EFI_PHYSICAL_ADDRESS *AcpiPtr;
+
+ if (ProductKey == NULL)
+ return EFI_INVALID_PARAMETER;
+
+ Status = CheckAddressRange(ProductKey, sizeof(MsdmTable->Data));
+ if (EFI_ERROR(Status))
+ return Status;
+
+ Status = pRS->GetVariable(
+ EFI_OA3_MSDM_VARIABLE,
+ &AmiGlobalVariableGuid,
+ NULL,
+ &Size,
+ &MsdmVariable
+ );
+ TRACE((TRACE_ALWAYS,"Oa3UpdateAcpiTable: XsdtAddr=%X, MsdmAddr=%X\n",MsdmVariable.XsdtAddress,MsdmVariable.MsdmAddress));
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ if ( MsdmVariable.XsdtAddress == 0 || MsdmVariable.MsdmAddress == 0 )
+ return EFI_INVALID_PARAMETER;
+
+ // Validate MSDM table signature
+ MsdmTable = (EFI_ACPI_MSDM_TABLE*)(UINTN)MsdmVariable.MsdmAddress;
+ if (MsdmTable->Header.Signature != MSDM_SIG)
+ return EFI_INVALID_PARAMETER;
+
+ // Validate XSDT table signature
+ AcpiHdr = (ACPI_HDR*)(UINTN)MsdmVariable.XsdtAddress;
+ if (AcpiHdr->Signature != XSDT_SIG)
+ return EFI_INVALID_PARAMETER;
+
+ // Copy a new Product Key to MSDM Data array
+ MemCpy(
+ (UINT8*)&MsdmTable->Version,
+#if OEM_ACTIVATION_TABLE_LOCATION == 0
+ ProductKey,
+#else
+ (UINT8*)OEM_ACTIVATION_TABLE_ADDRESS, // Copy Key from the NCB
+#endif
+ sizeof(EFI_ACPI_MSDM_TABLE) - sizeof(ACPI_HDR) );
+
+ // Updates MSDM table checksum
+ MsdmTable->Header.Checksum = 0;
+ MsdmTable->Header.Checksum = ChsumTbl((UINT8*)MsdmTable, sizeof(EFI_ACPI_MSDM_TABLE));
+
+ // Check if pointer to MSDM ACPI table has been set already
+ Ptr = (UINT8*)AcpiHdr + AcpiHdr->Length - sizeof(EFI_PHYSICAL_ADDRESS);
+ AcpiPtr = (EFI_PHYSICAL_ADDRESS*)Ptr;
+ if ( *AcpiPtr != (EFI_PHYSICAL_ADDRESS)MsdmTable ) {
+
+ // Validate ACPI header's length. Check a range to avoid SMM
+ Ptr = (UINT8*)AcpiHdr + AcpiHdr->Length;
+ Status = CheckAddressRange(Ptr, sizeof(EFI_PHYSICAL_ADDRESS));
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // Check destination if it's cleared by zero
+ AcpiPtr = (EFI_PHYSICAL_ADDRESS*)Ptr;
+ if (*AcpiPtr != 0)
+ return EFI_SECURITY_VIOLATION;
+
+ // Add address of MSDM table as the last pointer in XSDT
+ *AcpiPtr = (EFI_PHYSICAL_ADDRESS)MsdmTable;
+
+ // Updates Length filed of the XSDT table (increments by 8)
+ AcpiHdr->Length += sizeof(EFI_PHYSICAL_ADDRESS);
+
+ // Updates XSDT checksum
+ AcpiHdr->Checksum = 0;
+ AcpiHdr->Checksum = ChsumTbl((UINT8*)AcpiHdr, AcpiHdr->Length);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: SwSmiOa3Function
+//
+// Description:
+// Calling the SMI Interface
+// The caller will write AL (the value 0xee) to the SMI Command Port as
+// defined in the ACPI FADT.
+// The SMI handler will update the callers' buffer(s) and return.
+//
+// Input:
+// DispatchHandle
+// DispatchContext
+//
+// Output: VOID
+//
+// Notes:
+// The function will clear the carry bit if it is successful (CF = 0).
+// If the function is unsuccessful, it will set the carry bit and set the
+// error code in the AH register as indicated by the error table below.
+// The function returns the following data in the provided parameter block.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+#if PI_SPECIFICATION_VERSION<0x0001000A
+VOID SwSmiOa3Function(
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext )
+{
+ EFI_GUID SwSmiCpuTriggerGuid = SW_SMI_CPU_TRIGGER_GUID;
+ UINTN CpuIndex = pSmst->CurrentlyExecutingCpu - 1;
+ UINTN Index;
+
+ // determine which CPU triggered SMI
+ for (Index = 0; Index < pSmst->NumberOfTableEntries; Index++)
+ if ( !guidcmp(&pSmst->SmmConfigurationTable[Index].VendorGuid, &SwSmiCpuTriggerGuid) ) {
+ CpuIndex = ((SW_SMI_CPU_TRIGGER*)pSmst->SmmConfigurationTable[Index].VendorTable)->Cpu;
+ break;
+ }
+
+ // Update the ACPI table
+ Oa3UpdateAcpiTable((UINT8*)(EFI_PHYSICAL_ADDRESS)pSmst->CpuSaveState[CpuIndex].Ia32SaveState.EBX);
+}
+
+#else
+
+EFI_STATUS SwSmiOa3Function(
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL )
+{
+ EFI_STATUS Status;
+ EFI_SMM_SW_CONTEXT *SmmSwContext = ((EFI_SMM_SW_CONTEXT*)CommBuffer);
+ EFI_GUID EfiSmmCpuProtocolGuid = EFI_SMM_CPU_PROTOCOL_GUID;
+ EFI_SMM_CPU_PROTOCOL *SmmCpuProtocol = NULL;
+ EFI_PHYSICAL_ADDRESS Register = 0;
+
+ Status = pSmst->SmmLocateProtocol(
+ &EfiSmmCpuProtocolGuid,
+ NULL,
+ &SmmCpuProtocol
+ );
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // Read the RBX register
+ Status = SmmCpuProtocol->ReadSaveState(
+ SmmCpuProtocol,
+ sizeof(UINT32),
+ EFI_SMM_SAVE_STATE_REGISTER_RBX,
+ SmmSwContext->SwSmiCpuIndex,
+ &Register
+ );
+ if (!EFI_ERROR(Status))
+ Oa3UpdateAcpiTable((UINT8*)Register); // Update the ACPI table
+
+ return Status;
+}
+#endif
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: InSmmFunction
+//
+// Description: Registration of the SMI function
+//
+// Input:
+// ImageHandle - Image handle
+// SystemTable - Pointer to the system table
+//
+// Output: EFI_STATUS
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS InSmmFunction(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle = 0;
+
+#if PI_SPECIFICATION_VERSION<0x0001000A
+ EFI_GUID EfiSmmSwDispatchProtocolGuid = EFI_SMM_SW_DISPATCH_PROTOCOL_GUID;
+ EFI_SMM_SW_DISPATCH_PROTOCOL *SwDispatch = NULL;
+ EFI_SMM_SW_DISPATCH_CONTEXT SwContext;
+ Status = pBS->LocateProtocol(
+#else
+ EFI_GUID EfiSmmSwDispatchProtocolGuid = EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID;
+ EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch = NULL;
+ EFI_SMM_SW_REGISTER_CONTEXT SwContext;
+ Status = pSmst->SmmLocateProtocol(
+#endif
+ &EfiSmmSwDispatchProtocolGuid,
+ NULL,
+ &SwDispatch
+ );
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ SwContext.SwSmiInputValue = SW_SMI_OA3_FUNCTION_NUMBER;
+ Status = SwDispatch->Register(
+ SwDispatch,
+ SwSmiOa3Function,
+ &SwContext,
+ &Handle
+ );
+ ASSERT_EFI_ERROR(Status);
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+//
+// Procedure: SmmOemActivation_EntryPoint
+//
+// Description: This function is the entry point of the module.
+//
+// Input:
+// ImageHandle - Image handle
+// *SystemTable - Pointer to the system table
+//
+// Output: EFI_STATUS
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS EFIAPI SmmOemActivation_EntryPoint(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable )
+{
+ EFI_STATUS Status;
+ EFI_OA3_MSDM_STRUCTURE MsdmVariable;
+ EFI_GUID AmiGlobalVariableGuid = AMI_GLOBAL_VARIABLE_GUID;
+ UINTN Size = sizeof(EFI_OA3_MSDM_STRUCTURE);
+
+ InitAmiLib(ImageHandle, SystemTable);
+
+ // Get TSEG address and TSEG size
+ GetTsegVar();
+
+ // Check if OA3 MSDM variable does exist
+ Status = pRS->GetVariable(
+ EFI_OA3_MSDM_VARIABLE,
+ &AmiGlobalVariableGuid,
+ NULL,
+ &Size,
+ &MsdmVariable
+ );
+ if (!EFI_ERROR(Status)) {
+
+ // then install the SMI handler
+ Status = InitSmmHandler(
+ ImageHandle,
+ SystemTable,
+ InSmmFunction,
+ NULL
+ );
+ TRACE((TRACE_ALWAYS,"OEM Activation: InitSmmHandler Status=%r\n",Status));
+ ASSERT_EFI_ERROR(Status);
+ }
+
+ return Status;
+}
+
+
+//****************************************************************************
+//****************************************************************************
+//** **
+//** (C)Copyright 1985-2012, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone (770)-246-8600 **
+//** **
+//****************************************************************************
+//****************************************************************************