mirror of https://github.com/acidanthera/audk.git
UefiPayloadPkg: Add a common SMM control Runtime DXE module
This module consumes SMM Registers HOB (SMI_GBL_EN and SMI_APM_EN) to install SMM control 2 protocol gEfiSmmControl2ProtocolGuid. The protocol activate() would set SMI_GBL_EN and SMI_APM_EN and trigger SMI by writing to IO port 0xB3 and 0xB2. Signed-off-by: Guo Dong <guo.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Maurice Ma <maurice.ma@intel.com> Cc: Benjamin You <benjamin.you@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Reviewed-by: Benjamin You <benjamin.you@intel.com>
This commit is contained in:
parent
87a34ca0cf
commit
e7e8ea27d4
|
@ -0,0 +1,48 @@
|
|||
/** @file
|
||||
This file defines the SMM info hob structure.
|
||||
|
||||
Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef PAYLOAD_SMM_REGISTER_INFO_GUID_H_
|
||||
#define PAYLOAD_SMM_REGISTER_INFO_GUID_H_
|
||||
|
||||
#include <IndustryStandard/Acpi.h>
|
||||
|
||||
///
|
||||
/// SMM Information GUID
|
||||
///
|
||||
extern EFI_GUID gSmmRegisterInfoGuid;
|
||||
|
||||
///
|
||||
/// Reuse ACPI definition
|
||||
/// AddressSpaceId(0xC0-0xFF) is defined by OEM for MSR and other spaces
|
||||
///
|
||||
typedef EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE PLD_GENERIC_ADDRESS;
|
||||
|
||||
#define REGISTER_ID_SMI_GBL_EN 1
|
||||
#define REGISTER_ID_SMI_GBL_EN_LOCK 2
|
||||
#define REGISTER_ID_SMI_EOS 3
|
||||
#define REGISTER_ID_SMI_APM_EN 4
|
||||
#define REGISTER_ID_SMI_APM_STS 5
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
UINT64 Id;
|
||||
UINT64 Value;
|
||||
PLD_GENERIC_ADDRESS Address;
|
||||
} PLD_GENERIC_REGISTER;
|
||||
|
||||
typedef struct {
|
||||
UINT16 Revision;
|
||||
UINT16 Reserved;
|
||||
UINT32 Count;
|
||||
PLD_GENERIC_REGISTER Registers[0];
|
||||
} PLD_SMM_REGISTERS;
|
||||
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
|
@ -0,0 +1,256 @@
|
|||
/** @file
|
||||
This module produces the SMM Control2 Protocol
|
||||
|
||||
Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
#include <Protocol/SmmControl2.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/IoLib.h>
|
||||
#include <Library/HobLib.h>
|
||||
#include <Library/UefiRuntimeLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Guid/SmmRegisterInfoGuid.h>
|
||||
|
||||
#define SMM_DATA_PORT 0xB3
|
||||
#define SMM_CONTROL_PORT 0xB2
|
||||
|
||||
typedef struct {
|
||||
UINT8 GblBitOffset;
|
||||
UINT8 ApmBitOffset;
|
||||
UINT32 Address;
|
||||
} SMM_CONTROL2_REG;
|
||||
|
||||
SMM_CONTROL2_REG mSmiCtrlReg;
|
||||
|
||||
/**
|
||||
Invokes SMI activation from either the preboot or runtime environment.
|
||||
|
||||
This function generates an SMI.
|
||||
|
||||
@param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
|
||||
@param[in,out] CommandPort The value written to the command port.
|
||||
@param[in,out] DataPort The value written to the data port.
|
||||
@param[in] Periodic Optional mechanism to engender a periodic stream.
|
||||
@param[in] ActivationInterval Optional parameter to repeat at this period one
|
||||
time or, if the Periodic Boolean is set, periodically.
|
||||
|
||||
@retval EFI_SUCCESS The SMI has been engendered.
|
||||
@retval EFI_DEVICE_ERROR The timing is unsupported.
|
||||
@retval EFI_INVALID_PARAMETER The activation period is unsupported.
|
||||
@retval EFI_INVALID_PARAMETER The last periodic activation has not been cleared.
|
||||
@retval EFI_NOT_STARTED The MM base service has not been initialized.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Activate (
|
||||
IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
|
||||
IN OUT UINT8 *CommandPort OPTIONAL,
|
||||
IN OUT UINT8 *DataPort OPTIONAL,
|
||||
IN BOOLEAN Periodic OPTIONAL,
|
||||
IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
|
||||
)
|
||||
{
|
||||
UINT32 SmiEn;
|
||||
UINT32 SmiEnableBits;
|
||||
|
||||
if (Periodic) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
SmiEn = IoRead32 (mSmiCtrlReg.Address);
|
||||
SmiEnableBits = (1 << mSmiCtrlReg.GblBitOffset) | (1 << mSmiCtrlReg.ApmBitOffset);
|
||||
if ((SmiEn & SmiEnableBits) != SmiEnableBits) {
|
||||
//
|
||||
// Set the "global SMI enable" bit and APM bit
|
||||
//
|
||||
IoWrite32 (mSmiCtrlReg.Address, SmiEn | SmiEnableBits);
|
||||
}
|
||||
|
||||
IoWrite8 (SMM_DATA_PORT, DataPort == NULL ? 0 : *DataPort);
|
||||
IoWrite8 (SMM_CONTROL_PORT, CommandPort == NULL ? 0 : *CommandPort);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Clears an SMI.
|
||||
|
||||
@param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL
|
||||
@param Periodic TRUE to indicate a periodical SMI
|
||||
|
||||
@return Return value from SmmClear ()
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Deactivate (
|
||||
IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
|
||||
IN BOOLEAN Periodic
|
||||
)
|
||||
{
|
||||
if (Periodic) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Temporarily do nothing here
|
||||
//
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
///
|
||||
/// SMM COntrol2 Protocol instance
|
||||
///
|
||||
EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {
|
||||
Activate,
|
||||
Deactivate,
|
||||
0
|
||||
};
|
||||
|
||||
/**
|
||||
Get specified SMI register based on given register ID
|
||||
|
||||
@param[in] SmmRegister SMI related register array from bootloader
|
||||
@param[in] Id The register ID to get.
|
||||
|
||||
@retval NULL The register is not found or the format is not expected.
|
||||
@return smi register
|
||||
|
||||
**/
|
||||
PLD_GENERIC_REGISTER *
|
||||
GetSmmCtrlRegById (
|
||||
IN PLD_SMM_REGISTERS *SmmRegister,
|
||||
IN UINT32 Id
|
||||
)
|
||||
{
|
||||
UINT32 Index;
|
||||
PLD_GENERIC_REGISTER *PldReg;
|
||||
|
||||
PldReg = NULL;
|
||||
for (Index = 0; Index < SmmRegister->Count; Index++) {
|
||||
if (SmmRegister->Registers[Index].Id == Id) {
|
||||
PldReg = &SmmRegister->Registers[Index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (PldReg == NULL) {
|
||||
DEBUG ((DEBUG_INFO, "Register %d not found.\n", Id));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Checking the register if it is expected.
|
||||
//
|
||||
if ((PldReg->Address.AccessSize != EFI_ACPI_3_0_DWORD) ||
|
||||
(PldReg->Address.Address == 0) ||
|
||||
(PldReg->Address.RegisterBitWidth != 1) ||
|
||||
(PldReg->Address.AddressSpaceId != EFI_ACPI_3_0_SYSTEM_IO) ||
|
||||
(PldReg->Value != 1)) {
|
||||
DEBUG ((DEBUG_INFO, "Unexpected SMM register.\n"));
|
||||
DEBUG ((DEBUG_INFO, "AddressSpaceId= 0x%x\n", PldReg->Address.AddressSpaceId));
|
||||
DEBUG ((DEBUG_INFO, "RegBitWidth = 0x%x\n", PldReg->Address.RegisterBitWidth));
|
||||
DEBUG ((DEBUG_INFO, "RegBitOffset = 0x%x\n", PldReg->Address.RegisterBitOffset));
|
||||
DEBUG ((DEBUG_INFO, "AccessSize = 0x%x\n", PldReg->Address.AccessSize));
|
||||
DEBUG ((DEBUG_INFO, "Address = 0x%lx\n",PldReg->Address.Address ));
|
||||
return NULL;
|
||||
}
|
||||
return PldReg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Fixup data pointers so that the services can be called in virtual mode.
|
||||
|
||||
@param[in] Event The event registered.
|
||||
@param[in] Context Event context.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
SmmControlVirtualAddressChangeEvent (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
EfiConvertPointer (0x0, (VOID **) &(mSmmControl2.Trigger));
|
||||
EfiConvertPointer (0x0, (VOID **) &(mSmmControl2.Clear));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This function installs EFI_SMM_CONTROL2_PROTOCOL.
|
||||
|
||||
@param ImageHandle Handle for the image of this driver
|
||||
@param SystemTable Pointer to the EFI System Table
|
||||
|
||||
@retval EFI_UNSUPPORTED There's no Intel ICH on this platform
|
||||
@return The status returned from InstallProtocolInterface().
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmControlEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HOB_GUID_TYPE *GuidHob;
|
||||
PLD_SMM_REGISTERS *SmmRegister;
|
||||
PLD_GENERIC_REGISTER *SmiGblEnReg;
|
||||
PLD_GENERIC_REGISTER *SmiApmEnReg;
|
||||
EFI_EVENT Event;
|
||||
|
||||
GuidHob = GetFirstGuidHob (&gSmmRegisterInfoGuid);
|
||||
if (GuidHob == NULL) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
SmmRegister = (PLD_SMM_REGISTERS *) (GET_GUID_HOB_DATA(GuidHob));
|
||||
SmiGblEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_GBL_EN);
|
||||
if (SmiGblEnReg == NULL) {
|
||||
DEBUG ((DEBUG_ERROR, "SMI global enable reg not found.\n"));
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
mSmiCtrlReg.Address = (UINT32)SmiGblEnReg->Address.Address;
|
||||
mSmiCtrlReg.GblBitOffset = SmiGblEnReg->Address.RegisterBitOffset;
|
||||
|
||||
SmiApmEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_APM_EN);
|
||||
if (SmiApmEnReg == NULL) {
|
||||
DEBUG ((DEBUG_ERROR, "SMI APM enable reg not found.\n"));
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (SmiApmEnReg->Address.Address != mSmiCtrlReg.Address) {
|
||||
DEBUG ((DEBUG_ERROR, "SMI APM EN and SMI GBL EN are expected to have same register base\n"));
|
||||
DEBUG ((DEBUG_ERROR, "APM:0x%x, GBL:0x%x\n", SmiApmEnReg->Address.Address, mSmiCtrlReg.Address));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
mSmiCtrlReg.ApmBitOffset = SmiApmEnReg->Address.RegisterBitOffset;
|
||||
|
||||
//
|
||||
// Install our protocol interfaces on the device's handle
|
||||
//
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&ImageHandle,
|
||||
&gEfiSmmControl2ProtocolGuid,
|
||||
&mSmmControl2,
|
||||
NULL
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Status = gBS->CreateEventEx (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_NOTIFY,
|
||||
SmmControlVirtualAddressChangeEvent,
|
||||
NULL,
|
||||
&gEfiEventVirtualAddressChangeGuid,
|
||||
&Event
|
||||
);
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
## @file
|
||||
# SMM Control runtime DXE Module
|
||||
#
|
||||
# Provides the ability to generate a software SMI.
|
||||
#
|
||||
# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = SmmControlRuntimeDxe
|
||||
FILE_GUID = C3099578-F815-4a96-84A3-FC593760181D
|
||||
MODULE_TYPE = DXE_RUNTIME_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = SmmControlEntryPoint
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
SmmControlRuntimeDxe.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
UefiPayloadPkg/UefiPayloadPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
UefiDriverEntryPoint
|
||||
DebugLib
|
||||
UefiBootServicesTableLib
|
||||
UefiRuntimeLib
|
||||
PcdLib
|
||||
IoLib
|
||||
HobLib
|
||||
|
||||
[Guids]
|
||||
gSmmRegisterInfoGuid
|
||||
gEfiEventVirtualAddressChangeGuid
|
||||
|
||||
[Protocols]
|
||||
gEfiSmmControl2ProtocolGuid ## PRODUCES
|
||||
|
||||
[Depex]
|
||||
TRUE
|
|
@ -37,6 +37,8 @@
|
|||
gUefiSerialPortInfoGuid = { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98, 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } }
|
||||
gLoaderMemoryMapInfoGuid = { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4, 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } }
|
||||
|
||||
gSmmRegisterInfoGuid = { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9, 0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } }
|
||||
|
||||
[Ppis]
|
||||
gEfiPayLoadHobBasePpiGuid = { 0xdbe23aa1, 0xa342, 0x4b97, {0x85, 0xb6, 0xb2, 0x26, 0xf1, 0x61, 0x73, 0x89} }
|
||||
|
||||
|
|
Loading…
Reference in New Issue