diff options
Diffstat (limited to 'ReferenceCode/ME/ActiveManagement/AlertStandardFormat/Heci/Dxe/AlertStandardFormatDxe.c')
-rw-r--r-- | ReferenceCode/ME/ActiveManagement/AlertStandardFormat/Heci/Dxe/AlertStandardFormatDxe.c | 1234 |
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; +} |