|
@@ -0,0 +1,309 @@
|
|
|
+/** @file
|
|
|
+ This is to publish the SMM Control Ppi instance.
|
|
|
+
|
|
|
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
|
|
|
+ SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
+
|
|
|
+**/
|
|
|
+#include <Uefi/UefiBaseType.h>
|
|
|
+#include <Library/DebugLib.h>
|
|
|
+#include <Library/IoLib.h>
|
|
|
+#include <Library/MemoryAllocationLib.h>
|
|
|
+#include <Library/PcdLib.h>
|
|
|
+#include <Library/PeiServicesLib.h>
|
|
|
+
|
|
|
+#include <Ppi/MmControl.h>
|
|
|
+#include <IndustryStandard/Pci30.h>
|
|
|
+
|
|
|
+#define SMM_CONTROL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', '4', 's', 'c')
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ UINTN Signature;
|
|
|
+ EFI_HANDLE Handle;
|
|
|
+ EFI_PEI_MM_CONTROL_PPI SmmControl;
|
|
|
+} SMM_CONTROL_PRIVATE_DATA;
|
|
|
+
|
|
|
+#define SMM_CONTROL_PRIVATE_DATA_FROM_THIS(a) \
|
|
|
+ CR (a, \
|
|
|
+ SMM_CONTROL_PRIVATE_DATA, \
|
|
|
+ SmmControl, \
|
|
|
+ SMM_CONTROL_DEV_SIGNATURE \
|
|
|
+ )
|
|
|
+
|
|
|
+//
|
|
|
+// Common registers:
|
|
|
+//
|
|
|
+//
|
|
|
+// APM Registers
|
|
|
+//
|
|
|
+#define R_PCH_APM_CNT 0xB2
|
|
|
+//
|
|
|
+// ACPI and legacy I/O register offsets from ACPIBASE
|
|
|
+//
|
|
|
+#define R_PCH_ACPI_PM1_STS 0x00
|
|
|
+#define B_PCH_ACPI_PM1_STS_PRBTNOR BIT11
|
|
|
+
|
|
|
+#define R_PCH_SMI_EN 0x30
|
|
|
+
|
|
|
+#define R_PCH_SMI_STS 0x34
|
|
|
+#define B_PCH_SMI_STS_APM BIT5
|
|
|
+#define B_PCH_SMI_EN_APMC BIT5
|
|
|
+#define B_PCH_SMI_EN_EOS BIT1
|
|
|
+#define B_PCH_SMI_EN_GBL_SMI BIT0
|
|
|
+
|
|
|
+/**
|
|
|
+ Trigger the software SMI
|
|
|
+
|
|
|
+ @param[in] Data The value to be set on the software SMI data port
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS Function completes successfully
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+SmmTrigger (
|
|
|
+ UINT8 Data
|
|
|
+ )
|
|
|
+{
|
|
|
+ UINT16 ABase;
|
|
|
+ UINT32 OutputData;
|
|
|
+ UINT32 OutputPort;
|
|
|
+
|
|
|
+ ABase = FixedPcdGet16 (PcdAcpiBaseAddress);
|
|
|
+
|
|
|
+ ///
|
|
|
+ /// Enable the APMC SMI
|
|
|
+ ///
|
|
|
+ OutputPort = ABase + R_PCH_SMI_EN;
|
|
|
+ OutputData = IoRead32 ((UINTN) OutputPort);
|
|
|
+ OutputData |= (B_PCH_SMI_EN_APMC | B_PCH_SMI_EN_GBL_SMI);
|
|
|
+ DEBUG (
|
|
|
+ (DEBUG_EVENT,
|
|
|
+ "The SMI Control Port at address %x will be written to %x.\n",
|
|
|
+ OutputPort,
|
|
|
+ OutputData)
|
|
|
+ );
|
|
|
+ IoWrite32 (
|
|
|
+ (UINTN) OutputPort,
|
|
|
+ (UINT32) (OutputData)
|
|
|
+ );
|
|
|
+
|
|
|
+ OutputPort = R_PCH_APM_CNT;
|
|
|
+ OutputData = Data;
|
|
|
+
|
|
|
+ ///
|
|
|
+ /// Generate the APMC SMI
|
|
|
+ ///
|
|
|
+ IoWrite8 (
|
|
|
+ (UINTN) OutputPort,
|
|
|
+ (UINT8) (OutputData)
|
|
|
+ );
|
|
|
+
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Clear the SMI status
|
|
|
+
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS The function completes successfully
|
|
|
+ @retval EFI_DEVICE_ERROR Something error occurred
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+SmmClear (
|
|
|
+ VOID
|
|
|
+ )
|
|
|
+{
|
|
|
+ UINT16 ABase;
|
|
|
+ UINT32 OutputData;
|
|
|
+ UINT32 OutputPort;
|
|
|
+
|
|
|
+ ABase = FixedPcdGet16 (PcdAcpiBaseAddress);
|
|
|
+
|
|
|
+ ///
|
|
|
+ /// Clear the Power Button Override Status Bit, it gates EOS from being set.
|
|
|
+ ///
|
|
|
+ OutputPort = ABase + R_PCH_ACPI_PM1_STS;
|
|
|
+ OutputData = B_PCH_ACPI_PM1_STS_PRBTNOR;
|
|
|
+ DEBUG (
|
|
|
+ (DEBUG_EVENT,
|
|
|
+ "The PM1 Status Port at address %x will be written to %x.\n",
|
|
|
+ OutputPort,
|
|
|
+ OutputData)
|
|
|
+ );
|
|
|
+ IoWrite16 (
|
|
|
+ (UINTN) OutputPort,
|
|
|
+ (UINT16) (OutputData)
|
|
|
+ );
|
|
|
+
|
|
|
+ ///
|
|
|
+ /// Clear the APM SMI Status Bit
|
|
|
+ ///
|
|
|
+ OutputPort = ABase + R_PCH_SMI_STS;
|
|
|
+ OutputData = B_PCH_SMI_STS_APM;
|
|
|
+ DEBUG (
|
|
|
+ (DEBUG_EVENT,
|
|
|
+ "The SMI Status Port at address %x will be written to %x.\n",
|
|
|
+ OutputPort,
|
|
|
+ OutputData)
|
|
|
+ );
|
|
|
+ IoWrite32 (
|
|
|
+ (UINTN) OutputPort,
|
|
|
+ (UINT32) (OutputData)
|
|
|
+ );
|
|
|
+
|
|
|
+ ///
|
|
|
+ /// Set the EOS Bit
|
|
|
+ ///
|
|
|
+ OutputPort = ABase + R_PCH_SMI_EN;
|
|
|
+ OutputData = IoRead32 ((UINTN) OutputPort);
|
|
|
+ OutputData |= B_PCH_SMI_EN_EOS;
|
|
|
+ DEBUG (
|
|
|
+ (DEBUG_EVENT,
|
|
|
+ "The SMI Control Port at address %x will be written to %x.\n",
|
|
|
+ OutputPort,
|
|
|
+ OutputData)
|
|
|
+ );
|
|
|
+ IoWrite32 (
|
|
|
+ (UINTN) OutputPort,
|
|
|
+ (UINT32) (OutputData)
|
|
|
+ );
|
|
|
+
|
|
|
+ ///
|
|
|
+ /// There is no need to read EOS back and check if it is set.
|
|
|
+ /// This can lead to a reading of zero if an SMI occurs right after the SMI_EN port read
|
|
|
+ /// but before the data is returned to the CPU.
|
|
|
+ /// SMM Dispatcher should make sure that EOS is set after all SMI sources are processed.
|
|
|
+ ///
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ This routine generates an SMI
|
|
|
+
|
|
|
+ @param[in] This The EFI SMM Control protocol instance
|
|
|
+ @param[in, out] ArgumentBuffer The buffer of argument
|
|
|
+ @param[in, out] ArgumentBufferSize The size of the argument buffer
|
|
|
+ @param[in] Periodic Periodic or not
|
|
|
+ @param[in] ActivationInterval Interval of periodic SMI
|
|
|
+
|
|
|
+ @retval EFI Status Describing the result of the operation
|
|
|
+ @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+Activate (
|
|
|
+ IN EFI_PEI_SERVICES **PeiServices,
|
|
|
+ IN EFI_PEI_MM_CONTROL_PPI * This,
|
|
|
+ IN OUT INT8 *ArgumentBuffer OPTIONAL,
|
|
|
+ IN OUT UINTN *ArgumentBufferSize OPTIONAL,
|
|
|
+ IN BOOLEAN Periodic OPTIONAL,
|
|
|
+ IN UINTN ActivationInterval OPTIONAL
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+ UINT8 Data;
|
|
|
+
|
|
|
+ if (Periodic) {
|
|
|
+ DEBUG ((DEBUG_WARN, "Invalid parameter\n"));
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+ }
|
|
|
+
|
|
|
+ // NOTE: Copied from Quark. Matches the usage in PiSmmCommunicationPei
|
|
|
+ if (ArgumentBuffer == NULL) {
|
|
|
+ Data = 0xFF;
|
|
|
+ } else {
|
|
|
+ if (ArgumentBufferSize == NULL || *ArgumentBufferSize != 1) {
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+ }
|
|
|
+
|
|
|
+ Data = *ArgumentBuffer;
|
|
|
+ }
|
|
|
+ ///
|
|
|
+ /// Clear any pending the APM SMI
|
|
|
+ ///
|
|
|
+ Status = SmmClear ();
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ return Status;
|
|
|
+ }
|
|
|
+
|
|
|
+ return SmmTrigger (Data);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ This routine clears an SMI
|
|
|
+
|
|
|
+ @param[in] This The EFI SMM Control protocol instance
|
|
|
+ @param[in] Periodic Periodic or not
|
|
|
+
|
|
|
+ @retval EFI Status Describing the result of the operation
|
|
|
+ @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+Deactivate (
|
|
|
+ IN EFI_PEI_SERVICES **PeiServices,
|
|
|
+ IN EFI_PEI_MM_CONTROL_PPI * This,
|
|
|
+ IN BOOLEAN Periodic OPTIONAL
|
|
|
+ )
|
|
|
+{
|
|
|
+ if (Periodic) {
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+ }
|
|
|
+
|
|
|
+ return SmmClear ();
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ This function is to install an SMM Control PPI
|
|
|
+ - <b>Introduction</b> \n
|
|
|
+ An API to install an instance of EFI_PEI_MM_CONTROL_PPI. This PPI provides a standard
|
|
|
+ way for other modules to trigger software SMIs.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS - Ppi successfully started and installed.
|
|
|
+ @retval EFI_NOT_FOUND - Ppi can't be found.
|
|
|
+ @retval EFI_OUT_OF_RESOURCES - Ppi does not have enough resources to initialize the driver.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+PeiInstallSmmControlPpi (
|
|
|
+ VOID
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+ EFI_PEI_PPI_DESCRIPTOR *PpiList;
|
|
|
+ SMM_CONTROL_PRIVATE_DATA *SmmControlPrivate;
|
|
|
+
|
|
|
+ //
|
|
|
+ // Initialize private data
|
|
|
+ //
|
|
|
+ SmmControlPrivate = AllocateZeroPool (sizeof (*SmmControlPrivate));
|
|
|
+ ASSERT (SmmControlPrivate != NULL);
|
|
|
+ if (SmmControlPrivate == NULL) {
|
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
|
+ }
|
|
|
+ PpiList = AllocateZeroPool (sizeof (*PpiList));
|
|
|
+ ASSERT (PpiList != NULL);
|
|
|
+ if (PpiList == NULL) {
|
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
|
+ }
|
|
|
+
|
|
|
+ SmmControlPrivate->Signature = SMM_CONTROL_PRIVATE_DATA_SIGNATURE;
|
|
|
+ SmmControlPrivate->Handle = NULL;
|
|
|
+
|
|
|
+ SmmControlPrivate->SmmControl.Trigger = Activate;
|
|
|
+ SmmControlPrivate->SmmControl.Clear = Deactivate;
|
|
|
+
|
|
|
+ //
|
|
|
+ // Install PPI
|
|
|
+ //
|
|
|
+ PpiList->Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
|
|
|
+ PpiList->Guid = &gEfiPeiMmControlPpiGuid;
|
|
|
+ PpiList->Ppi = &SmmControlPrivate->SmmControl;
|
|
|
+
|
|
|
+ Status = PeiServicesInstallPpi (PpiList);
|
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
|
+
|
|
|
+ // Unlike driver, do not disable SMIs as S3 resume continues
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|