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