SmmControlRuntimeDxe.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /** @file
  2. This module produces the SMM Control2 Protocol
  3. Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <PiDxe.h>
  7. #include <Protocol/SmmControl2.h>
  8. #include <Library/DebugLib.h>
  9. #include <Library/UefiBootServicesTableLib.h>
  10. #include <Library/IoLib.h>
  11. #include <Library/HobLib.h>
  12. #include <Library/UefiRuntimeLib.h>
  13. #include <Library/BaseMemoryLib.h>
  14. #include <Guid/SmmRegisterInfoGuid.h>
  15. #define SMM_DATA_PORT 0xB3
  16. #define SMM_CONTROL_PORT 0xB2
  17. typedef struct {
  18. UINT8 GblBitOffset;
  19. UINT8 ApmBitOffset;
  20. UINT32 Address;
  21. } SMM_CONTROL2_REG;
  22. SMM_CONTROL2_REG mSmiCtrlReg;
  23. /**
  24. Invokes SMI activation from either the preboot or runtime environment.
  25. This function generates an SMI.
  26. @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
  27. @param[in,out] CommandPort The value written to the command port.
  28. @param[in,out] DataPort The value written to the data port.
  29. @param[in] Periodic Optional mechanism to engender a periodic stream.
  30. @param[in] ActivationInterval Optional parameter to repeat at this period one
  31. time or, if the Periodic Boolean is set, periodically.
  32. @retval EFI_SUCCESS The SMI has been engendered.
  33. @retval EFI_DEVICE_ERROR The timing is unsupported.
  34. @retval EFI_INVALID_PARAMETER The activation period is unsupported.
  35. @retval EFI_INVALID_PARAMETER The last periodic activation has not been cleared.
  36. @retval EFI_NOT_STARTED The MM base service has not been initialized.
  37. **/
  38. EFI_STATUS
  39. EFIAPI
  40. Activate (
  41. IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
  42. IN OUT UINT8 *CommandPort OPTIONAL,
  43. IN OUT UINT8 *DataPort OPTIONAL,
  44. IN BOOLEAN Periodic OPTIONAL,
  45. IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
  46. )
  47. {
  48. UINT32 SmiEn;
  49. UINT32 SmiEnableBits;
  50. if (Periodic) {
  51. return EFI_INVALID_PARAMETER;
  52. }
  53. SmiEn = IoRead32 (mSmiCtrlReg.Address);
  54. SmiEnableBits = (1 << mSmiCtrlReg.GblBitOffset) | (1 << mSmiCtrlReg.ApmBitOffset);
  55. if ((SmiEn & SmiEnableBits) != SmiEnableBits) {
  56. //
  57. // Set the "global SMI enable" bit and APM bit
  58. //
  59. IoWrite32 (mSmiCtrlReg.Address, SmiEn | SmiEnableBits);
  60. }
  61. IoWrite8 (SMM_DATA_PORT, DataPort == NULL ? 0 : *DataPort);
  62. IoWrite8 (SMM_CONTROL_PORT, CommandPort == NULL ? 0 : *CommandPort);
  63. return EFI_SUCCESS;
  64. }
  65. /**
  66. Clears an SMI.
  67. @param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL
  68. @param Periodic TRUE to indicate a periodical SMI
  69. @return Return value from SmmClear ()
  70. **/
  71. EFI_STATUS
  72. EFIAPI
  73. Deactivate (
  74. IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
  75. IN BOOLEAN Periodic
  76. )
  77. {
  78. if (Periodic) {
  79. return EFI_INVALID_PARAMETER;
  80. }
  81. //
  82. // Temporarily do nothing here
  83. //
  84. return EFI_SUCCESS;
  85. }
  86. ///
  87. /// SMM COntrol2 Protocol instance
  88. ///
  89. EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {
  90. Activate,
  91. Deactivate,
  92. 0
  93. };
  94. /**
  95. Get specified SMI register based on given register ID
  96. @param[in] SmmRegister SMI related register array from bootloader
  97. @param[in] Id The register ID to get.
  98. @retval NULL The register is not found or the format is not expected.
  99. @return smi register
  100. **/
  101. PLD_GENERIC_REGISTER *
  102. GetSmmCtrlRegById (
  103. IN PLD_SMM_REGISTERS *SmmRegister,
  104. IN UINT32 Id
  105. )
  106. {
  107. UINT32 Index;
  108. PLD_GENERIC_REGISTER *PldReg;
  109. PldReg = NULL;
  110. for (Index = 0; Index < SmmRegister->Count; Index++) {
  111. if (SmmRegister->Registers[Index].Id == Id) {
  112. PldReg = &SmmRegister->Registers[Index];
  113. break;
  114. }
  115. }
  116. if (PldReg == NULL) {
  117. DEBUG ((DEBUG_INFO, "Register %d not found.\n", Id));
  118. return NULL;
  119. }
  120. //
  121. // Checking the register if it is expected.
  122. //
  123. if ((PldReg->Address.AccessSize != EFI_ACPI_3_0_DWORD) ||
  124. (PldReg->Address.Address == 0) ||
  125. (PldReg->Address.RegisterBitWidth != 1) ||
  126. (PldReg->Address.AddressSpaceId != EFI_ACPI_3_0_SYSTEM_IO) ||
  127. (PldReg->Value != 1))
  128. {
  129. DEBUG ((DEBUG_INFO, "Unexpected SMM register.\n"));
  130. DEBUG ((DEBUG_INFO, "AddressSpaceId= 0x%x\n", PldReg->Address.AddressSpaceId));
  131. DEBUG ((DEBUG_INFO, "RegBitWidth = 0x%x\n", PldReg->Address.RegisterBitWidth));
  132. DEBUG ((DEBUG_INFO, "RegBitOffset = 0x%x\n", PldReg->Address.RegisterBitOffset));
  133. DEBUG ((DEBUG_INFO, "AccessSize = 0x%x\n", PldReg->Address.AccessSize));
  134. DEBUG ((DEBUG_INFO, "Address = 0x%lx\n", PldReg->Address.Address));
  135. return NULL;
  136. }
  137. return PldReg;
  138. }
  139. /**
  140. Fixup data pointers so that the services can be called in virtual mode.
  141. @param[in] Event The event registered.
  142. @param[in] Context Event context.
  143. **/
  144. VOID
  145. EFIAPI
  146. SmmControlVirtualAddressChangeEvent (
  147. IN EFI_EVENT Event,
  148. IN VOID *Context
  149. )
  150. {
  151. EfiConvertPointer (0x0, (VOID **)&(mSmmControl2.Trigger));
  152. EfiConvertPointer (0x0, (VOID **)&(mSmmControl2.Clear));
  153. }
  154. /**
  155. This function installs EFI_SMM_CONTROL2_PROTOCOL.
  156. @param ImageHandle Handle for the image of this driver
  157. @param SystemTable Pointer to the EFI System Table
  158. @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
  159. @return The status returned from InstallProtocolInterface().
  160. **/
  161. EFI_STATUS
  162. EFIAPI
  163. SmmControlEntryPoint (
  164. IN EFI_HANDLE ImageHandle,
  165. IN EFI_SYSTEM_TABLE *SystemTable
  166. )
  167. {
  168. EFI_STATUS Status;
  169. EFI_HOB_GUID_TYPE *GuidHob;
  170. PLD_SMM_REGISTERS *SmmRegister;
  171. PLD_GENERIC_REGISTER *SmiGblEnReg;
  172. PLD_GENERIC_REGISTER *SmiApmEnReg;
  173. EFI_EVENT Event;
  174. GuidHob = GetFirstGuidHob (&gSmmRegisterInfoGuid);
  175. if (GuidHob == NULL) {
  176. return EFI_UNSUPPORTED;
  177. }
  178. SmmRegister = (PLD_SMM_REGISTERS *)(GET_GUID_HOB_DATA (GuidHob));
  179. SmiGblEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_GBL_EN);
  180. if (SmiGblEnReg == NULL) {
  181. DEBUG ((DEBUG_ERROR, "SMI global enable reg not found.\n"));
  182. return EFI_NOT_FOUND;
  183. }
  184. mSmiCtrlReg.Address = (UINT32)SmiGblEnReg->Address.Address;
  185. mSmiCtrlReg.GblBitOffset = SmiGblEnReg->Address.RegisterBitOffset;
  186. SmiApmEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_APM_EN);
  187. if (SmiApmEnReg == NULL) {
  188. DEBUG ((DEBUG_ERROR, "SMI APM enable reg not found.\n"));
  189. return EFI_NOT_FOUND;
  190. }
  191. if (SmiApmEnReg->Address.Address != mSmiCtrlReg.Address) {
  192. DEBUG ((DEBUG_ERROR, "SMI APM EN and SMI GBL EN are expected to have same register base\n"));
  193. DEBUG ((DEBUG_ERROR, "APM:0x%x, GBL:0x%x\n", SmiApmEnReg->Address.Address, mSmiCtrlReg.Address));
  194. return EFI_UNSUPPORTED;
  195. }
  196. mSmiCtrlReg.ApmBitOffset = SmiApmEnReg->Address.RegisterBitOffset;
  197. //
  198. // Install our protocol interfaces on the device's handle
  199. //
  200. Status = gBS->InstallMultipleProtocolInterfaces (
  201. &ImageHandle,
  202. &gEfiSmmControl2ProtocolGuid,
  203. &mSmmControl2,
  204. NULL
  205. );
  206. ASSERT_EFI_ERROR (Status);
  207. Status = gBS->CreateEventEx (
  208. EVT_NOTIFY_SIGNAL,
  209. TPL_NOTIFY,
  210. SmmControlVirtualAddressChangeEvent,
  211. NULL,
  212. &gEfiEventVirtualAddressChangeGuid,
  213. &Event
  214. );
  215. return Status;
  216. }