summaryrefslogtreecommitdiff
path: root/ReferenceCode/ME/ActiveManagement/AlertStandardFormat/Heci/Dxe/AlertStandardFormatDxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/ME/ActiveManagement/AlertStandardFormat/Heci/Dxe/AlertStandardFormatDxe.c')
-rw-r--r--ReferenceCode/ME/ActiveManagement/AlertStandardFormat/Heci/Dxe/AlertStandardFormatDxe.c1234
1 files changed, 1234 insertions, 0 deletions
diff --git a/ReferenceCode/ME/ActiveManagement/AlertStandardFormat/Heci/Dxe/AlertStandardFormatDxe.c b/ReferenceCode/ME/ActiveManagement/AlertStandardFormat/Heci/Dxe/AlertStandardFormatDxe.c
new file mode 100644
index 0000000..5119b8e
--- /dev/null
+++ b/ReferenceCode/ME/ActiveManagement/AlertStandardFormat/Heci/Dxe/AlertStandardFormatDxe.c
@@ -0,0 +1,1234 @@
+/** @file
+ Processes ASF messages
+
+@copyright
+ Copyright (c) 2005 - 2012 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 such 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 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
+
+**/
+
+//
+// External include files do NOT need to be explicitly specified in real EDKII
+// environment
+//
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGlueDxe.h"
+#include "AlertStandardFormatDxe.h"
+#include "MeLib.h"
+#endif
+
+#include "AlertStandardFormatCommon.c"
+
+UINT64 mAsfMonotonicCount;
+EFI_ASF_BOOT_OPTIONS mAsfBootOptions;
+BOOLEAN mBootOptionsValid;
+BOOLEAN mAsfAddressValid;
+BOOLEAN mProgressEventEnabled;
+
+ALERT_STANDARD_FORMAT_INSTANCE *mAsfContext;
+
+EFI_GUID gAmtForcePushPetVariableGuid = AMT_FORCE_PUSH_PET_VARIABLE_GUID;
+EFI_GUID gAmtPetQueueHobGuid = AMT_PET_QUEUE_HOB_GUID;
+EFI_GUID gAmtForcePushPetHobGuid = AMT_FORCE_PUSH_PET_HOB_GUID;
+
+AMT_PET_QUEUE_PROTOCOL gAmtPetQueue;
+AMT_PET_QUEUE_PROTOCOL *gAmtPetQueueProtocol;
+AMT_FORCE_PUSH_PET_POLICY_HOB *gAmtForcePushPETPolicyHob;
+
+/**
+ Update ASF Boot Options data in ACPI ASF RCMP table
+
+ @param[in] AsfBootOptions ASF Boot Options data for ACPI ASF RCMP table used
+**/
+VOID
+UpdateAcpiAsfRcmpBootOptions (
+ EFI_ASF_BOOT_OPTIONS *AsfBootOptions
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_1_0_ASF_DESCRIPTION_TABLE *AcpiAsfTable;
+ UINTN Handle;
+ UINTN VersionCount;
+ UINT16 *WordPointer;
+ EFI_ACPI_TABLE_VERSION Version[] = {
+ EFI_ACPI_TABLE_VERSION_1_0B,
+ EFI_ACPI_TABLE_VERSION_2_0,
+ EFI_ACPI_TABLE_VERSION_3_0
+ };
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+
+ ///
+ /// Locate ACPI Table Protocol
+ ///
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+
+ ///
+ /// Initialize ASL manipulation library
+ ///
+ InitializeAslUpdateLib ();
+
+ for (VersionCount = 0; VersionCount < sizeof (Version) / sizeof (EFI_ACPI_TABLE_VERSION); VersionCount++) {
+ Handle = 0;
+ ///
+ /// Locate the ASF Table
+ ///
+ Status = LocateAcpiTableBySignature (
+ EFI_ACPI_1_0_ASF_DESCRIPTION_TABLE_SIGNATURE,
+ (EFI_ACPI_DESCRIPTION_HEADER **) &AcpiAsfTable,
+ &Handle,
+ &Version[VersionCount]
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (AsfBootOptions->SubCommand == ASF_BOOT_OPTIONS_PRESENT) {
+ ///
+ /// Check Asf table if get boot option successfully
+ ///
+ AcpiAsfTable->AsfRmcp.RMCPCompletionCode = 00;
+ AcpiAsfTable->AsfRmcp.RMCPIANA = AsfBootOptions->IanaId;
+ AcpiAsfTable->AsfRmcp.RMCPSpecialCommand = AsfBootOptions->SpecialCommand;
+ WordPointer = (UINT16 *) &AcpiAsfTable->AsfRmcp.RMCPSpecialCommandParameter;
+ *WordPointer = AsfBootOptions->SpecialCommandParam;
+ WordPointer = (UINT16 *) &AcpiAsfTable->AsfRmcp.RMCPBootOptions;
+ *WordPointer = AsfBootOptions->BootOptions;
+ WordPointer = (UINT16 *) &AcpiAsfTable->AsfRmcp.RMCPOEMParameters;
+ *WordPointer = AsfBootOptions->OemParameters;
+ } else {
+ ///
+ /// Failed to get boot option, update the completion code to 0x1
+ ///
+ AcpiAsfTable->AsfRmcp.RMCPCompletionCode = 01;
+ }
+ if (Handle != 0) {
+ Status = AcpiTable->UninstallAcpiTable (
+ AcpiTable,
+ Handle
+ );
+ }
+ ///
+ /// Update the Acpi Asf table
+ ///
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ AcpiAsfTable,
+ sizeof(EFI_ACPI_1_0_ASF_DESCRIPTION_TABLE),
+ &Handle
+ );
+ FreePool (AcpiAsfTable);
+ }
+}
+
+/**
+ 16 bits are changed backward for string transfer to value used
+
+ @param[in] Value The value to be transferred
+
+ @retval UINT16 Value The value after transferring
+**/
+UINT16
+Swap16 (
+ IN UINT16 Value
+ )
+{
+ UINT16 OutValue;
+ UINT8 *TempIn;
+ UINT8 *TempOut;
+
+ TempIn = (UINT8 *) &Value;
+ TempOut = (UINT8 *) &OutValue;
+
+ TempOut[0] = TempIn[1];
+ TempOut[1] = TempIn[0];
+
+ return OutValue;
+}
+
+/**
+ The driver entry point - detect ASF support or not, if support, will install relative protocol.
+
+ @param[in] ImageHandle Handle for this drivers loaded image protocol.
+ @param[in] SystemTable EFI system table.
+
+ @retval EFI_SUCCESS The driver installed without error.
+ @exception EFI_UNSUPPORTED The chipset is unsupported by this driver.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures.
+**/
+EFI_STATUS
+EFIAPI
+AlertStandardFormatDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_DATA_HUB_PROTOCOL *DataHub;
+ EFI_EVENT DataHubEvent;
+ UINT64 DataClass;
+ EFI_ASF_BOOT_OPTIONS *AsfBootOptions;
+
+ ///
+ /// First check if ASF support is enabled in Setup.
+ ///
+ if (!AsfSupported ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mBootOptionsValid = FALSE;
+ mAsfAddressValid = FALSE;
+
+ mAsfContext = AllocateZeroPool (sizeof (ALERT_STANDARD_FORMAT_INSTANCE));
+ ASSERT (mAsfContext != NULL);
+ if (mAsfContext == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ///
+ /// Get the Data Hub Protocol. Assume only one instance
+ /// of Data Hub Protocol is available in the system.
+ ///
+ Status = gBS->LocateProtocol (
+ &gEfiDataHubProtocolGuid,
+ NULL,
+ (VOID **) &DataHub
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mAsfContext->Handle = ImageHandle;
+ mAsfContext->Signature = ALERT_STANDARD_FORMAT_PRIVATE_DATA_SIGNATURE;
+ mAsfContext->AlertStandardFormat.GetSmbusAddr = GetSmbusAddr;
+ mAsfContext->AlertStandardFormat.SetSmbusAddr = SetSmbusAddr;
+ mAsfContext->AlertStandardFormat.GetBootOptions = GetBootOptions;
+ mAsfContext->AlertStandardFormat.SendAsfMessage = SendAsfMessage;
+
+ ///
+ /// Sending ASF Messaging if ManageabilityMode is not zero
+ ///
+ if (ManageabilityModeSetting () != MNT_OFF) {
+ ///
+ /// ActiveManagement Protocol is not ready at this point. Need to Check Boot Options Manually
+ ///
+ mProgressEventEnabled = FALSE;
+ Status = GetBootOptions (&(mAsfContext->AlertStandardFormat), &AsfBootOptions);
+ if (!EFI_ERROR (Status)) {
+ if (AsfBootOptions->SubCommand == ASF_BOOT_OPTIONS_PRESENT) {
+ if ((AsfBootOptions->BootOptions & FORCE_PROGRESS_EVENTS) == FORCE_PROGRESS_EVENTS) {
+ mProgressEventEnabled = TRUE;
+ }
+ }
+ }
+ ///
+ /// If no boot options available, check policy
+ ///
+ if (!mProgressEventEnabled) {
+ mProgressEventEnabled = FwProgressSupport ();
+ }
+ ///
+ /// Create message queue
+ ///
+ AmtCreateMessageQueue ();
+
+ ///
+ /// Get ForcePushPetPolicy Hob
+ ///
+ gAmtForcePushPETPolicyHob = GetForcePushPetPolicy ();
+
+ ///
+ /// save PEI force push error event from hob to variable
+ ///
+ SaveForcePushErrorEventFromPeiToDxe ();
+
+ ///
+ /// Try to send message
+ ///
+ SendPETMessageInQueue ();
+
+ ///
+ /// Register our Setup Data Filter Function.
+ /// This function is notified at the lowest TPL
+ ///
+ Status = gBS->CreateEvent (
+ EVENT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DataHubEventCallback,
+ NULL,
+ &DataHubEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (mProgressEventEnabled) {
+ DataClass = EFI_DATA_RECORD_CLASS_ERROR | EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
+ } else {
+ DataClass = EFI_DATA_RECORD_CLASS_ERROR;
+ }
+
+ Status = DataHub->RegisterFilterDriver (
+ DataHub,
+ DataHubEvent,
+ EFI_TPL_APPLICATION,
+ DataClass,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ ///
+ /// Install the AlertStandardFormat interface
+ ///
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mAsfContext->Handle,
+ &gEfiAlertStandardFormatProtocolGuid,
+ &mAsfContext->AlertStandardFormat,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Return the SMBus address used by the ASF driver.
+ Not applicable in Intel ME/HECI system, need to return EFI_UNSUPPORTED.
+
+ @param[in] This The address of protocol
+ @param[in] SmbusDeviceAddress Out put the Smbus Address
+
+ @exception EFI_UNSUPPORTED The function is unsupported by this driver
+**/
+EFI_STATUS
+EFIAPI
+GetSmbusAddr (
+ IN EFI_ALERT_STANDARD_FORMAT_PROTOCOL *This,
+ OUT UINTN *SmbusDeviceAddress
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Set the SMBus address used by the ASF driver. 0 is an invalid address.
+ Not applicable in Intel ME/HECI system, need to return EFI_UNSUPPORTED.
+
+ @param[in] This The address of protocol
+ @param[in] SmbusDeviceAddress SMBus address of the device
+
+ @exception EFI_UNSUPPORTED The function is unsupported by this driver
+**/
+EFI_STATUS
+EFIAPI
+SetSmbusAddr (
+ IN EFI_ALERT_STANDARD_FORMAT_PROTOCOL *This,
+ IN UINTN SmbusDeviceAddress
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Return EFI_SUCCESS if Firmware Init Complete is set in HFS[9].
+
+ @param[in] Heci EFI_HECI_PROTOCOL
+ @param[in] Timeout Time in second
+
+ @retval EFI_SUCCESS Firmware Init Complete is set
+ @retval EFI_TIMEOUT Firmware Init Complete is not set in 5 seconds
+**/
+EFI_STATUS
+WaitFirmwareInitDone (
+ EFI_HECI_PROTOCOL *Heci,
+ UINT32 Timeout
+ )
+{
+ UINT32 idx;
+ EFI_STATUS Status;
+ UINT32 MeStatus;
+
+ Status = EFI_SUCCESS;
+ idx = 0;
+
+ Heci->GetMeStatus (&MeStatus);
+
+ while (!ME_STATUS_IS_ME_FW_INIT_COMPLETE (MeStatus)) {
+ gBS->Stall (100000);
+ idx++;
+ if (idx > Timeout * 10) {
+ Status = EFI_TIMEOUT;
+ break;
+ }
+
+ Heci->GetMeStatus (&MeStatus);
+ }
+
+ return Status;
+}
+
+/**
+ Initialize KVM by sending HECI messafe to ME
+
+ @param[in] Event The event registered.
+ @param[in] Context Event context. Not used in this event handler.
+**/
+VOID
+EFIAPI
+QueryKvm (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ BdsKvmInitialization ();
+ gBS->CloseEvent (Event);
+}
+
+/**
+ Return the ASF Boot Options obtained from the controller. If the
+ Boot Options parameter is NULL and no boot options have been retrieved,
+ Query the ASF controller for its boot options.
+ Get ASF Boot Options through HECI.
+
+ @param[in] This The address of protocol
+ @param[in] AsfBootOptions Pointer to ASF boot options to copy current ASF Boot options
+
+ @retval EFI_SUCCESS Boot options copied
+ @retval EFI_NOT_READY No boot options
+**/
+EFI_STATUS
+EFIAPI
+GetBootOptions (
+ IN EFI_ALERT_STANDARD_FORMAT_PROTOCOL *This,
+ IN OUT EFI_ASF_BOOT_OPTIONS **AsfBootOptions
+ )
+{
+ EFI_STATUS Status;
+ UINT8 ConsoleLock;
+ UINT32 MeStatus;
+ UINT32 MeMode;
+ EFI_STATUS TempStatus;
+ VOID *AfterConsolOutNotifyReg;
+ EFI_EVENT AfterConsolOutInstalledEvent;
+ EFI_GUID guidConOutStarted = EFI_CONSOLE_OUT_DEVICE_GUID;
+ EFI_HECI_PROTOCOL *Heci;
+ HECI_ASF_GET_BOOT_OPTIONS_RESPONSE HeciAsfGetBootOptionsResponse;
+ HECI_ASF_CLEAR_BOOT_OPTION HeciAsfClearBootOption;
+ UINT32 HeciLength;
+
+ if (!mBootOptionsValid) {
+ Status = gBS->LocateProtocol (
+ &gEfiHeciProtocolGuid,
+ NULL,
+ (VOID **) &Heci
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "ASF Get Boot Options failed!, Status = %r\n", Status));
+ return Status;
+ }
+
+ ZeroMem ((VOID *) &mAsfBootOptions, sizeof (EFI_ASF_BOOT_OPTIONS));
+ mAsfBootOptions.SubCommand = ASF_BOOT_OPTIONS_NOT_PRESENT;
+ mAsfBootOptions.Version = 0x10;
+ UpdateAcpiAsfRcmpBootOptions (&mAsfBootOptions);
+
+ ///
+ /// Get ME Status
+ ///
+ TempStatus = Heci->GetMeStatus (&MeStatus);
+ ASSERT_EFI_ERROR (TempStatus);
+
+ ///
+ /// Get ME Operation Mode
+ ///
+ Heci->GetMeMode (&MeMode);
+
+ ///
+ /// Only Send ASF Get Boot Options message when ME is ready and ME FW INIT is completed
+ ///
+ if (ME_STATUS_IS_ME_FW_BOOT_OPTIONS_PRESENT (MeStatus) &&
+ (ManageabilityModeSetting () != MNT_OFF) &&
+ (MeMode == ME_MODE_NORMAL)
+ ) {
+ if (WaitFirmwareInitDone (Heci, 5) != EFI_TIMEOUT) {
+ ///
+ /// Prepare Boot Option Command header
+ ///
+ HeciAsfGetBootOptionsResponse.Command = EFI_ASF_MESSAGE_COMMAND_ASF_CONFIGURATION;
+ HeciAsfGetBootOptionsResponse.ByteCount = EFI_ASF_MESSAGE_BYTEOUNTT_GET_BOOT_OPT;
+ HeciAsfGetBootOptionsResponse.AsfBootOptions.SubCommand = EFI_ASF_MESSAGE_SUBCOMMAND_RETURN_BOOT_OPT;
+ HeciAsfGetBootOptionsResponse.AsfBootOptions.Version = 0x10;
+ HeciLength = HECI_ASF_GET_BOOT_OPTIONS_LENGTH;
+ Status = Heci->SendMsg (
+ (UINT32 *) &HeciAsfGetBootOptionsResponse,
+ HeciLength,
+ BIOS_ASF_HOST_ADDR,
+ HECI_ASF_MESSAGE_ADDR
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "ASF Get Boot Options failed!(SendwACK), Status = %r\n", Status));
+ return Status;
+ }
+
+ HeciLength = HECI_ASF_GET_BOOT_OPTIONS_RESPONSE_LENGTH;
+ Status = Heci->ReadMsg (
+ BLOCKING,
+ (UINT32 *) &HeciAsfGetBootOptionsResponse,
+ &HeciLength
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "ASF Get Boot Options failed!(ReadMsg), Status = %r\n", Status));
+ return Status;
+ }
+
+ CopyMem (
+ (VOID *) &mAsfBootOptions,
+ (VOID *) &(HeciAsfGetBootOptionsResponse.AsfBootOptions),
+ sizeof (EFI_ASF_BOOT_OPTIONS)
+ );
+
+ ///
+ /// By default, this table is belong to all ACPI table versions.
+ /// It is ok if the table is not found and that means the platform does not publish that version.
+ ///
+ UpdateAcpiAsfRcmpBootOptions (&mAsfBootOptions);
+
+ mAsfBootOptions.SpecialCommandParam = Swap16 (mAsfBootOptions.SpecialCommandParam);
+
+ ///
+ /// ASF Get Boot Options - Clear Boot Options
+ /// Need to do this so don't get caught in an endless loop plus by
+ /// definition get boot options is a one time boot situation.
+ /// So if server on other end of ASF device wants another back to back
+ /// boot it will request it. Do this only if there were boot options
+ ///
+ if (mAsfBootOptions.SubCommand == ASF_BOOT_OPTIONS_PRESENT) {
+ HeciAsfClearBootOption.Command = EFI_ASF_MESSAGE_COMMAND_ASF_CONFIGURATION;
+ HeciAsfClearBootOption.AsfClearBootOptions.SubCommand = EFI_ASF_MESSAGE_SUBCOMMAND_CLEAR_BOOT_OPT;
+ HeciAsfClearBootOption.AsfClearBootOptions.Version = EFI_ASF_MESSAGE_VERSIONNUMBER;
+ HeciAsfClearBootOption.ByteCount = EFI_ASF_MESSAGE_BYTECOUNT_CLEAR_BOOT_OPT;
+ HeciLength = HECI_ASF_CLEAR_BOOT_OPTION_LENGTH;
+
+ Status = Heci->SendMsg (
+ (UINT32 *) &HeciAsfClearBootOption,
+ HeciLength,
+ BIOS_ASF_HOST_ADDR,
+ HECI_ASF_MESSAGE_ADDR
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "ASF Clear Boot Options failed!, Status = %r\n", Status));
+ return Status;
+ }
+ }
+ }
+ }
+ ///
+ /// Set flag so we don't try to get the Boot options again.
+ ///
+ mBootOptionsValid = TRUE;
+
+ ///
+ /// Set up Event for KVM for when Output Display Console is installed
+ ///
+ if ((mAsfBootOptions.SpecialCommandParam & USE_KVM) == USE_KVM) {
+
+ Status = gBS->CreateEvent (
+ EFI_EVENT_NOTIFY_SIGNAL,
+ EFI_TPL_NOTIFY,
+ QueryKvm,
+ NULL,
+ &AfterConsolOutInstalledEvent
+ );
+
+ Status = gBS->RegisterProtocolNotify (
+ &guidConOutStarted,
+ AfterConsolOutInstalledEvent,
+ &AfterConsolOutNotifyReg
+ );
+
+ }
+ ///
+ /// Check for keyboard locking in the boot options
+ ///
+ ConsoleLock = NO_LOCK_CONSOLE;
+
+ if (mAsfBootOptions.SubCommand == ASF_BOOT_OPTIONS_PRESENT) {
+ if ((mAsfBootOptions.BootOptions & LOCK_KEYBOARD) == LOCK_KEYBOARD) {
+ ConsoleLock = LOCK_CONSOLE;
+ }
+ }
+ ///
+ /// Save the console lock flag for later usage in console locking determination
+ ///
+ gRT->SetVariable (
+ EFI_CONSOLE_LOCK_VARIABLE_NAME,
+ &gEfiConsoleLockGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (ConsoleLock),
+ &ConsoleLock
+ );
+ }
+
+ if (AsfBootOptions) {
+ *AsfBootOptions = &mAsfBootOptions;
+
+ ///
+ /// If we're asking for the options, then resend them to the debug output just encase they've been hosed.
+ ///
+ DEBUG ((EFI_D_ERROR, "mAsfBootOptions.SubCommand = 0x%x\n", mAsfBootOptions.SubCommand));
+ DEBUG ((EFI_D_ERROR, "mAsfBootOptions.Version = 0x%x\n", mAsfBootOptions.Version));
+ DEBUG ((EFI_D_ERROR, "mAsfBootOptions.IanaId = 0x%x\n", mAsfBootOptions.IanaId));
+ DEBUG ((EFI_D_ERROR, "mAsfBootOptions.SpecialCommand = 0x%x\n", mAsfBootOptions.SpecialCommand));
+ DEBUG ((EFI_D_ERROR, "mAsfBootOptions.SpecialCommandParam = 0x%x\n", mAsfBootOptions.SpecialCommandParam));
+ DEBUG ((EFI_D_ERROR, "mAsfBootOptions.BootOptions = 0x%x\n", mAsfBootOptions.BootOptions));
+ DEBUG ((EFI_D_ERROR, "mAsfBootOptions.OemParameters = 0x%x\n", mAsfBootOptions.OemParameters));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send ASF Message through HECI.
+
+ @param[in] This The address of protocol
+ @param[in] AsfMessage Pointer to ASF message
+
+ @retval EFI_SUCCESS Boot options copied
+ @retval EFI_INVALID_PARAMETER Invalid pointer
+ @retval EFI_NOT_READY No controller
+**/
+EFI_STATUS
+EFIAPI
+SendAsfMessage (
+ IN EFI_ALERT_STANDARD_FORMAT_PROTOCOL *This,
+ IN EFI_ASF_MESSAGE *AsfMessage
+ )
+{
+ EFI_STATUS Status;
+ EFI_HECI_PROTOCOL *Heci;
+ UINT32 HeciLength;
+ HECI_ASF_PUSH_PROGRESS_CODE HeciAsfPushProgressCode;
+ UINT32 MeStatus;
+ UINT32 MeMode;
+ EFI_STATUS TempStatus;
+
+ Status = gBS->LocateProtocol (
+ &gEfiHeciProtocolGuid,
+ NULL,
+ (VOID **) &Heci
+ );
+
+ if (!EFI_ERROR (Status)) {
+ TempStatus = Heci->GetMeStatus (&MeStatus);
+ ASSERT_EFI_ERROR (TempStatus);
+
+ ///
+ /// Get ME Operation Mode
+ ///
+ Heci->GetMeMode (&MeMode);
+
+ ///
+ /// Only send ASF Push Progress code when ME is ready and ME is in normal mode. Ignore FW Init Status.
+ ///
+ if (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_READY && MeMode == ME_MODE_NORMAL) {
+ ZeroMem ((VOID *) &HeciAsfPushProgressCode, sizeof (HECI_ASF_PUSH_PROGRESS_CODE));
+ HeciAsfPushProgressCode.Command = EFI_ASF_MESSAGE_COMMAND_MESSAGE;
+ HeciAsfPushProgressCode.ByteCount = 0x10;
+ HeciLength = HECI_ASF_PUSH_PROGRESS_CODE_LENGTH;
+ CopyMem ((VOID *) &(HeciAsfPushProgressCode.AsfMessage), (VOID *) AsfMessage, sizeof (EFI_ASF_MESSAGE));
+
+ Status = Heci->SendMsg (
+ (UINT32 *) &HeciAsfPushProgressCode,
+ HeciLength,
+ BIOS_ASF_HOST_ADDR,
+ HECI_ASF_MESSAGE_ADDR
+ );
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This routine returns ForcePushPetPolicy information.
+
+ @param[in] None
+
+ @retval AMT_FORCE_PUSH_PET_POLICY_HOB ForcePushPetPolicy information.
+**/
+AMT_FORCE_PUSH_PET_POLICY_HOB *
+GetForcePushPetPolicy (
+ VOID
+ )
+{
+ AMT_FORCE_PUSH_PET_POLICY_HOB *AmtForcePushPETPolicyHob;
+ EFI_STATUS Status;
+
+ Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, (VOID **) &AmtForcePushPETPolicyHob);
+ ASSERT_EFI_ERROR (Status);
+
+ return GetNextGuidHob (&gAmtForcePushPetPolicyGuid, AmtForcePushPETPolicyHob);
+}
+
+/**
+ This routine checks whethre current message is ForcePush message.
+
+ @param[in] MessageType AMT PET Message Type.
+
+ @retval TRUE It is ForcePush message.
+ @retval FALSE It is not ForcePush message.
+**/
+BOOLEAN
+IsForcePushErrorEvent (
+ IN EFI_FRAMEWORK_MESSAGE_TYPE MessageType
+ )
+{
+ UINTN Index;
+ UINTN Number;
+
+ Number = (gAmtForcePushPETPolicyHob->EfiHobGuidType.Header.HobLength - sizeof (EFI_HOB_GUID_TYPE)) /
+ sizeof (EFI_FRAMEWORK_MESSAGE_TYPE);
+ for (Index = 0; Index < Number; Index++) {
+ if (gAmtForcePushPETPolicyHob->MessageType[Index] == MessageType) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Filters all the progress and error codes for Asf.
+
+ @param[in] Event The event registered.
+ @param[in] Context Event context. Not used in this event handler.
+**/
+VOID
+EFIAPI
+DataHubEventCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_DATA_HUB_PROTOCOL *DataHub;
+ EFI_DATA_RECORD_HEADER *Record;
+ DATA_HUB_STATUS_CODE_DATA_RECORD *StatusRecord;
+ UINTN Index;
+
+ ///
+ /// Get the Data Hub Protocol. Assume only one instance
+ ///
+ Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (VOID **) &DataHub);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Get all available data records from data hub
+ ///
+ Record = NULL;
+
+ do {
+ Status = DataHub->GetNextRecord (DataHub, &mAsfMonotonicCount, &Event, &Record);
+ if (!EFI_ERROR (Status)) {
+ if (mProgressEventEnabled) {
+ if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_PROGRESS_CODE) {
+ StatusRecord = (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record + 1);
+ for (Index = 0; Index < sizeof (mAsfProgressDataHubMap) / sizeof (EFI_ASF_DATA_HUB_MAP); Index++) {
+ if (mAsfProgressDataHubMap[Index].StatusCodeValue == StatusRecord->Value) {
+ Status = SendPostPacket (mAsfProgressDataHubMap[Index].MessageType);
+ break;
+ }
+ }
+ }
+ }
+
+ if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_ERROR) {
+ StatusRecord = (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record + 1);
+ for (Index = 0; Index < sizeof (mAsfErrorDataHubMap) / sizeof (EFI_ASF_DATA_HUB_MAP); Index++) {
+ if (mAsfErrorDataHubMap[Index].StatusCodeValue == StatusRecord->Value) {
+ Status = SendPostPacket (mAsfErrorDataHubMap[Index].MessageType);
+ if ((Status == EFI_DEVICE_ERROR) && IsForcePushErrorEvent (mAsfErrorDataHubMap[Index].MessageType)) {
+ SaveForcePushErrorEvent (mAsfErrorDataHubMap[Index].MessageType);
+ }
+ break;
+ }
+ }
+ }
+ }
+ } while (!EFI_ERROR (Status) && (mAsfMonotonicCount != 0));
+}
+
+/**
+ Sends a POST packet across ASF
+
+ @param[in] MessageType POST Status Code
+
+ @retval EFI_DEVICE_ERROR No message found
+ @retval EFI_SUCCESS Boot options copied
+ @retval EFI_INVALID_PARAMETER Invalid pointer
+ @retval EFI_NOT_READY No controller
+**/
+EFI_STATUS
+SendPostPacket (
+ IN EFI_FRAMEWORK_MESSAGE_TYPE MessageType
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = EFI_DEVICE_ERROR;
+ ///
+ /// Find the message to send across the wire
+ ///
+ for (Index = 0; Index < sizeof (mAsfFrameworkMessage) / sizeof (EFI_ASF_FRAMEWORK_MESSAGE); Index++) {
+ if (mAsfFrameworkMessage[Index].MessageType == MessageType) {
+ Status = SendAsfMessage (NULL, &mAsfFrameworkMessage[Index].Message);
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Provides an interface that a software module can call to report an ASF DXE status code.
+
+ @param[in] Type Indicates the type of status code being reported.
+ @param[in] Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is
+ used to classify the entity as well as an operation.
+ @param[in] Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param[in] CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different
+ rules to different callers.
+ @param[in] Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_DEVICE_ERROR The function should not be completed due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+AmtReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID * CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA * Data OPTIONAL
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if (mProgressEventEnabled) {
+ if ((Type & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
+ for (Index = 0; Index < sizeof (mAsfProgressDataHubMap) / sizeof (EFI_ASF_DATA_HUB_MAP); Index++) {
+ if (mAsfProgressDataHubMap[Index].StatusCodeValue == Value) {
+ return SendPostPacket (mAsfProgressDataHubMap[Index].MessageType);
+ }
+ }
+ }
+ }
+
+ if ((Type & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
+ for (Index = 0; Index < sizeof (mAsfErrorDataHubMap) / sizeof (EFI_ASF_DATA_HUB_MAP); Index++) {
+ if (mAsfErrorDataHubMap[Index].StatusCodeValue == Value) {
+ Status = SendPostPacket (mAsfErrorDataHubMap[Index].MessageType);
+ if ((Status == EFI_DEVICE_ERROR) && IsForcePushErrorEvent (mAsfErrorDataHubMap[Index].MessageType)) {
+ SaveForcePushErrorEvent (mAsfErrorDataHubMap[Index].MessageType);
+ }
+
+ return Status;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine puts PET message to MessageQueue, which will be sent later.
+
+ @param[in] Type StatusCode message type.
+ @param[in] Value StatusCode message value.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures
+**/
+EFI_STATUS
+QueuePetMessage (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value
+ )
+{
+ AMT_PET_QUEUE_NODE *NewNode;
+
+ NewNode = AllocateZeroPool (sizeof (AMT_PET_QUEUE_NODE));
+ ASSERT (NewNode != NULL);
+ if (NewNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewNode->Signature = AMT_PET_QUEUE_NODE_SIGNATURE;
+ NewNode->Type = Type;
+ NewNode->Value = Value;
+ InsertTailList ((LIST_ENTRY *) &gAmtPetQueueProtocol->MessageList, (LIST_ENTRY *) &NewNode->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine sends PET message in MessageQueue.
+
+ @param[in] PeiServices PeiServices pointer.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_NOT_READY No controller
+**/
+EFI_STATUS
+SendPETMessageInQueue (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ AMT_PET_QUEUE_HOB *PETQueueHob;
+ EFI_LIST_ENTRY *Link;
+ AMT_PET_QUEUE_NODE *Node;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ EFI_HECI_PROTOCOL *Heci;
+ UINT32 MeStatus;
+ EFI_STATUS TempStatus;
+
+ ///
+ /// Try HECI state
+ ///
+ Status = gBS->LocateProtocol (
+ &gEfiHeciProtocolGuid,
+ NULL,
+ (VOID **) &Heci
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_READY;
+ }
+
+ TempStatus = Heci->GetMeStatus (&MeStatus);
+ ASSERT_EFI_ERROR (TempStatus);
+
+ ///
+ /// Only send ASF Push Progress code when ME is ready. Ignore FW Init Status.
+ ///
+ if (ME_STATUS_ME_STATE_ONLY (MeStatus) != ME_READY) {
+ return EFI_NOT_READY;
+ }
+ ///
+ /// Get PETQueueHob
+ ///
+ Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, (VOID **) &PETQueueHob);
+
+ while (TRUE) {
+ PETQueueHob = GetNextGuidHob (&gAmtPetQueueHobGuid, PETQueueHob);
+ if (PETQueueHob == NULL) {
+ break;
+ }
+ ///
+ /// Send message
+ ///
+ AmtReportStatusCode (PETQueueHob->Type, PETQueueHob->Value, 0, NULL, NULL);
+
+ ///
+ /// Mark it as sent
+ ///
+ PETQueueHob->Type = (UINT32) -1;
+
+ ///
+ /// Need find next one
+ ///
+ Hob.Raw = (VOID *) PETQueueHob;
+ PETQueueHob = (AMT_PET_QUEUE_HOB *) GET_NEXT_HOB (Hob);
+ }
+ ///
+ /// Send DXEQueue
+ ///
+ Link = (EFI_LIST_ENTRY *) GetFirstNode ((LIST_ENTRY *) &gAmtPetQueueProtocol->MessageList);
+
+ while (!IsNull ((LIST_ENTRY *) &gAmtPetQueueProtocol->MessageList, (LIST_ENTRY *) Link)) {
+ Node = AMT_PET_QUEUE_NODE_FROM_LINK (Link);
+
+ ///
+ /// Send message
+ ///
+ AmtReportStatusCode (Node->Type, Node->Value, 0, NULL, NULL);
+
+ ///
+ /// Mark it as sent
+ ///
+ Node->Type = (UINT32) -1;
+
+ Link = (EFI_LIST_ENTRY *) GetNextNode (
+ (LIST_ENTRY *) &gAmtPetQueueProtocol->MessageList,
+ (LIST_ENTRY *) &Node->Link
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine creats PET MessageQueue.
+
+ @param[in] None
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+AmtCreateMessageQueue (
+ VOID
+ )
+{
+ ///
+ /// Create Queue for later usage
+ ///
+ gAmtPetQueueProtocol = &gAmtPetQueue;
+
+ InitializeListHead ((LIST_ENTRY *) &gAmtPetQueueProtocol->MessageList);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine saves current ForcePush ErrorEvent to Variable, which will be sent again.
+
+ @param[in] MessageType ASF PET message type.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures
+**/
+EFI_STATUS
+SaveForcePushErrorEvent (
+ IN EFI_FRAMEWORK_MESSAGE_TYPE MessageType
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ EFI_FRAMEWORK_MESSAGE_TYPE *Message;
+
+ ///
+ /// Create PET queue variable
+ ///
+ Message = NULL;
+ Size = 0;
+ Status = gRT->GetVariable (
+ AMT_FORCE_PUSH_PET_VARIABLE_NAME,
+ &gAmtForcePushPetVariableGuid,
+ NULL,
+ &Size,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ ///
+ /// Get the exist message
+ ///
+ Message = AllocateZeroPool (Size + sizeof (MessageType));
+ ASSERT (Message != NULL);
+ if (Message == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable (
+ AMT_FORCE_PUSH_PET_VARIABLE_NAME,
+ &gAmtForcePushPetVariableGuid,
+ NULL,
+ &Size,
+ Message
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Fill new item
+ ///
+ *(EFI_FRAMEWORK_MESSAGE_TYPE *) ((UINTN) Message + Size) = MessageType;
+ Size += sizeof (MessageType);
+ } else if (Status == EFI_NOT_FOUND) {
+ ///
+ /// Create a new one
+ ///
+ Size = sizeof (MessageType);
+ Message = AllocateZeroPool (sizeof (MessageType));
+ ASSERT (Message != NULL);
+ if (Message == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Message = MessageType;
+ } else {
+ ASSERT (FALSE);
+ }
+ ///
+ /// Set PET message to variable
+ ///
+ if (Message != NULL) {
+ Status = gRT->SetVariable (
+ AMT_FORCE_PUSH_PET_VARIABLE_NAME,
+ &gAmtForcePushPetVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ Message
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Message);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine converts Hob ForcePush ErrorEvent to Variable, which will be sent again.
+
+ @param[in] None
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SaveForcePushErrorEventFromPeiToDxe (
+ VOID
+ )
+{
+ AMT_FORCE_PUSH_PET_HOB *AmtForcePushPETHob;
+ EFI_STATUS Status;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ ///
+ /// Find ASF ForcePush PET Hob
+ ///
+ Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, (VOID **) &AmtForcePushPETHob);
+
+ while (TRUE) {
+ AmtForcePushPETHob = GetNextGuidHob (&gAmtForcePushPetHobGuid, AmtForcePushPETHob);
+ if (AmtForcePushPETHob == NULL) {
+ break;
+ }
+
+ SaveForcePushErrorEvent (AmtForcePushPETHob->MessageType);
+
+ ///
+ /// Need find next one
+ ///
+ Hob.Raw = (VOID *) AmtForcePushPETHob;
+ AmtForcePushPETHob = (AMT_FORCE_PUSH_PET_HOB *) GET_NEXT_HOB (Hob);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine tries to send all ForcePush ErrorEvent.
+ If message is sent, it will be deleted from Variable.
+ If message is not sent, it will be still stored to Variable.
+
+ @param[in] None
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures
+**/
+EFI_STATUS
+SendAllForcePushErrorEvent (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ EFI_FRAMEWORK_MESSAGE_TYPE *Message;
+ UINTN Index;
+ EFI_FRAMEWORK_MESSAGE_TYPE *NewMessage;
+ UINTN NewIndex;
+
+ ///
+ /// Create PET queue variable
+ ///
+ Message = NULL;
+ Size = 0;
+ Status = gRT->GetVariable (
+ AMT_FORCE_PUSH_PET_VARIABLE_NAME,
+ &gAmtForcePushPetVariableGuid,
+ NULL,
+ &Size,
+ NULL
+ );
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_SUCCESS;
+ }
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+ ///
+ /// Get the exist message
+ ///
+ Message = AllocateZeroPool (Size);
+ ASSERT (Message != NULL);
+ if (Message == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewMessage = AllocateZeroPool (Size);
+ ASSERT (NewMessage != NULL);
+ if (NewMessage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable (
+ AMT_FORCE_PUSH_PET_VARIABLE_NAME,
+ &gAmtForcePushPetVariableGuid,
+ NULL,
+ &Size,
+ Message
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ NewIndex = 0;
+ for (Index = 0; Index < Size / sizeof (EFI_FRAMEWORK_MESSAGE_TYPE); Index++) {
+ Status = SendPostPacket (Message[Index]);
+ if (EFI_ERROR (Status)) {
+ ///
+ /// Fail, save it again.
+ ///
+ NewMessage[NewIndex] = Message[Index];
+ NewIndex++;
+ }
+ }
+
+ FreePool (Message);
+
+ ///
+ /// SetVariable again
+ ///
+ if (NewIndex == 0) {
+ FreePool (NewMessage);
+ NewMessage = NULL;
+ }
+
+ Status = gRT->SetVariable (
+ AMT_FORCE_PUSH_PET_VARIABLE_NAME,
+ &gAmtForcePushPetVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ NewIndex * sizeof (EFI_FRAMEWORK_MESSAGE_TYPE),
+ NewMessage
+ );
+
+ if (NewMessage != NULL) {
+ FreePool (NewMessage);
+ }
+
+ return EFI_SUCCESS;
+}