1 /** @file 2 PiSmmCommunication SMM 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 <PiSmm.h> 16 #include <Library/UefiDriverEntryPoint.h> 17 #include <Library/UefiBootServicesTableLib.h> 18 #include <Library/UefiRuntimeServicesTableLib.h> 19 #include <Library/SmmServicesTableLib.h> 20 #include <Library/BaseLib.h> 21 #include <Library/BaseMemoryLib.h> 22 #include <Library/HobLib.h> 23 #include <Library/DebugLib.h> 24 #include <Library/SmmMemLib.h> 25 #include <Library/PcdLib.h> 26 #include <Protocol/SmmSwDispatch2.h> 27 #include <Protocol/SmmReadyToLock.h> 28 #include <Protocol/SmmCommunication.h> 29 #include <Protocol/AcpiTable.h> 30 #include <Ppi/SmmCommunication.h> 31 #include <Guid/Acpi.h> 32 33 #include "PiSmmCommunicationPrivate.h" 34 35 EFI_SMM_COMMUNICATION_CONTEXT mSmmCommunicationContext = { 36 SMM_COMMUNICATION_SIGNATURE 37 }; 38 39 EFI_SMM_COMMUNICATION_ACPI_TABLE mSmmCommunicationAcpiTable = { 40 { 41 { 42 EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE, 43 sizeof (EFI_SMM_COMMUNICATION_ACPI_TABLE), 44 0x1, // Revision 45 0x0, // Checksum 46 {0x0}, // OemId[6] 47 0x0, // OemTableId 48 0x0, // OemRevision 49 0x0, // CreatorId 50 0x0 // CreatorRevision 51 }, 52 {0x0}, // Identifier 53 OFFSET_OF (EFI_SMM_COMMUNICATION_ACPI_TABLE, SwSmiNumber) // DataOffset 54 }, 55 0x0, // SwSmiNumber 56 0x0 // BufferPtrAddress 57 }; 58 59 /** 60 Set SMM communication context. 61 **/ 62 VOID 63 SetCommunicationContext ( 64 VOID 65 ) 66 { 67 EFI_STATUS Status; 68 69 Status = gSmst->SmmInstallConfigurationTable ( 70 gSmst, 71 &gEfiPeiSmmCommunicationPpiGuid, 72 &mSmmCommunicationContext, 73 sizeof(mSmmCommunicationContext) 74 ); 75 ASSERT_EFI_ERROR (Status); 76 } 77 78 /** 79 Dispatch function for a Software SMI handler. 80 81 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). 82 @param Context Points to an optional handler context which was specified when the 83 handler was registered. 84 @param CommBuffer A pointer to a collection of data in memory that will 85 be conveyed from a non-SMM environment into an SMM environment. 86 @param CommBufferSize The size of the CommBuffer. 87 88 @retval EFI_SUCCESS Command is handled successfully. 89 90 **/ 91 EFI_STATUS 92 EFIAPI 93 PiSmmCommunicationHandler ( 94 IN EFI_HANDLE DispatchHandle, 95 IN CONST VOID *Context OPTIONAL, 96 IN OUT VOID *CommBuffer OPTIONAL, 97 IN OUT UINTN *CommBufferSize OPTIONAL 98 ) 99 { 100 UINTN CommSize; 101 EFI_STATUS Status; 102 EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader; 103 EFI_PHYSICAL_ADDRESS *BufferPtrAddress; 104 105 DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Enter\n")); 106 107 BufferPtrAddress = (EFI_PHYSICAL_ADDRESS *)(UINTN)mSmmCommunicationContext.BufferPtrAddress; 108 CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)(UINTN)*BufferPtrAddress; 109 DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader - %x\n", CommunicateHeader)); 110 if (CommunicateHeader == NULL) { 111 DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler is NULL, needn't to call dispatch function\n")); 112 Status = EFI_SUCCESS; 113 } else { 114 if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicateHeader, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))) { 115 DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader invalid - 0x%x\n", CommunicateHeader)); 116 Status = EFI_SUCCESS; 117 goto Done; 118 } 119 120 CommSize = (UINTN)CommunicateHeader->MessageLength; 121 if (!SmmIsBufferOutsideSmmValid ((UINTN)&CommunicateHeader->Data[0], CommSize)) { 122 DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateData invalid - 0x%x\n", &CommunicateHeader->Data[0])); 123 Status = EFI_SUCCESS; 124 goto Done; 125 } 126 127 // 128 // Call dispatch function 129 // 130 DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Data - %x\n", &CommunicateHeader->Data[0])); 131 Status = gSmst->SmiManage ( 132 &CommunicateHeader->HeaderGuid, 133 NULL, 134 &CommunicateHeader->Data[0], 135 &CommSize 136 ); 137 } 138 139 Done: 140 DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler %r\n", Status)); 141 DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Exit\n")); 142 143 return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_INTERRUPT_PENDING; 144 } 145 146 /** 147 Allocate EfiACPIMemoryNVS below 4G memory address. 148 149 This function allocates EfiACPIMemoryNVS below 4G memory address. 150 151 @param Size Size of memory to allocate. 152 153 @return Allocated address for output. 154 155 **/ 156 VOID* 157 AllocateAcpiNvsMemoryBelow4G ( 158 IN UINTN Size 159 ) 160 { 161 UINTN Pages; 162 EFI_PHYSICAL_ADDRESS Address; 163 EFI_STATUS Status; 164 VOID* Buffer; 165 166 Pages = EFI_SIZE_TO_PAGES (Size); 167 Address = 0xffffffff; 168 169 Status = gBS->AllocatePages ( 170 AllocateMaxAddress, 171 EfiACPIMemoryNVS, 172 Pages, 173 &Address 174 ); 175 ASSERT_EFI_ERROR (Status); 176 177 Buffer = (VOID *) (UINTN) Address; 178 ZeroMem (Buffer, Size); 179 180 return Buffer; 181 } 182 183 /** 184 Entry Point for PI SMM communication SMM driver. 185 186 @param[in] ImageHandle Image handle of this driver. 187 @param[in] SystemTable A Pointer to the EFI System Table. 188 189 @retval EFI_SUCEESS 190 @return Others Some error occurs. 191 **/ 192 EFI_STATUS 193 EFIAPI 194 PiSmmCommunicationSmmEntryPoint ( 195 IN EFI_HANDLE ImageHandle, 196 IN EFI_SYSTEM_TABLE *SystemTable 197 ) 198 { 199 EFI_STATUS Status; 200 EFI_SMM_SW_DISPATCH2_PROTOCOL *SmmSwDispatch2; 201 EFI_SMM_SW_REGISTER_CONTEXT SmmSwDispatchContext; 202 EFI_HANDLE DispatchHandle; 203 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol; 204 UINTN TableKey; 205 UINT64 OemTableId; 206 EFI_PHYSICAL_ADDRESS *BufferPtrAddress; 207 208 CopyMem ( 209 mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId, 210 PcdGetPtr (PcdAcpiDefaultOemId), 211 sizeof (mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId) 212 ); 213 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); 214 CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemTableId, &OemTableId, sizeof (UINT64)); 215 mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); 216 mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); 217 mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); 218 219 // 220 // Register software SMI handler 221 // 222 Status = gSmst->SmmLocateProtocol ( 223 &gEfiSmmSwDispatch2ProtocolGuid, 224 NULL, 225 (VOID **)&SmmSwDispatch2 226 ); 227 ASSERT_EFI_ERROR (Status); 228 229 SmmSwDispatchContext.SwSmiInputValue = (UINTN)-1; 230 Status = SmmSwDispatch2->Register ( 231 SmmSwDispatch2, 232 PiSmmCommunicationHandler, 233 &SmmSwDispatchContext, 234 &DispatchHandle 235 ); 236 ASSERT_EFI_ERROR (Status); 237 238 DEBUG ((EFI_D_INFO, "SmmCommunication SwSmi: %x\n", (UINTN)SmmSwDispatchContext.SwSmiInputValue)); 239 240 // 241 // Set ACPI table 242 // 243 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol); 244 ASSERT_EFI_ERROR (Status); 245 246 mSmmCommunicationAcpiTable.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue; 247 BufferPtrAddress = AllocateAcpiNvsMemoryBelow4G (sizeof(EFI_PHYSICAL_ADDRESS)); 248 ASSERT (BufferPtrAddress != NULL); 249 DEBUG ((EFI_D_INFO, "SmmCommunication BufferPtrAddress: 0x%016lx, BufferPtr: 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress, *BufferPtrAddress)); 250 mSmmCommunicationAcpiTable.BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress; 251 CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Identifier, &gEfiSmmCommunicationProtocolGuid, sizeof(gEfiSmmCommunicationProtocolGuid)); 252 253 Status = AcpiTableProtocol->InstallAcpiTable ( 254 AcpiTableProtocol, 255 &mSmmCommunicationAcpiTable, 256 sizeof(mSmmCommunicationAcpiTable), 257 &TableKey 258 ); 259 ASSERT_EFI_ERROR (Status); 260 261 // 262 // Save context 263 // 264 mSmmCommunicationContext.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue; 265 mSmmCommunicationContext.BufferPtrAddress = mSmmCommunicationAcpiTable.BufferPtrAddress; 266 SetCommunicationContext (); 267 268 return Status; 269 } 270