1 /** @file 2 SMM Base Protocol on SMM Base2 Protocol Thunk driver. 3 4 This driver co-operates with SMM Base Helper SMM driver to provide SMM Base Protocol 5 based on SMM Base2 Protocol. 6 7 This thunk driver is expected to be loaded before PI SMM IPL driver so that 8 SMM BASE Protocol can be published immediately after SMM Base2 Protocol is installed to 9 make SMM Base Protocol.InSmm() as early as possible. 10 11 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR> 12 This program and the accompanying materials 13 are licensed and made available under the terms and conditions of the BSD License 14 which accompanies this distribution. The full text of the license may be found at 15 http://opensource.org/licenses/bsd-license.php 16 17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 20 **/ 21 22 #include <PiDxe.h> 23 #include <FrameworkSmm.h> 24 25 #include <Protocol/SmmBase2.h> 26 #include <Protocol/SmmCommunication.h> 27 #include <Protocol/SmmBaseHelperReady.h> 28 29 #include <Guid/SmmBaseThunkCommunication.h> 30 #include <Guid/EventGroup.h> 31 32 #include <Library/DebugLib.h> 33 #include <Library/UefiBootServicesTableLib.h> 34 #include <Library/UefiDriverEntryPoint.h> 35 #include <Library/UefiLib.h> 36 #include <Library/UefiRuntimeLib.h> 37 38 SMMBASETHUNK_COMMUNICATION_DATA mCommunicationData = { 39 EFI_SMM_BASE_THUNK_COMMUNICATION_GUID, 40 sizeof (SMMBASE_FUNCTION_DATA) 41 }; 42 43 EFI_HANDLE mSmmBaseHandle = NULL; 44 EFI_SMM_BASE2_PROTOCOL *mSmmBase2 = NULL; 45 EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL; 46 EFI_SMM_BASE_HELPER_READY_PROTOCOL *mSmmBaseHelperReady = NULL; 47 BOOLEAN mAtRuntime = FALSE; 48 49 /** 50 Determine if in SMM mode. 51 52 @retval TRUE In SMM mode. 53 @retval FALSE Not in SMM mode. 54 **/ 55 BOOLEAN 56 IsInSmm ( 57 VOID 58 ) 59 { 60 EFI_STATUS Status; 61 BOOLEAN InSmm; 62 63 Status = mSmmBase2->InSmm (mSmmBase2, &InSmm); 64 ASSERT_EFI_ERROR (Status); 65 return InSmm; 66 } 67 68 /** 69 Invoke services provided by SMM Base Helper SMM driver. 70 **/ 71 VOID 72 SmmBaseHelperService ( 73 VOID 74 ) 75 { 76 UINTN DataSize; 77 78 mCommunicationData.FunctionData.Status = EFI_UNSUPPORTED; 79 mCommunicationData.FunctionData.SmmBaseImageHandle = mSmmBaseHandle; 80 81 if ((mCommunicationData.FunctionData.Function != SmmBaseFunctionCommunicate) && IsInSmm()) { 82 /// 83 /// If in SMM mode, directly call services in SMM Base Helper. 84 /// 85 DataSize = (UINTN)(sizeof (SMMBASE_FUNCTION_DATA)); 86 mSmmBaseHelperReady->ServiceEntry ( 87 NULL, 88 NULL, 89 &mCommunicationData.FunctionData, 90 &DataSize 91 ); 92 } else { 93 /// 94 /// Call services in SMM Base Helper via SMM Communication Protocol. 95 /// 96 DataSize = (UINTN)(sizeof (mCommunicationData)); 97 mSmmCommunication->Communicate ( 98 mSmmCommunication, 99 &mCommunicationData, 100 &DataSize 101 ); 102 } 103 } 104 105 /** 106 Register a given driver into SMRAM. This is the equivalent of performing 107 the LoadImage/StartImage into System Management Mode. 108 109 @param[in] This Protocol instance pointer. 110 @param[in] FilePath Location of the image to be installed as the handler. 111 @param[in] SourceBuffer Optional source buffer in case the image file 112 is in memory. 113 @param[in] SourceSize Size of the source image file, if in memory. 114 @param[out] ImageHandle The handle that the base driver uses to decode 115 the handler. Unique among SMM handlers only, 116 not unique across DXE/EFI. 117 @param[in] LegacyIA32Binary An optional parameter specifying that the associated 118 file is a real-mode IA-32 binary. 119 120 @retval EFI_SUCCESS The operation was successful. 121 @retval EFI_OUT_OF_RESOURCES There were no additional SMRAM resources to load the handler 122 @retval EFI_UNSUPPORTED This platform does not support 16-bit handlers. 123 @retval EFI_UNSUPPORTED Platform is in runtime. 124 @retval EFI_INVALID_PARAMETER The handlers was not the correct image type 125 **/ 126 EFI_STATUS 127 EFIAPI 128 SmmBaseRegister ( 129 IN EFI_SMM_BASE_PROTOCOL *This, 130 IN EFI_DEVICE_PATH_PROTOCOL *FilePath, 131 IN VOID *SourceBuffer, 132 IN UINTN SourceSize, 133 OUT EFI_HANDLE *ImageHandle, 134 IN BOOLEAN LegacyIA32Binary 135 ) 136 { 137 if (mAtRuntime || LegacyIA32Binary) { 138 return EFI_UNSUPPORTED; 139 } 140 141 mCommunicationData.FunctionData.Function = SmmBaseFunctionRegister; 142 mCommunicationData.FunctionData.Args.Register.FilePath = FilePath; 143 mCommunicationData.FunctionData.Args.Register.SourceBuffer = SourceBuffer; 144 mCommunicationData.FunctionData.Args.Register.SourceSize = SourceSize; 145 mCommunicationData.FunctionData.Args.Register.ImageHandle = ImageHandle; 146 mCommunicationData.FunctionData.Args.Register.LegacyIA32Binary = LegacyIA32Binary; 147 148 SmmBaseHelperService (); 149 return mCommunicationData.FunctionData.Status; 150 } 151 152 /** 153 Removes a handler from execution within SMRAM. This is the equivalent of performing 154 the UnloadImage in System Management Mode. 155 156 @param[in] This Protocol instance pointer. 157 @param[in] ImageHandle The handler to be removed. 158 159 @retval EFI_SUCCESS The operation was successful 160 @retval EFI_INVALID_PARAMETER The handler did not exist 161 @retval EFI_UNSUPPORTED Platform is in runtime. 162 **/ 163 EFI_STATUS 164 EFIAPI 165 SmmBaseUnregister ( 166 IN EFI_SMM_BASE_PROTOCOL *This, 167 IN EFI_HANDLE ImageHandle 168 ) 169 { 170 if (mAtRuntime) { 171 return EFI_UNSUPPORTED; 172 } 173 174 mCommunicationData.FunctionData.Function = SmmBaseFunctionUnregister; 175 mCommunicationData.FunctionData.Args.UnRegister.ImageHandle = ImageHandle; 176 177 SmmBaseHelperService (); 178 return mCommunicationData.FunctionData.Status; 179 } 180 181 /** 182 The SMM Inter-module Communicate Service Communicate() function 183 provides a service to send/receive messages from a registered 184 EFI service. The BASE protocol driver is responsible for doing 185 any of the copies such that the data lives in boot-service-accessible RAM. 186 187 @param[in] This Protocol instance pointer. 188 @param[in] ImageHandle The handle of the registered driver. 189 @param[in, out] CommunicationBuffer Pointer to the buffer to convey into SMRAM. 190 @param[in, out] BufferSize The size of the data buffer being passed in. 191 On exit, the size of data being returned. 192 Zero if the handler does not wish to reply with any data. 193 194 @retval EFI_SUCCESS The message was successfully posted 195 @retval EFI_INVALID_PARAMETER The buffer was NULL 196 **/ 197 EFI_STATUS 198 EFIAPI 199 SmmBaseCommunicate ( 200 IN EFI_SMM_BASE_PROTOCOL *This, 201 IN EFI_HANDLE ImageHandle, 202 IN OUT VOID *CommunicationBuffer, 203 IN OUT UINTN *BufferSize 204 ) 205 { 206 /// 207 /// Note this is a runtime interface 208 /// 209 210 if (CommunicationBuffer == NULL || BufferSize == NULL) { 211 return EFI_INVALID_PARAMETER; 212 } 213 214 mCommunicationData.FunctionData.Function = SmmBaseFunctionCommunicate; 215 mCommunicationData.FunctionData.Args.Communicate.ImageHandle = ImageHandle; 216 mCommunicationData.FunctionData.Args.Communicate.CommunicationBuffer = CommunicationBuffer; 217 mCommunicationData.FunctionData.Args.Communicate.SourceSize = BufferSize; 218 219 SmmBaseHelperService (); 220 return mCommunicationData.FunctionData.Status; 221 } 222 223 /** 224 Register a callback to execute within SMM. 225 This allows receipt of messages created with EFI_SMM_BASE_PROTOCOL.Communicate(). 226 227 @param[in] This Protocol instance pointer. 228 @param[in] SmmImageHandle Handle of the callback service. 229 @param[in] CallbackAddress Address of the callback service. 230 @param[in] MakeLast If present, will stipulate that the handler is posted to 231 be executed last in the dispatch table. 232 @param[in] FloatingPointSave An optional parameter that informs the 233 EFI_SMM_ACCESS_PROTOCOL Driver core if it needs to save 234 the floating point register state. If any handler 235 require this, the state will be saved for all handlers. 236 237 @retval EFI_SUCCESS The operation was successful 238 @retval EFI_OUT_OF_RESOURCES Not enough space in the dispatch queue 239 @retval EFI_UNSUPPORTED Platform is in runtime. 240 @retval EFI_UNSUPPORTED The caller is not in SMM. 241 **/ 242 EFI_STATUS 243 EFIAPI 244 SmmBaseRegisterCallback ( 245 IN EFI_SMM_BASE_PROTOCOL *This, 246 IN EFI_HANDLE SmmImageHandle, 247 IN EFI_SMM_CALLBACK_ENTRY_POINT CallbackAddress, 248 IN BOOLEAN MakeLast, 249 IN BOOLEAN FloatingPointSave 250 ) 251 { 252 if (!IsInSmm()) { 253 return EFI_UNSUPPORTED; 254 } 255 256 mCommunicationData.FunctionData.Function = SmmBaseFunctionRegisterCallback; 257 mCommunicationData.FunctionData.Args.RegisterCallback.SmmImageHandle = SmmImageHandle; 258 mCommunicationData.FunctionData.Args.RegisterCallback.CallbackAddress = CallbackAddress; 259 mCommunicationData.FunctionData.Args.RegisterCallback.MakeLast = MakeLast; 260 mCommunicationData.FunctionData.Args.RegisterCallback.FloatingPointSave = FloatingPointSave; 261 262 SmmBaseHelperService(); 263 return mCommunicationData.FunctionData.Status; 264 } 265 266 /** 267 This routine tells caller if execution context is SMM or not. 268 269 @param[in] This Protocol instance pointer. 270 @param[out] InSmm Whether the caller is inside SMM for IA-32 271 or servicing a PMI for the Itanium processor 272 family. 273 274 @retval EFI_SUCCESS The operation was successful 275 @retval EFI_INVALID_PARAMETER InSmm was NULL. 276 **/ 277 EFI_STATUS 278 EFIAPI 279 SmmBaseInSmm ( 280 IN EFI_SMM_BASE_PROTOCOL *This, 281 OUT BOOLEAN *InSmm 282 ) 283 { 284 return mSmmBase2->InSmm (mSmmBase2, InSmm); 285 } 286 287 /** 288 The SmmAllocatePool() function allocates a memory region of Size bytes from memory of 289 type PoolType and returns the address of the allocated memory in the location referenced 290 by Buffer. This function allocates pages from EFI SMRAM Memory as needed to grow the 291 requested pool type. All allocations are eight-byte aligned. 292 293 @param[in] This Protocol instance pointer. 294 @param[in] PoolType The type of pool to allocate. 295 The only supported type is EfiRuntimeServicesData; 296 the interface will internally map this runtime request to 297 SMRAM for IA-32 and leave as this type for the Itanium 298 processor family. Other types can be ignored. 299 @param[in] Size The number of bytes to allocate from the pool. 300 @param[out] Buffer A pointer to a pointer to the allocated buffer if the call 301 succeeds; undefined otherwise. 302 303 @retval EFI_SUCCESS The requested number of bytes was allocated. 304 @retval EFI_OUT_OF_RESOURCES The pool requested could not be allocated. 305 @retval EFI_UNSUPPORTED Platform is in runtime. 306 **/ 307 EFI_STATUS 308 EFIAPI 309 SmmBaseSmmAllocatePool ( 310 IN EFI_SMM_BASE_PROTOCOL *This, 311 IN EFI_MEMORY_TYPE PoolType, 312 IN UINTN Size, 313 OUT VOID **Buffer 314 ) 315 { 316 if (mAtRuntime) { 317 return EFI_UNSUPPORTED; 318 } 319 320 mCommunicationData.FunctionData.Function = SmmBaseFunctionAllocatePool; 321 mCommunicationData.FunctionData.Args.AllocatePool.PoolType = PoolType; 322 mCommunicationData.FunctionData.Args.AllocatePool.Size = Size; 323 mCommunicationData.FunctionData.Args.AllocatePool.Buffer = Buffer; 324 325 SmmBaseHelperService (); 326 return mCommunicationData.FunctionData.Status; 327 } 328 329 /** 330 The SmmFreePool() function returns the memory specified by Buffer to the system. 331 On return, the memory's type is EFI SMRAM Memory. The Buffer that is freed must 332 have been allocated by SmmAllocatePool(). 333 334 @param[in] This Protocol instance pointer. 335 @param[in] Buffer Pointer to the buffer allocation. 336 337 @retval EFI_SUCCESS The memory was returned to the system. 338 @retval EFI_INVALID_PARAMETER Buffer was invalid. 339 @retval EFI_UNSUPPORTED Platform is in runtime. 340 **/ 341 EFI_STATUS 342 EFIAPI 343 SmmBaseSmmFreePool ( 344 IN EFI_SMM_BASE_PROTOCOL *This, 345 IN VOID *Buffer 346 ) 347 { 348 if (mAtRuntime) { 349 return EFI_UNSUPPORTED; 350 } 351 352 mCommunicationData.FunctionData.Function = SmmBaseFunctionFreePool; 353 mCommunicationData.FunctionData.Args.FreePool.Buffer = Buffer; 354 355 SmmBaseHelperService (); 356 return mCommunicationData.FunctionData.Status; 357 } 358 359 /** 360 The GetSmstLocation() function returns the location of the System Management 361 Service Table. The use of the API is such that a driver can discover the 362 location of the SMST in its entry point and then cache it in some driver 363 global variable so that the SMST can be invoked in subsequent callbacks. 364 365 @param[in] This Protocol instance pointer. 366 @param[out] Smst Pointer to the SMST. 367 368 @retval EFI_SUCCESS The operation was successful 369 @retval EFI_INVALID_PARAMETER Smst was invalid. 370 @retval EFI_UNSUPPORTED Not in SMM. 371 **/ 372 EFI_STATUS 373 EFIAPI 374 SmmBaseGetSmstLocation ( 375 IN EFI_SMM_BASE_PROTOCOL *This, 376 OUT EFI_SMM_SYSTEM_TABLE **Smst 377 ) 378 { 379 if (!IsInSmm ()) { 380 return EFI_UNSUPPORTED; 381 } 382 383 if (Smst == NULL) { 384 return EFI_INVALID_PARAMETER; 385 } 386 387 *Smst = mSmmBaseHelperReady->FrameworkSmst; 388 return EFI_SUCCESS; 389 } 390 391 /** 392 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 393 394 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. 395 It convers pointer to new virtual address. 396 397 @param Event Event whose notification function is being invoked 398 @param Context Pointer to the notification function's context 399 **/ 400 VOID 401 EFIAPI 402 SmmBaseAddressChangeEvent ( 403 IN EFI_EVENT Event, 404 IN VOID *Context 405 ) 406 { 407 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication); 408 } 409 410 /// 411 /// SMM Base Protocol instance 412 /// 413 EFI_SMM_BASE_PROTOCOL mSmmBase = { 414 SmmBaseRegister, 415 SmmBaseUnregister, 416 SmmBaseCommunicate, 417 SmmBaseRegisterCallback, 418 SmmBaseInSmm, 419 SmmBaseSmmAllocatePool, 420 SmmBaseSmmFreePool, 421 SmmBaseGetSmstLocation 422 }; 423 424 /** 425 Notification function on Exit Boot Services Event. 426 427 This function sets a flag indicating it is in Runtime phase. 428 429 @param Event Event whose notification function is being invoked 430 @param Context Pointer to the notification function's context 431 **/ 432 VOID 433 EFIAPI 434 SmmBaseExitBootServicesEventNotify ( 435 IN EFI_EVENT Event, 436 IN VOID *Context 437 ) 438 { 439 mAtRuntime = TRUE; 440 } 441 442 /** 443 Entry Point for SMM Base Protocol on SMM Base2 Protocol Thunk driver. 444 445 @param[in] ImageHandle Image handle of this driver. 446 @param[in] SystemTable A Pointer to the EFI System Table. 447 448 @retval EFI_SUCCESS The entry point is executed successfully. 449 **/ 450 EFI_STATUS 451 EFIAPI 452 SmmBaseThunkMain ( 453 IN EFI_HANDLE ImageHandle, 454 IN EFI_SYSTEM_TABLE *SystemTable 455 ) 456 { 457 EFI_STATUS Status; 458 EFI_EVENT Event; 459 460 mSmmBaseHandle = ImageHandle; 461 462 // 463 // Assume only one instance of SMM Base2 Protocol in the system 464 // Locate SMM Base2 Protocol 465 // 466 Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **) &mSmmBase2); 467 ASSERT_EFI_ERROR (Status); 468 469 // 470 // Assume only one instance of SMM Communication Protocol in the system 471 // Locate SMM Communication Protocol 472 // 473 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication); 474 ASSERT_EFI_ERROR (Status); 475 476 // 477 // Assume only one instance of SMM Base Helper Ready Protocol in the system 478 // Locate SMM Base Helper Ready Protocol 479 // 480 Status = gBS->LocateProtocol (&gEfiSmmBaseHelperReadyProtocolGuid, NULL, (VOID **) &mSmmBaseHelperReady); 481 ASSERT_EFI_ERROR (Status); 482 483 // 484 // Create event notification on Exit Boot Services event. 485 // 486 Status = gBS->CreateEventEx ( 487 EVT_NOTIFY_SIGNAL, 488 TPL_NOTIFY, 489 SmmBaseExitBootServicesEventNotify, 490 NULL, 491 &gEfiEventExitBootServicesGuid, 492 &Event 493 ); 494 ASSERT_EFI_ERROR (Status); 495 496 // 497 // Create event on SetVirtualAddressMap() to convert mSmmCommunication from a physical address to a virtual address 498 // 499 Status = gBS->CreateEventEx ( 500 EVT_NOTIFY_SIGNAL, 501 TPL_NOTIFY, 502 SmmBaseAddressChangeEvent, 503 NULL, 504 &gEfiEventVirtualAddressChangeGuid, 505 &Event 506 ); 507 ASSERT_EFI_ERROR (Status); 508 509 // 510 // Publish Framework SMM BASE Protocol immediately after SMM Base2 Protocol is installed to 511 // make SMM Base Protocol.InSmm() available as early as possible. 512 // 513 Status = gBS->InstallMultipleProtocolInterfaces ( 514 &mSmmBaseHandle, 515 &gEfiSmmBaseProtocolGuid, &mSmmBase, 516 NULL 517 ); 518 ASSERT_EFI_ERROR (Status); 519 520 return EFI_SUCCESS; 521 } 522