1 /** @file 2 SMM handle & protocol handling. 3 4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials are licensed and made available 6 under the terms and conditions of the BSD License which accompanies this 7 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 "PiSmmCore.h" 16 17 // 18 // mProtocolDatabase - A list of all protocols in the system. (simple list for now) 19 // gHandleList - A list of all the handles in the system 20 // 21 LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase); 22 LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList); 23 24 /** 25 Check whether a handle is a valid EFI_HANDLE 26 27 @param UserHandle The handle to check 28 29 @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE. 30 @retval EFI_SUCCESS The handle is valid EFI_HANDLE. 31 32 **/ 33 EFI_STATUS 34 SmmValidateHandle ( 35 IN EFI_HANDLE UserHandle 36 ) 37 { 38 IHANDLE *Handle; 39 40 Handle = (IHANDLE *)UserHandle; 41 if (Handle == NULL) { 42 return EFI_INVALID_PARAMETER; 43 } 44 if (Handle->Signature != EFI_HANDLE_SIGNATURE) { 45 return EFI_INVALID_PARAMETER; 46 } 47 return EFI_SUCCESS; 48 } 49 50 /** 51 Finds the protocol entry for the requested protocol. 52 53 @param Protocol The ID of the protocol 54 @param Create Create a new entry if not found 55 56 @return Protocol entry 57 58 **/ 59 PROTOCOL_ENTRY * 60 SmmFindProtocolEntry ( 61 IN EFI_GUID *Protocol, 62 IN BOOLEAN Create 63 ) 64 { 65 LIST_ENTRY *Link; 66 PROTOCOL_ENTRY *Item; 67 PROTOCOL_ENTRY *ProtEntry; 68 69 // 70 // Search the database for the matching GUID 71 // 72 73 ProtEntry = NULL; 74 for (Link = mProtocolDatabase.ForwardLink; 75 Link != &mProtocolDatabase; 76 Link = Link->ForwardLink) { 77 78 Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE); 79 if (CompareGuid (&Item->ProtocolID, Protocol)) { 80 // 81 // This is the protocol entry 82 // 83 ProtEntry = Item; 84 break; 85 } 86 } 87 88 // 89 // If the protocol entry was not found and Create is TRUE, then 90 // allocate a new entry 91 // 92 if ((ProtEntry == NULL) && Create) { 93 ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY)); 94 if (ProtEntry != NULL) { 95 // 96 // Initialize new protocol entry structure 97 // 98 ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE; 99 CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol); 100 InitializeListHead (&ProtEntry->Protocols); 101 InitializeListHead (&ProtEntry->Notify); 102 103 // 104 // Add it to protocol database 105 // 106 InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries); 107 } 108 } 109 return ProtEntry; 110 } 111 112 /** 113 Finds the protocol instance for the requested handle and protocol. 114 Note: This function doesn't do parameters checking, it's caller's responsibility 115 to pass in valid parameters. 116 117 @param Handle The handle to search the protocol on 118 @param Protocol GUID of the protocol 119 @param Interface The interface for the protocol being searched 120 121 @return Protocol instance (NULL: Not found) 122 123 **/ 124 PROTOCOL_INTERFACE * 125 SmmFindProtocolInterface ( 126 IN IHANDLE *Handle, 127 IN EFI_GUID *Protocol, 128 IN VOID *Interface 129 ) 130 { 131 PROTOCOL_INTERFACE *Prot; 132 PROTOCOL_ENTRY *ProtEntry; 133 LIST_ENTRY *Link; 134 135 Prot = NULL; 136 137 // 138 // Lookup the protocol entry for this protocol ID 139 // 140 ProtEntry = SmmFindProtocolEntry (Protocol, FALSE); 141 if (ProtEntry != NULL) { 142 // 143 // Look at each protocol interface for any matches 144 // 145 for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) { 146 // 147 // If this protocol interface matches, remove it 148 // 149 Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); 150 if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) { 151 break; 152 } 153 Prot = NULL; 154 } 155 } 156 return Prot; 157 } 158 159 /** 160 Wrapper function to SmmInstallProtocolInterfaceNotify. This is the public API which 161 Calls the private one which contains a BOOLEAN parameter for notifications 162 163 @param UserHandle The handle to install the protocol handler on, 164 or NULL if a new handle is to be allocated 165 @param Protocol The protocol to add to the handle 166 @param InterfaceType Indicates whether Interface is supplied in 167 native form. 168 @param Interface The interface for the protocol being added 169 170 @return Status code 171 172 **/ 173 EFI_STATUS 174 EFIAPI 175 SmmInstallProtocolInterface ( 176 IN OUT EFI_HANDLE *UserHandle, 177 IN EFI_GUID *Protocol, 178 IN EFI_INTERFACE_TYPE InterfaceType, 179 IN VOID *Interface 180 ) 181 { 182 return SmmInstallProtocolInterfaceNotify ( 183 UserHandle, 184 Protocol, 185 InterfaceType, 186 Interface, 187 TRUE 188 ); 189 } 190 191 /** 192 Installs a protocol interface into the boot services environment. 193 194 @param UserHandle The handle to install the protocol handler on, 195 or NULL if a new handle is to be allocated 196 @param Protocol The protocol to add to the handle 197 @param InterfaceType Indicates whether Interface is supplied in 198 native form. 199 @param Interface The interface for the protocol being added 200 @param Notify indicates whether notify the notification list 201 for this protocol 202 203 @retval EFI_INVALID_PARAMETER Invalid parameter 204 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate 205 @retval EFI_SUCCESS Protocol interface successfully installed 206 207 **/ 208 EFI_STATUS 209 SmmInstallProtocolInterfaceNotify ( 210 IN OUT EFI_HANDLE *UserHandle, 211 IN EFI_GUID *Protocol, 212 IN EFI_INTERFACE_TYPE InterfaceType, 213 IN VOID *Interface, 214 IN BOOLEAN Notify 215 ) 216 { 217 PROTOCOL_INTERFACE *Prot; 218 PROTOCOL_ENTRY *ProtEntry; 219 IHANDLE *Handle; 220 EFI_STATUS Status; 221 VOID *ExistingInterface; 222 223 // 224 // returns EFI_INVALID_PARAMETER if InterfaceType is invalid. 225 // Also added check for invalid UserHandle and Protocol pointers. 226 // 227 if (UserHandle == NULL || Protocol == NULL) { 228 return EFI_INVALID_PARAMETER; 229 } 230 231 if (InterfaceType != EFI_NATIVE_INTERFACE) { 232 return EFI_INVALID_PARAMETER; 233 } 234 235 // 236 // Print debug message 237 // 238 DEBUG((DEBUG_LOAD | DEBUG_INFO, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface)); 239 240 Status = EFI_OUT_OF_RESOURCES; 241 Prot = NULL; 242 Handle = NULL; 243 244 if (*UserHandle != NULL) { 245 Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface); 246 if (!EFI_ERROR (Status)) { 247 return EFI_INVALID_PARAMETER; 248 } 249 } 250 251 // 252 // Lookup the Protocol Entry for the requested protocol 253 // 254 ProtEntry = SmmFindProtocolEntry (Protocol, TRUE); 255 if (ProtEntry == NULL) { 256 goto Done; 257 } 258 259 // 260 // Allocate a new protocol interface structure 261 // 262 Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE)); 263 if (Prot == NULL) { 264 Status = EFI_OUT_OF_RESOURCES; 265 goto Done; 266 } 267 268 // 269 // If caller didn't supply a handle, allocate a new one 270 // 271 Handle = (IHANDLE *)*UserHandle; 272 if (Handle == NULL) { 273 Handle = AllocateZeroPool (sizeof(IHANDLE)); 274 if (Handle == NULL) { 275 Status = EFI_OUT_OF_RESOURCES; 276 goto Done; 277 } 278 279 // 280 // Initialize new handler structure 281 // 282 Handle->Signature = EFI_HANDLE_SIGNATURE; 283 InitializeListHead (&Handle->Protocols); 284 285 // 286 // Add this handle to the list global list of all handles 287 // in the system 288 // 289 InsertTailList (&gHandleList, &Handle->AllHandles); 290 } 291 292 Status = SmmValidateHandle (Handle); 293 if (EFI_ERROR (Status)) { 294 goto Done; 295 } 296 297 // 298 // Each interface that is added must be unique 299 // 300 ASSERT (SmmFindProtocolInterface (Handle, Protocol, Interface) == NULL); 301 302 // 303 // Initialize the protocol interface structure 304 // 305 Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE; 306 Prot->Handle = Handle; 307 Prot->Protocol = ProtEntry; 308 Prot->Interface = Interface; 309 310 // 311 // Add this protocol interface to the head of the supported 312 // protocol list for this handle 313 // 314 InsertHeadList (&Handle->Protocols, &Prot->Link); 315 316 // 317 // Add this protocol interface to the tail of the 318 // protocol entry 319 // 320 InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol); 321 322 // 323 // Notify the notification list for this protocol 324 // 325 if (Notify) { 326 SmmNotifyProtocol (Prot); 327 } 328 Status = EFI_SUCCESS; 329 330 Done: 331 if (!EFI_ERROR (Status)) { 332 // 333 // Return the new handle back to the caller 334 // 335 *UserHandle = Handle; 336 } else { 337 // 338 // There was an error, clean up 339 // 340 if (Prot != NULL) { 341 FreePool (Prot); 342 } 343 } 344 return Status; 345 } 346 347 /** 348 Uninstalls all instances of a protocol:interfacer from a handle. 349 If the last protocol interface is remove from the handle, the 350 handle is freed. 351 352 @param UserHandle The handle to remove the protocol handler from 353 @param Protocol The protocol, of protocol:interface, to remove 354 @param Interface The interface, of protocol:interface, to remove 355 356 @retval EFI_INVALID_PARAMETER Protocol is NULL. 357 @retval EFI_SUCCESS Protocol interface successfully uninstalled. 358 359 **/ 360 EFI_STATUS 361 EFIAPI 362 SmmUninstallProtocolInterface ( 363 IN EFI_HANDLE UserHandle, 364 IN EFI_GUID *Protocol, 365 IN VOID *Interface 366 ) 367 { 368 EFI_STATUS Status; 369 IHANDLE *Handle; 370 PROTOCOL_INTERFACE *Prot; 371 372 // 373 // Check that Protocol is valid 374 // 375 if (Protocol == NULL) { 376 return EFI_INVALID_PARAMETER; 377 } 378 379 // 380 // Check that UserHandle is a valid handle 381 // 382 Status = SmmValidateHandle (UserHandle); 383 if (EFI_ERROR (Status)) { 384 return Status; 385 } 386 387 // 388 // Check that Protocol exists on UserHandle, and Interface matches the interface in the database 389 // 390 Prot = SmmFindProtocolInterface (UserHandle, Protocol, Interface); 391 if (Prot == NULL) { 392 return EFI_NOT_FOUND; 393 } 394 395 // 396 // Remove the protocol interface from the protocol 397 // 398 Status = EFI_NOT_FOUND; 399 Handle = (IHANDLE *)UserHandle; 400 Prot = SmmRemoveInterfaceFromProtocol (Handle, Protocol, Interface); 401 402 if (Prot != NULL) { 403 // 404 // Remove the protocol interface from the handle 405 // 406 RemoveEntryList (&Prot->Link); 407 408 // 409 // Free the memory 410 // 411 Prot->Signature = 0; 412 FreePool (Prot); 413 Status = EFI_SUCCESS; 414 } 415 416 // 417 // If there are no more handlers for the handle, free the handle 418 // 419 if (IsListEmpty (&Handle->Protocols)) { 420 Handle->Signature = 0; 421 RemoveEntryList (&Handle->AllHandles); 422 FreePool (Handle); 423 } 424 return Status; 425 } 426 427 /** 428 Locate a certain GUID protocol interface in a Handle's protocols. 429 430 @param UserHandle The handle to obtain the protocol interface on 431 @param Protocol The GUID of the protocol 432 433 @return The requested protocol interface for the handle 434 435 **/ 436 PROTOCOL_INTERFACE * 437 SmmGetProtocolInterface ( 438 IN EFI_HANDLE UserHandle, 439 IN EFI_GUID *Protocol 440 ) 441 { 442 EFI_STATUS Status; 443 PROTOCOL_ENTRY *ProtEntry; 444 PROTOCOL_INTERFACE *Prot; 445 IHANDLE *Handle; 446 LIST_ENTRY *Link; 447 448 Status = SmmValidateHandle (UserHandle); 449 if (EFI_ERROR (Status)) { 450 return NULL; 451 } 452 453 Handle = (IHANDLE *)UserHandle; 454 455 // 456 // Look at each protocol interface for a match 457 // 458 for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { 459 Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); 460 ProtEntry = Prot->Protocol; 461 if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) { 462 return Prot; 463 } 464 } 465 return NULL; 466 } 467 468 /** 469 Queries a handle to determine if it supports a specified protocol. 470 471 @param UserHandle The handle being queried. 472 @param Protocol The published unique identifier of the protocol. 473 @param Interface Supplies the address where a pointer to the 474 corresponding Protocol Interface is returned. 475 476 @retval EFI_SUCCESS The interface information for the specified protocol was returned. 477 @retval EFI_UNSUPPORTED The device does not support the specified protocol. 478 @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.. 479 @retval EFI_INVALID_PARAMETER Protocol is NULL. 480 @retval EFI_INVALID_PARAMETER Interface is NULL. 481 482 **/ 483 EFI_STATUS 484 EFIAPI 485 SmmHandleProtocol ( 486 IN EFI_HANDLE UserHandle, 487 IN EFI_GUID *Protocol, 488 OUT VOID **Interface 489 ) 490 { 491 EFI_STATUS Status; 492 PROTOCOL_INTERFACE *Prot; 493 494 // 495 // Check for invalid Protocol 496 // 497 if (Protocol == NULL) { 498 return EFI_INVALID_PARAMETER; 499 } 500 501 // 502 // Check for invalid Interface 503 // 504 if (Interface == NULL) { 505 return EFI_INVALID_PARAMETER; 506 } else { 507 *Interface = NULL; 508 } 509 510 // 511 // Check for invalid UserHandle 512 // 513 Status = SmmValidateHandle (UserHandle); 514 if (EFI_ERROR (Status)) { 515 return Status; 516 } 517 518 // 519 // Look at each protocol interface for a match 520 // 521 Prot = SmmGetProtocolInterface (UserHandle, Protocol); 522 if (Prot == NULL) { 523 return EFI_UNSUPPORTED; 524 } 525 526 // 527 // This is the protocol interface entry for this protocol 528 // 529 *Interface = Prot->Interface; 530 531 return EFI_SUCCESS; 532 } 533