2 This module produces the SMM Control2 Protocol
4 Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Protocol/SmmControl2.h>
11 #include <Library/DebugLib.h>
12 #include <Library/UefiBootServicesTableLib.h>
13 #include <Library/IoLib.h>
14 #include <Library/HobLib.h>
15 #include <Library/UefiRuntimeLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Guid/SmmRegisterInfoGuid.h>
19 #define SMM_DATA_PORT 0xB3
20 #define SMM_CONTROL_PORT 0xB2
28 SMM_CONTROL2_REG mSmiCtrlReg
;
31 Invokes SMI activation from either the preboot or runtime environment.
33 This function generates an SMI.
35 @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
36 @param[in,out] CommandPort The value written to the command port.
37 @param[in,out] DataPort The value written to the data port.
38 @param[in] Periodic Optional mechanism to engender a periodic stream.
39 @param[in] ActivationInterval Optional parameter to repeat at this period one
40 time or, if the Periodic Boolean is set, periodically.
42 @retval EFI_SUCCESS The SMI has been engendered.
43 @retval EFI_DEVICE_ERROR The timing is unsupported.
44 @retval EFI_INVALID_PARAMETER The activation period is unsupported.
45 @retval EFI_INVALID_PARAMETER The last periodic activation has not been cleared.
46 @retval EFI_NOT_STARTED The MM base service has not been initialized.
51 IN CONST EFI_SMM_CONTROL2_PROTOCOL
*This
,
52 IN OUT UINT8
*CommandPort OPTIONAL
,
53 IN OUT UINT8
*DataPort OPTIONAL
,
54 IN BOOLEAN Periodic OPTIONAL
,
55 IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
62 return EFI_INVALID_PARAMETER
;
65 SmiEn
= IoRead32 (mSmiCtrlReg
.Address
);
66 SmiEnableBits
= (1 << mSmiCtrlReg
.GblBitOffset
) | (1 << mSmiCtrlReg
.ApmBitOffset
);
67 if ((SmiEn
& SmiEnableBits
) != SmiEnableBits
) {
69 // Set the "global SMI enable" bit and APM bit
71 IoWrite32 (mSmiCtrlReg
.Address
, SmiEn
| SmiEnableBits
);
74 IoWrite8 (SMM_DATA_PORT
, DataPort
== NULL
? 0 : *DataPort
);
75 IoWrite8 (SMM_CONTROL_PORT
, CommandPort
== NULL
? 0 : *CommandPort
);
82 @param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL
83 @param Periodic TRUE to indicate a periodical SMI
85 @return Return value from SmmClear ()
91 IN CONST EFI_SMM_CONTROL2_PROTOCOL
*This
,
96 return EFI_INVALID_PARAMETER
;
100 // Temporarily do nothing here
106 /// SMM COntrol2 Protocol instance
108 EFI_SMM_CONTROL2_PROTOCOL mSmmControl2
= {
115 Get specified SMI register based on given register ID
117 @param[in] SmmRegister SMI related register array from bootloader
118 @param[in] Id The register ID to get.
120 @retval NULL The register is not found or the format is not expected.
124 PLD_GENERIC_REGISTER
*
126 IN PLD_SMM_REGISTERS
*SmmRegister
,
131 PLD_GENERIC_REGISTER
*PldReg
;
134 for (Index
= 0; Index
< SmmRegister
->Count
; Index
++) {
135 if (SmmRegister
->Registers
[Index
].Id
== Id
) {
136 PldReg
= &SmmRegister
->Registers
[Index
];
141 if (PldReg
== NULL
) {
142 DEBUG ((DEBUG_INFO
, "Register %d not found.\n", Id
));
147 // Checking the register if it is expected.
149 if ((PldReg
->Address
.AccessSize
!= EFI_ACPI_3_0_DWORD
) ||
150 (PldReg
->Address
.Address
== 0) ||
151 (PldReg
->Address
.RegisterBitWidth
!= 1) ||
152 (PldReg
->Address
.AddressSpaceId
!= EFI_ACPI_3_0_SYSTEM_IO
) ||
153 (PldReg
->Value
!= 1)) {
154 DEBUG ((DEBUG_INFO
, "Unexpected SMM register.\n"));
155 DEBUG ((DEBUG_INFO
, "AddressSpaceId= 0x%x\n", PldReg
->Address
.AddressSpaceId
));
156 DEBUG ((DEBUG_INFO
, "RegBitWidth = 0x%x\n", PldReg
->Address
.RegisterBitWidth
));
157 DEBUG ((DEBUG_INFO
, "RegBitOffset = 0x%x\n", PldReg
->Address
.RegisterBitOffset
));
158 DEBUG ((DEBUG_INFO
, "AccessSize = 0x%x\n", PldReg
->Address
.AccessSize
));
159 DEBUG ((DEBUG_INFO
, "Address = 0x%lx\n",PldReg
->Address
.Address
));
167 Fixup data pointers so that the services can be called in virtual mode.
169 @param[in] Event The event registered.
170 @param[in] Context Event context.
175 SmmControlVirtualAddressChangeEvent (
180 EfiConvertPointer (0x0, (VOID
**) &(mSmmControl2
.Trigger
));
181 EfiConvertPointer (0x0, (VOID
**) &(mSmmControl2
.Clear
));
186 This function installs EFI_SMM_CONTROL2_PROTOCOL.
188 @param ImageHandle Handle for the image of this driver
189 @param SystemTable Pointer to the EFI System Table
191 @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
192 @return The status returned from InstallProtocolInterface().
197 SmmControlEntryPoint (
198 IN EFI_HANDLE ImageHandle
,
199 IN EFI_SYSTEM_TABLE
*SystemTable
203 EFI_HOB_GUID_TYPE
*GuidHob
;
204 PLD_SMM_REGISTERS
*SmmRegister
;
205 PLD_GENERIC_REGISTER
*SmiGblEnReg
;
206 PLD_GENERIC_REGISTER
*SmiApmEnReg
;
209 GuidHob
= GetFirstGuidHob (&gSmmRegisterInfoGuid
);
210 if (GuidHob
== NULL
) {
211 return EFI_UNSUPPORTED
;
214 SmmRegister
= (PLD_SMM_REGISTERS
*) (GET_GUID_HOB_DATA(GuidHob
));
215 SmiGblEnReg
= GetSmmCtrlRegById (SmmRegister
, REGISTER_ID_SMI_GBL_EN
);
216 if (SmiGblEnReg
== NULL
) {
217 DEBUG ((DEBUG_ERROR
, "SMI global enable reg not found.\n"));
218 return EFI_NOT_FOUND
;
220 mSmiCtrlReg
.Address
= (UINT32
)SmiGblEnReg
->Address
.Address
;
221 mSmiCtrlReg
.GblBitOffset
= SmiGblEnReg
->Address
.RegisterBitOffset
;
223 SmiApmEnReg
= GetSmmCtrlRegById (SmmRegister
, REGISTER_ID_SMI_APM_EN
);
224 if (SmiApmEnReg
== NULL
) {
225 DEBUG ((DEBUG_ERROR
, "SMI APM enable reg not found.\n"));
226 return EFI_NOT_FOUND
;
229 if (SmiApmEnReg
->Address
.Address
!= mSmiCtrlReg
.Address
) {
230 DEBUG ((DEBUG_ERROR
, "SMI APM EN and SMI GBL EN are expected to have same register base\n"));
231 DEBUG ((DEBUG_ERROR
, "APM:0x%x, GBL:0x%x\n", SmiApmEnReg
->Address
.Address
, mSmiCtrlReg
.Address
));
232 return EFI_UNSUPPORTED
;
234 mSmiCtrlReg
.ApmBitOffset
= SmiApmEnReg
->Address
.RegisterBitOffset
;
237 // Install our protocol interfaces on the device's handle
239 Status
= gBS
->InstallMultipleProtocolInterfaces (
241 &gEfiSmmControl2ProtocolGuid
,
245 ASSERT_EFI_ERROR (Status
);
247 Status
= gBS
->CreateEventEx (
250 SmmControlVirtualAddressChangeEvent
,
252 &gEfiEventVirtualAddressChangeGuid
,