1 /** @file 2 SMM SwDispatch2 Protocol on SMM SwDispatch Protocol Thunk driver. 3 4 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR> 5 6 7 This program and the accompanying materials are licensed and made available under 8 9 the terms and conditions of the BSD License that accompanies this distribution. 10 11 The full text of the license may be found at 12 13 http://opensource.org/licenses/bsd-license.php. 14 15 16 17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 18 19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 20 21 22 23 24 **/ 25 26 #include <PiDxe.h> 27 #include <FrameworkSmm.h> 28 29 #include <Protocol/SmmSwDispatch2.h> 30 #include <Protocol/SmmSwDispatch.h> 31 #include <Protocol/SmmControl.h> 32 #include <Protocol/SmmCpu.h> 33 34 #include <Library/UefiBootServicesTableLib.h> 35 #include <Library/UefiDriverEntryPoint.h> 36 #include <Library/SmmServicesTableLib.h> 37 #include <Library/BaseLib.h> 38 #include <Library/IoLib.h> 39 #include <Library/DebugLib.h> 40 41 typedef struct { 42 LIST_ENTRY Link; 43 EFI_HANDLE DispatchHandle; 44 UINTN SwSmiInputValue; 45 UINTN DispatchFunction; 46 } EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT; 47 48 /** 49 Register a child SMI source dispatch function for the specified software SMI. 50 51 This service registers a function (DispatchFunction) which will be called when the software 52 SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return, 53 DispatchHandle contains a unique handle which may be used later to unregister the function 54 using UnRegister(). 55 56 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. 57 @param[in] DispatchFunction Function to register for handler when the specified software 58 SMI is generated. 59 @param[in, out] RegisterContext Pointer to the dispatch function's context. 60 The caller fills this context in before calling 61 the register function to indicate to the register 62 function which Software SMI input value the 63 dispatch function should be invoked for. 64 @param[out] DispatchHandle Handle generated by the dispatcher to track the 65 function instance. 66 67 @retval EFI_SUCCESS The dispatch function has been successfully 68 registered and the SMI source has been enabled. 69 @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SMI source. 70 @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI input value 71 is not within valid range. 72 @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this 73 child. 74 @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned 75 for this dispatch. 76 **/ 77 EFI_STATUS 78 EFIAPI 79 SmmSwDispatch2Register ( 80 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, 81 IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, 82 IN OUT EFI_SMM_SW_REGISTER_CONTEXT *RegisterContext, 83 OUT EFI_HANDLE *DispatchHandle 84 ); 85 86 /** 87 Unregister a child SMI source dispatch function for the specified software SMI. 88 89 This service removes the handler associated with DispatchHandle so that it will no longer be 90 called in response to a software SMI. 91 92 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. 93 @param[in] DispatchHandle Handle of dispatch function to deregister. 94 95 @retval EFI_SUCCESS The dispatch function has been successfully unregistered. 96 @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. 97 **/ 98 EFI_STATUS 99 EFIAPI 100 SmmSwDispatch2UnRegister ( 101 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, 102 IN EFI_HANDLE DispatchHandle 103 ); 104 105 EFI_SMM_SW_DISPATCH2_PROTOCOL gSmmSwDispatch2 = { 106 SmmSwDispatch2Register, 107 SmmSwDispatch2UnRegister, 108 0 // MaximumSwiValue 109 }; 110 111 EFI_SMM_SW_DISPATCH_PROTOCOL *mSmmSwDispatch; 112 UINT8 mSmiTriggerRegister; 113 UINT8 mSmiDataRegister; 114 115 EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol; 116 LIST_ENTRY mSmmSwDispatch2ThunkQueue = INITIALIZE_LIST_HEAD_VARIABLE (mSmmSwDispatch2ThunkQueue); FindSmmSwDispatch2ContextBySwSmiInputValue(IN UINTN SwSmiInputValue)117 118 /** 119 This function find SmmSwDispatch2Context by SwSmiInputValue. 120 121 @param SwSmiInputValue The SwSmiInputValue to indentify the SmmSwDispatch2 context 122 123 @return SmmSwDispatch2 context 124 **/ 125 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT * 126 FindSmmSwDispatch2ContextBySwSmiInputValue ( 127 IN UINTN SwSmiInputValue 128 ) 129 { 130 LIST_ENTRY *Link; 131 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext; 132 133 for (Link = mSmmSwDispatch2ThunkQueue.ForwardLink; 134 Link != &mSmmSwDispatch2ThunkQueue; 135 Link = Link->ForwardLink) { 136 ThunkContext = BASE_CR ( 137 Link, 138 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT, 139 Link 140 ); 141 if (ThunkContext->SwSmiInputValue == SwSmiInputValue) { 142 return ThunkContext; 143 } 144 } 145 return NULL; 146 } FindSmmSwDispatch2ContextByDispatchHandle(IN EFI_HANDLE DispatchHandle)147 148 /** 149 This function find SmmSwDispatch2Context by DispatchHandle. 150 151 @param DispatchHandle The DispatchHandle to indentify the SmmSwDispatch2Thunk context 152 153 @return SmmSwDispatch2Thunk context 154 **/ 155 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT * 156 FindSmmSwDispatch2ContextByDispatchHandle ( 157 IN EFI_HANDLE DispatchHandle 158 ) 159 { 160 LIST_ENTRY *Link; 161 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext; 162 163 for (Link = mSmmSwDispatch2ThunkQueue.ForwardLink; 164 Link != &mSmmSwDispatch2ThunkQueue; 165 Link = Link->ForwardLink) { 166 ThunkContext = BASE_CR ( 167 Link, 168 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT, 169 Link 170 ); 171 if (ThunkContext->DispatchHandle == DispatchHandle) { 172 return ThunkContext; 173 } 174 } 175 return NULL; 176 } 177 178 /** 179 Framework dispatch function for a Software SMI handler. 180 181 @param DispatchHandle The handle of this dispatch function. 182 @param DispatchContext The pointer to the dispatch function's context. 183 The SwSmiInputValue field is filled in 184 by the software dispatch driver prior to FrameworkDispatchFunction(IN EFI_HANDLE DispatchHandle,IN EFI_SMM_SW_DISPATCH_CONTEXT * DispatchContext)185 invoking this dispatch function. 186 The dispatch function will only be called 187 for input values for which it is registered. 188 189 @return None 190 191 **/ 192 VOID 193 EFIAPI 194 FrameworkDispatchFunction ( 195 IN EFI_HANDLE DispatchHandle, 196 IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext 197 ) 198 { 199 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext; 200 EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction; 201 EFI_SMM_SW_REGISTER_CONTEXT RegisterContext; 202 EFI_SMM_SW_CONTEXT SwContext; 203 UINTN Size; 204 UINTN Index; 205 EFI_SMM_SAVE_STATE_IO_INFO IoInfo; 206 EFI_STATUS Status; 207 208 // 209 // Search context 210 // 211 ThunkContext = FindSmmSwDispatch2ContextBySwSmiInputValue (DispatchContext->SwSmiInputValue); 212 ASSERT (ThunkContext != NULL); 213 if (ThunkContext == NULL) { 214 return ; 215 } 216 217 // 218 // Construct new context 219 // 220 RegisterContext.SwSmiInputValue = DispatchContext->SwSmiInputValue; 221 Size = sizeof(SwContext); 222 SwContext.CommandPort = IoRead8 (mSmiTriggerRegister); 223 SwContext.DataPort = IoRead8 (mSmiDataRegister); 224 225 // 226 // Try to find which CPU trigger SWSMI 227 // 228 SwContext.SwSmiCpuIndex = 0; 229 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) { 230 Status = mSmmCpuProtocol->ReadSaveState ( 231 mSmmCpuProtocol, 232 sizeof(IoInfo), 233 EFI_SMM_SAVE_STATE_REGISTER_IO, 234 Index, 235 &IoInfo 236 ); 237 if (EFI_ERROR (Status)) { 238 continue; 239 } 240 if (IoInfo.IoPort == mSmiTriggerRegister) { 241 // 242 // Great! Find it. 243 // 244 SwContext.SwSmiCpuIndex = Index; 245 break; 246 } 247 } 248 249 // 250 // Dispatch 251 // 252 DispatchFunction = (EFI_SMM_HANDLER_ENTRY_POINT2)ThunkContext->DispatchFunction; 253 DispatchFunction ( 254 DispatchHandle, 255 &RegisterContext, 256 &SwContext, 257 &Size 258 ); 259 return ; 260 } 261 262 /** 263 Register a child SMI source dispatch function for the specified software SMI. 264 265 This service registers a function (DispatchFunction) which will be called when the software 266 SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return, 267 DispatchHandle contains a unique handle which may be used later to unregister the function 268 using UnRegister(). 269 270 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. 271 @param[in] DispatchFunction Function to register for handler when the specified software 272 SMI is generated. 273 @param[in, out] RegisterContext Pointer to the dispatch function's context. 274 The caller fills this context in before calling 275 the register function to indicate to the register 276 function which Software SMI input value the 277 dispatch function should be invoked for. 278 @param[out] DispatchHandle Handle generated by the dispatcher to track the 279 function instance. 280 281 @retval EFI_SUCCESS The dispatch function has been successfully 282 registered and the SMI source has been enabled. 283 @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SMI source. SmmSwDispatch2Register(IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL * This,IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,IN OUT EFI_SMM_SW_REGISTER_CONTEXT * RegisterContext,OUT EFI_HANDLE * DispatchHandle)284 @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI input value 285 is not within valid range. 286 @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this 287 child. 288 @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned 289 for this dispatch. 290 **/ 291 EFI_STATUS 292 EFIAPI 293 SmmSwDispatch2Register ( 294 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, 295 IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, 296 IN OUT EFI_SMM_SW_REGISTER_CONTEXT *RegisterContext, 297 OUT EFI_HANDLE *DispatchHandle 298 ) 299 { 300 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext; 301 EFI_SMM_SW_DISPATCH_CONTEXT DispatchContext; 302 EFI_STATUS Status; 303 UINTN Index; 304 305 if (RegisterContext->SwSmiInputValue == (UINTN)-1) { 306 // 307 // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure. 308 // 309 Status = EFI_NOT_FOUND; 310 for (Index = 1; Index < gSmmSwDispatch2.MaximumSwiValue; Index++) { 311 DispatchContext.SwSmiInputValue = Index; 312 Status = mSmmSwDispatch->Register ( 313 mSmmSwDispatch, 314 FrameworkDispatchFunction, 315 &DispatchContext, 316 DispatchHandle 317 ); 318 if (!EFI_ERROR (Status)) { 319 RegisterContext->SwSmiInputValue = Index; 320 break; 321 } 322 } 323 if (RegisterContext->SwSmiInputValue == (UINTN)-1) { 324 return EFI_OUT_OF_RESOURCES; 325 } 326 } else { 327 DispatchContext.SwSmiInputValue = RegisterContext->SwSmiInputValue; 328 Status = mSmmSwDispatch->Register ( 329 mSmmSwDispatch, 330 FrameworkDispatchFunction, 331 &DispatchContext, 332 DispatchHandle 333 ); 334 } 335 if (!EFI_ERROR (Status)) { 336 // 337 // Register 338 // 339 Status = gSmst->SmmAllocatePool ( 340 EfiRuntimeServicesData, 341 sizeof(*ThunkContext), 342 (VOID **)&ThunkContext 343 ); 344 ASSERT_EFI_ERROR (Status); 345 if (EFI_ERROR (Status)) { 346 mSmmSwDispatch->UnRegister (mSmmSwDispatch, *DispatchHandle); 347 return EFI_OUT_OF_RESOURCES; 348 } 349 350 ThunkContext->SwSmiInputValue = RegisterContext->SwSmiInputValue; 351 ThunkContext->DispatchFunction = (UINTN)DispatchFunction; 352 ThunkContext->DispatchHandle = *DispatchHandle; 353 InsertTailList (&mSmmSwDispatch2ThunkQueue, &ThunkContext->Link); 354 } 355 356 return Status; 357 } 358 359 /** 360 Unregister a child SMI source dispatch function for the specified software SMI. 361 362 This service removes the handler associated with DispatchHandle so that it will no longer be 363 called in response to a software SMI. SmmSwDispatch2UnRegister(IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)364 365 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance. 366 @param[in] DispatchHandle Handle of dispatch function to deregister. 367 368 @retval EFI_SUCCESS The dispatch function has been successfully unregistered. 369 @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. 370 **/ 371 EFI_STATUS 372 EFIAPI 373 SmmSwDispatch2UnRegister ( 374 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, 375 IN EFI_HANDLE DispatchHandle 376 ) 377 { 378 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext; 379 EFI_STATUS Status; 380 381 Status = mSmmSwDispatch->UnRegister (mSmmSwDispatch, DispatchHandle); 382 if (!EFI_ERROR (Status)) { 383 // 384 // Unregister 385 // 386 ThunkContext = FindSmmSwDispatch2ContextByDispatchHandle (DispatchHandle); 387 ASSERT (ThunkContext != NULL); 388 if (ThunkContext != NULL) { 389 RemoveEntryList (&ThunkContext->Link); 390 gSmst->SmmFreePool (ThunkContext); 391 } 392 } 393 394 return Status; 395 } 396 397 /** 398 Entry Point for this thunk driver. SmmSwDispatch2ThunkMain(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)399 400 @param[in] ImageHandle Image handle of this driver. 401 @param[in] SystemTable A Pointer to the EFI System Table. 402 403 @retval EFI_SUCCESS The entry point is executed successfully. 404 @retval other Some error occurred when executing this entry point. 405 **/ 406 EFI_STATUS 407 EFIAPI 408 SmmSwDispatch2ThunkMain ( 409 IN EFI_HANDLE ImageHandle, 410 IN EFI_SYSTEM_TABLE *SystemTable 411 ) 412 { 413 EFI_STATUS Status; 414 EFI_SMM_CONTROL_PROTOCOL *SmmControl; 415 EFI_SMM_CONTROL_REGISTER RegisterInfo; 416 417 // 418 // Locate Framework SMM SwDispatch Protocol 419 // 420 Status = gBS->LocateProtocol ( 421 &gEfiSmmSwDispatchProtocolGuid, 422 NULL, 423 (VOID **)&mSmmSwDispatch 424 ); 425 ASSERT_EFI_ERROR (Status); 426 gSmmSwDispatch2.MaximumSwiValue = mSmmSwDispatch->MaximumSwiValue; 427 if (gSmmSwDispatch2.MaximumSwiValue == 0x0) { 428 DEBUG ((EFI_D_ERROR, "BUGBUG: MaximumSwiValue is 0, work-around to make it 0xFF\n")); 429 gSmmSwDispatch2.MaximumSwiValue = 0xFF; 430 } 431 432 // 433 // Locate Framework SMM Control Protocol 434 // 435 Status = gBS->LocateProtocol ( 436 &gEfiSmmControlProtocolGuid, 437 NULL, 438 (VOID **)&SmmControl 439 ); 440 441 ASSERT_EFI_ERROR (Status); 442 Status = SmmControl->GetRegisterInfo ( 443 SmmControl, 444 &RegisterInfo 445 ); 446 ASSERT_EFI_ERROR (Status); 447 mSmiTriggerRegister = RegisterInfo.SmiTriggerRegister; 448 mSmiDataRegister = RegisterInfo.SmiDataRegister; 449 450 // 451 // Locate PI SMM CPU protocol 452 // 453 Status = gSmst->SmmLocateProtocol ( 454 &gEfiSmmCpuProtocolGuid, 455 NULL, 456 (VOID **)&mSmmCpuProtocol 457 ); 458 ASSERT_EFI_ERROR (Status); 459 460 // 461 // Publish PI SMM SwDispatch2 Protocol 462 // 463 ImageHandle = NULL; 464 Status = gSmst->SmmInstallProtocolInterface ( 465 &ImageHandle, 466 &gEfiSmmSwDispatch2ProtocolGuid, 467 EFI_NATIVE_INTERFACE, 468 &gSmmSwDispatch2 469 ); 470 ASSERT_EFI_ERROR (Status); 471 return Status; 472 } 473 474