123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- /** @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;
- }
|