PiSmmCommunicationPei.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /** @file
  2. PiSmmCommunication PEI Driver.
  3. Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <PiPei.h>
  7. #include <PiDxe.h>
  8. #include <PiSmm.h>
  9. #include <Library/PeiServicesTablePointerLib.h>
  10. #include <Library/PeiServicesLib.h>
  11. #include <Library/BaseLib.h>
  12. #include <Library/BaseMemoryLib.h>
  13. #include <Library/HobLib.h>
  14. #include <Library/DebugLib.h>
  15. #include <Protocol/SmmCommunication.h>
  16. #include <Ppi/SmmCommunication.h>
  17. #include <Ppi/SmmAccess.h>
  18. #include <Ppi/SmmControl.h>
  19. #include <Guid/AcpiS3Context.h>
  20. #include "PiSmmCommunicationPrivate.h"
  21. /**
  22. the whole picture is below:
  23. +----------------------------------+
  24. | ACPI_VARIABLE_HOB |
  25. | SmramDescriptor | <- DRAM
  26. | CpuStart |---
  27. +----------------------------------+ |
  28. |
  29. +----------------------------------+<--
  30. | SMM_S3_RESUME_STATE |
  31. | Signature | <- SMRAM
  32. | Smst |---
  33. +----------------------------------+ |
  34. |
  35. +----------------------------------+<--
  36. | EFI_SMM_SYSTEM_TABLE2 |
  37. | NumberOfTableEntries | <- SMRAM
  38. | SmmConfigurationTable |---
  39. +----------------------------------+ |
  40. |
  41. +----------------------------------+<--
  42. | EFI_SMM_COMMUNICATION_CONTEXT |
  43. | SwSmiNumber | <- SMRAM
  44. | BufferPtrAddress |---
  45. +----------------------------------+ |
  46. |
  47. +----------------------------------+<--
  48. | Communication Buffer Pointer | <- AcpiNvs
  49. +----------------------------------+---
  50. |
  51. +----------------------------------+<--
  52. | EFI_SMM_COMMUNICATE_HEADER |
  53. | HeaderGuid | <- DRAM
  54. | MessageLength |
  55. +----------------------------------+
  56. **/
  57. #if defined (MDE_CPU_IA32)
  58. typedef struct {
  59. EFI_TABLE_HEADER Hdr;
  60. UINT64 SmmFirmwareVendor;
  61. UINT64 SmmFirmwareRevision;
  62. UINT64 SmmInstallConfigurationTable;
  63. UINT64 SmmIoMemRead;
  64. UINT64 SmmIoMemWrite;
  65. UINT64 SmmIoIoRead;
  66. UINT64 SmmIoIoWrite;
  67. UINT64 SmmAllocatePool;
  68. UINT64 SmmFreePool;
  69. UINT64 SmmAllocatePages;
  70. UINT64 SmmFreePages;
  71. UINT64 SmmStartupThisAp;
  72. UINT64 CurrentlyExecutingCpu;
  73. UINT64 NumberOfCpus;
  74. UINT64 CpuSaveStateSize;
  75. UINT64 CpuSaveState;
  76. UINT64 NumberOfTableEntries;
  77. UINT64 SmmConfigurationTable;
  78. } EFI_SMM_SYSTEM_TABLE2_64;
  79. typedef struct {
  80. EFI_GUID VendorGuid;
  81. UINT64 VendorTable;
  82. } EFI_CONFIGURATION_TABLE64;
  83. #endif
  84. #if defined (MDE_CPU_X64)
  85. typedef EFI_SMM_SYSTEM_TABLE2 EFI_SMM_SYSTEM_TABLE2_64;
  86. typedef EFI_CONFIGURATION_TABLE EFI_CONFIGURATION_TABLE64;
  87. #endif
  88. /**
  89. Communicates with a registered handler.
  90. This function provides a service to send and receive messages from a registered UEFI service.
  91. @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance.
  92. @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
  93. @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
  94. being returned. Zero if the handler does not wish to reply with any data.
  95. @retval EFI_SUCCESS The message was successfully posted.
  96. @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
  97. @retval EFI_NOT_STARTED The service is NOT started.
  98. **/
  99. EFI_STATUS
  100. EFIAPI
  101. Communicate (
  102. IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This,
  103. IN OUT VOID *CommBuffer,
  104. IN OUT UINTN *CommSize
  105. );
  106. EFI_PEI_SMM_COMMUNICATION_PPI mSmmCommunicationPpi = { Communicate };
  107. EFI_PEI_PPI_DESCRIPTOR mPpiList = {
  108. (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
  109. &gEfiPeiSmmCommunicationPpiGuid,
  110. &mSmmCommunicationPpi
  111. };
  112. /**
  113. Get SMM communication context.
  114. @return SMM communication context.
  115. **/
  116. EFI_SMM_COMMUNICATION_CONTEXT *
  117. GetCommunicationContext (
  118. VOID
  119. )
  120. {
  121. EFI_HOB_GUID_TYPE *GuidHob;
  122. EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
  123. GuidHob = GetFirstGuidHob (&gEfiPeiSmmCommunicationPpiGuid);
  124. ASSERT (GuidHob != NULL);
  125. SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)GET_GUID_HOB_DATA (GuidHob);
  126. return SmmCommunicationContext;
  127. }
  128. /**
  129. Set SMM communication context.
  130. @param SmmCommunicationContext SMM communication context.
  131. **/
  132. VOID
  133. SetCommunicationContext (
  134. IN EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext
  135. )
  136. {
  137. EFI_PEI_HOB_POINTERS Hob;
  138. UINTN BufferSize;
  139. BufferSize = sizeof (*SmmCommunicationContext);
  140. Hob.Raw = BuildGuidHob (
  141. &gEfiPeiSmmCommunicationPpiGuid,
  142. BufferSize
  143. );
  144. ASSERT (Hob.Raw);
  145. CopyMem ((VOID *)Hob.Raw, SmmCommunicationContext, sizeof (*SmmCommunicationContext));
  146. }
  147. /**
  148. Get VendorTable by VendorGuid in Smst.
  149. @param Signature Signature of SMM_S3_RESUME_STATE
  150. @param Smst SMM system table
  151. @param VendorGuid vendor guid
  152. @return vendor table.
  153. **/
  154. VOID *
  155. InternalSmstGetVendorTableByGuid (
  156. IN UINT64 Signature,
  157. IN EFI_SMM_SYSTEM_TABLE2 *Smst,
  158. IN EFI_GUID *VendorGuid
  159. )
  160. {
  161. EFI_CONFIGURATION_TABLE *SmmConfigurationTable;
  162. UINTN NumberOfTableEntries;
  163. UINTN Index;
  164. EFI_SMM_SYSTEM_TABLE2_64 *Smst64;
  165. EFI_CONFIGURATION_TABLE64 *SmmConfigurationTable64;
  166. if ((sizeof (UINTN) == sizeof (UINT32)) && (Signature == SMM_S3_RESUME_SMM_64)) {
  167. //
  168. // 32 PEI + 64 DXE
  169. //
  170. Smst64 = (EFI_SMM_SYSTEM_TABLE2_64 *)Smst;
  171. DEBUG ((DEBUG_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst64->SmmConfigurationTable));
  172. DEBUG ((DEBUG_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst64->NumberOfTableEntries));
  173. SmmConfigurationTable64 = (EFI_CONFIGURATION_TABLE64 *)(UINTN)Smst64->SmmConfigurationTable;
  174. NumberOfTableEntries = (UINTN)Smst64->NumberOfTableEntries;
  175. for (Index = 0; Index < NumberOfTableEntries; Index++) {
  176. if (CompareGuid (&SmmConfigurationTable64[Index].VendorGuid, VendorGuid)) {
  177. return (VOID *)(UINTN)SmmConfigurationTable64[Index].VendorTable;
  178. }
  179. }
  180. return NULL;
  181. } else {
  182. DEBUG ((DEBUG_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst->SmmConfigurationTable));
  183. DEBUG ((DEBUG_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst->NumberOfTableEntries));
  184. SmmConfigurationTable = Smst->SmmConfigurationTable;
  185. NumberOfTableEntries = Smst->NumberOfTableEntries;
  186. for (Index = 0; Index < NumberOfTableEntries; Index++) {
  187. if (CompareGuid (&SmmConfigurationTable[Index].VendorGuid, VendorGuid)) {
  188. return (VOID *)SmmConfigurationTable[Index].VendorTable;
  189. }
  190. }
  191. return NULL;
  192. }
  193. }
  194. /**
  195. Init SMM communication context.
  196. **/
  197. VOID
  198. InitCommunicationContext (
  199. VOID
  200. )
  201. {
  202. EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
  203. SMM_S3_RESUME_STATE *SmmS3ResumeState;
  204. VOID *GuidHob;
  205. EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
  206. GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
  207. ASSERT (GuidHob != NULL);
  208. SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *)GET_GUID_HOB_DATA (GuidHob);
  209. SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
  210. DEBUG ((DEBUG_INFO, "InitCommunicationContext - SmmS3ResumeState: %x\n", SmmS3ResumeState));
  211. DEBUG ((DEBUG_INFO, "InitCommunicationContext - Smst: %x\n", SmmS3ResumeState->Smst));
  212. SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)InternalSmstGetVendorTableByGuid (
  213. SmmS3ResumeState->Signature,
  214. (EFI_SMM_SYSTEM_TABLE2 *)(UINTN)SmmS3ResumeState->Smst,
  215. &gEfiPeiSmmCommunicationPpiGuid
  216. );
  217. ASSERT (SmmCommunicationContext != NULL);
  218. SetCommunicationContext (SmmCommunicationContext);
  219. return;
  220. }
  221. /**
  222. Communicates with a registered handler.
  223. This function provides a service to send and receive messages from a registered UEFI service.
  224. @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance.
  225. @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
  226. @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
  227. being returned. Zero if the handler does not wish to reply with any data.
  228. @retval EFI_SUCCESS The message was successfully posted.
  229. @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
  230. @retval EFI_NOT_STARTED The service is NOT started.
  231. **/
  232. EFI_STATUS
  233. EFIAPI
  234. Communicate (
  235. IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This,
  236. IN OUT VOID *CommBuffer,
  237. IN OUT UINTN *CommSize
  238. )
  239. {
  240. EFI_STATUS Status;
  241. PEI_SMM_CONTROL_PPI *SmmControl;
  242. PEI_SMM_ACCESS_PPI *SmmAccess;
  243. UINT8 SmiCommand;
  244. UINTN Size;
  245. EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
  246. DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei Communicate Enter\n"));
  247. if (CommBuffer == NULL) {
  248. return EFI_INVALID_PARAMETER;
  249. }
  250. //
  251. // Get needed resource
  252. //
  253. Status = PeiServicesLocatePpi (
  254. &gPeiSmmControlPpiGuid,
  255. 0,
  256. NULL,
  257. (VOID **)&SmmControl
  258. );
  259. if (EFI_ERROR (Status)) {
  260. return EFI_NOT_STARTED;
  261. }
  262. Status = PeiServicesLocatePpi (
  263. &gPeiSmmAccessPpiGuid,
  264. 0,
  265. NULL,
  266. (VOID **)&SmmAccess
  267. );
  268. if (EFI_ERROR (Status)) {
  269. return EFI_NOT_STARTED;
  270. }
  271. //
  272. // Check SMRAM locked, it should be done after SMRAM lock.
  273. //
  274. if (!SmmAccess->LockState) {
  275. DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
  276. return EFI_NOT_STARTED;
  277. }
  278. SmmCommunicationContext = GetCommunicationContext ();
  279. DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei BufferPtrAddress - 0x%016lx, BufferPtr: 0x%016lx\n", SmmCommunicationContext->BufferPtrAddress, *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress));
  280. //
  281. // No need to check if BufferPtr is 0, because it is in PEI phase.
  282. //
  283. *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer;
  284. DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei CommBuffer - %x\n", (UINTN)CommBuffer));
  285. //
  286. // Send command
  287. //
  288. SmiCommand = (UINT8)SmmCommunicationContext->SwSmiNumber;
  289. Size = sizeof (SmiCommand);
  290. Status = SmmControl->Trigger (
  291. (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
  292. SmmControl,
  293. (INT8 *)&SmiCommand,
  294. &Size,
  295. FALSE,
  296. 0
  297. );
  298. ASSERT_EFI_ERROR (Status);
  299. //
  300. // Setting BufferPtr to 0 means this transaction is done.
  301. //
  302. *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = 0;
  303. DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei Communicate Exit\n"));
  304. return EFI_SUCCESS;
  305. }
  306. /**
  307. Entry Point for PI SMM communication PEIM.
  308. @param FileHandle Handle of the file being invoked.
  309. @param PeiServices Pointer to PEI Services table.
  310. @retval EFI_SUCCESS
  311. @return Others Some error occurs.
  312. **/
  313. EFI_STATUS
  314. EFIAPI
  315. PiSmmCommunicationPeiEntryPoint (
  316. IN EFI_PEI_FILE_HANDLE FileHandle,
  317. IN CONST EFI_PEI_SERVICES **PeiServices
  318. )
  319. {
  320. EFI_STATUS Status;
  321. PEI_SMM_ACCESS_PPI *SmmAccess;
  322. EFI_BOOT_MODE BootMode;
  323. UINTN Index;
  324. BootMode = GetBootModeHob ();
  325. if (BootMode != BOOT_ON_S3_RESUME) {
  326. return EFI_UNSUPPORTED;
  327. }
  328. Status = PeiServicesLocatePpi (
  329. &gPeiSmmAccessPpiGuid,
  330. 0,
  331. NULL,
  332. (VOID **)&SmmAccess
  333. );
  334. if (EFI_ERROR (Status)) {
  335. return EFI_NOT_STARTED;
  336. }
  337. //
  338. // Check SMRAM locked, it should be done before SMRAM lock.
  339. //
  340. if (SmmAccess->LockState) {
  341. DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
  342. return EFI_ACCESS_DENIED;
  343. }
  344. //
  345. // Open all SMRAM
  346. //
  347. for (Index = 0; !EFI_ERROR (Status); Index++) {
  348. Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
  349. }
  350. InitCommunicationContext ();
  351. PeiServicesInstallPpi (&mPpiList);
  352. return RETURN_SUCCESS;
  353. }