1 /** @file 2 Locate handle functions 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 // ProtocolRequest - Last LocateHandle request ID 19 // 20 UINTN mEfiLocateHandleRequest = 0; 21 22 // 23 // Internal prototypes 24 // 25 26 typedef struct { 27 EFI_GUID *Protocol; 28 VOID *SearchKey; 29 LIST_ENTRY *Position; 30 PROTOCOL_ENTRY *ProtEntry; 31 } LOCATE_POSITION; 32 33 typedef 34 IHANDLE * 35 (* CORE_GET_NEXT) ( 36 IN OUT LOCATE_POSITION *Position, 37 OUT VOID **Interface 38 ); 39 40 /** 41 Routine to get the next Handle, when you are searching for all handles. 42 43 @param Position Information about which Handle to seach for. 44 @param Interface Return the interface structure for the matching 45 protocol. 46 47 @return An pointer to IHANDLE if the next Position is not the end of the list. 48 Otherwise,NULL is returned. 49 50 **/ 51 IHANDLE * 52 SmmGetNextLocateAllHandles ( 53 IN OUT LOCATE_POSITION *Position, 54 OUT VOID **Interface 55 ) 56 { 57 IHANDLE *Handle; 58 59 // 60 // Next handle 61 // 62 Position->Position = Position->Position->ForwardLink; 63 64 // 65 // If not at the end of the list, get the handle 66 // 67 Handle = NULL; 68 *Interface = NULL; 69 if (Position->Position != &gHandleList) { 70 Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE); 71 } 72 return Handle; 73 } 74 75 /** 76 Routine to get the next Handle, when you are searching for register protocol 77 notifies. 78 79 @param Position Information about which Handle to seach for. 80 @param Interface Return the interface structure for the matching 81 protocol. 82 83 @return An pointer to IHANDLE if the next Position is not the end of the list. 84 Otherwise,NULL is returned. 85 86 **/ 87 IHANDLE * 88 SmmGetNextLocateByRegisterNotify ( 89 IN OUT LOCATE_POSITION *Position, 90 OUT VOID **Interface 91 ) 92 { 93 IHANDLE *Handle; 94 PROTOCOL_NOTIFY *ProtNotify; 95 PROTOCOL_INTERFACE *Prot; 96 LIST_ENTRY *Link; 97 98 Handle = NULL; 99 *Interface = NULL; 100 ProtNotify = Position->SearchKey; 101 102 // 103 // If this is the first request, get the next handle 104 // 105 if (ProtNotify != NULL) { 106 ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE); 107 Position->SearchKey = NULL; 108 109 // 110 // If not at the end of the list, get the next handle 111 // 112 Link = ProtNotify->Position->ForwardLink; 113 if (Link != &ProtNotify->Protocol->Protocols) { 114 Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE); 115 Handle = Prot->Handle; 116 *Interface = Prot->Interface; 117 } 118 } 119 return Handle; 120 } 121 122 /** 123 Routine to get the next Handle, when you are searching for a given protocol. 124 125 @param Position Information about which Handle to seach for. 126 @param Interface Return the interface structure for the matching 127 protocol. 128 129 @return An pointer to IHANDLE if the next Position is not the end of the list. 130 Otherwise,NULL is returned. 131 132 **/ 133 IHANDLE * 134 SmmGetNextLocateByProtocol ( 135 IN OUT LOCATE_POSITION *Position, 136 OUT VOID **Interface 137 ) 138 { 139 IHANDLE *Handle; 140 LIST_ENTRY *Link; 141 PROTOCOL_INTERFACE *Prot; 142 143 Handle = NULL; 144 *Interface = NULL; 145 for (; ;) { 146 // 147 // Next entry 148 // 149 Link = Position->Position->ForwardLink; 150 Position->Position = Link; 151 152 // 153 // If not at the end, return the handle 154 // 155 if (Link == &Position->ProtEntry->Protocols) { 156 Handle = NULL; 157 break; 158 } 159 160 // 161 // Get the handle 162 // 163 Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE); 164 Handle = Prot->Handle; 165 *Interface = Prot->Interface; 166 167 // 168 // If this handle has not been returned this request, then 169 // return it now 170 // 171 if (Handle->LocateRequest != mEfiLocateHandleRequest) { 172 Handle->LocateRequest = mEfiLocateHandleRequest; 173 break; 174 } 175 } 176 return Handle; 177 } 178 179 /** 180 Return the first Protocol Interface that matches the Protocol GUID. If 181 Registration is pasased in return a Protocol Instance that was just add 182 to the system. If Retistration is NULL return the first Protocol Interface 183 you find. 184 185 @param Protocol The protocol to search for 186 @param Registration Optional Registration Key returned from 187 RegisterProtocolNotify() 188 @param Interface Return the Protocol interface (instance). 189 190 @retval EFI_SUCCESS If a valid Interface is returned 191 @retval EFI_INVALID_PARAMETER Invalid parameter 192 @retval EFI_NOT_FOUND Protocol interface not found 193 194 **/ 195 EFI_STATUS 196 EFIAPI 197 SmmLocateProtocol ( 198 IN EFI_GUID *Protocol, 199 IN VOID *Registration OPTIONAL, 200 OUT VOID **Interface 201 ) 202 { 203 EFI_STATUS Status; 204 LOCATE_POSITION Position; 205 PROTOCOL_NOTIFY *ProtNotify; 206 IHANDLE *Handle; 207 208 if (Interface == NULL) { 209 return EFI_INVALID_PARAMETER; 210 } 211 212 if (Protocol == NULL) { 213 return EFI_NOT_FOUND; 214 } 215 216 *Interface = NULL; 217 Status = EFI_SUCCESS; 218 219 // 220 // Set initial position 221 // 222 Position.Protocol = Protocol; 223 Position.SearchKey = Registration; 224 Position.Position = &gHandleList; 225 226 mEfiLocateHandleRequest += 1; 227 228 if (Registration == NULL) { 229 // 230 // Look up the protocol entry and set the head pointer 231 // 232 Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE); 233 if (Position.ProtEntry == NULL) { 234 return EFI_NOT_FOUND; 235 } 236 Position.Position = &Position.ProtEntry->Protocols; 237 238 Handle = SmmGetNextLocateByProtocol (&Position, Interface); 239 } else { 240 Handle = SmmGetNextLocateByRegisterNotify (&Position, Interface); 241 } 242 243 if (Handle == NULL) { 244 Status = EFI_NOT_FOUND; 245 } else if (Registration != NULL) { 246 // 247 // If this is a search by register notify and a handle was 248 // returned, update the register notification position 249 // 250 ProtNotify = Registration; 251 ProtNotify->Position = ProtNotify->Position->ForwardLink; 252 } 253 254 return Status; 255 } 256 257 /** 258 Locates the requested handle(s) and returns them in Buffer. 259 260 @param SearchType The type of search to perform to locate the 261 handles 262 @param Protocol The protocol to search for 263 @param SearchKey Dependant on SearchType 264 @param BufferSize On input the size of Buffer. On output the 265 size of data returned. 266 @param Buffer The buffer to return the results in 267 268 @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is 269 returned in BufferSize. 270 @retval EFI_INVALID_PARAMETER Invalid parameter 271 @retval EFI_SUCCESS Successfully found the requested handle(s) and 272 returns them in Buffer. 273 274 **/ 275 EFI_STATUS 276 EFIAPI 277 SmmLocateHandle ( 278 IN EFI_LOCATE_SEARCH_TYPE SearchType, 279 IN EFI_GUID *Protocol OPTIONAL, 280 IN VOID *SearchKey OPTIONAL, 281 IN OUT UINTN *BufferSize, 282 OUT EFI_HANDLE *Buffer 283 ) 284 { 285 EFI_STATUS Status; 286 LOCATE_POSITION Position; 287 PROTOCOL_NOTIFY *ProtNotify; 288 CORE_GET_NEXT GetNext; 289 UINTN ResultSize; 290 IHANDLE *Handle; 291 IHANDLE **ResultBuffer; 292 VOID *Interface; 293 294 if (BufferSize == NULL) { 295 return EFI_INVALID_PARAMETER; 296 } 297 298 if ((*BufferSize > 0) && (Buffer == NULL)) { 299 return EFI_INVALID_PARAMETER; 300 } 301 302 GetNext = NULL; 303 304 // 305 // Set initial position 306 // 307 Position.Protocol = Protocol; 308 Position.SearchKey = SearchKey; 309 Position.Position = &gHandleList; 310 311 ResultSize = 0; 312 ResultBuffer = (IHANDLE **) Buffer; 313 Status = EFI_SUCCESS; 314 315 // 316 // Get the search function based on type 317 // 318 switch (SearchType) { 319 case AllHandles: 320 GetNext = SmmGetNextLocateAllHandles; 321 break; 322 323 case ByRegisterNotify: 324 GetNext = SmmGetNextLocateByRegisterNotify; 325 // 326 // Must have SearchKey for locate ByRegisterNotify 327 // 328 if (SearchKey == NULL) { 329 Status = EFI_INVALID_PARAMETER; 330 } 331 break; 332 333 case ByProtocol: 334 GetNext = SmmGetNextLocateByProtocol; 335 if (Protocol == NULL) { 336 Status = EFI_INVALID_PARAMETER; 337 break; 338 } 339 // 340 // Look up the protocol entry and set the head pointer 341 // 342 Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE); 343 if (Position.ProtEntry == NULL) { 344 Status = EFI_NOT_FOUND; 345 break; 346 } 347 Position.Position = &Position.ProtEntry->Protocols; 348 break; 349 350 default: 351 Status = EFI_INVALID_PARAMETER; 352 break; 353 } 354 355 if (EFI_ERROR(Status)) { 356 return Status; 357 } 358 359 // 360 // Enumerate out the matching handles 361 // 362 mEfiLocateHandleRequest += 1; 363 for (; ;) { 364 // 365 // Get the next handle. If no more handles, stop 366 // 367 Handle = GetNext (&Position, &Interface); 368 if (NULL == Handle) { 369 break; 370 } 371 372 // 373 // Increase the resulting buffer size, and if this handle 374 // fits return it 375 // 376 ResultSize += sizeof(Handle); 377 if (ResultSize <= *BufferSize) { 378 *ResultBuffer = Handle; 379 ResultBuffer += 1; 380 } 381 } 382 383 // 384 // If the result is a zero length buffer, then there were no 385 // matching handles 386 // 387 if (ResultSize == 0) { 388 Status = EFI_NOT_FOUND; 389 } else { 390 // 391 // Return the resulting buffer size. If it's larger than what 392 // was passed, then set the error code 393 // 394 if (ResultSize > *BufferSize) { 395 Status = EFI_BUFFER_TOO_SMALL; 396 } 397 398 *BufferSize = ResultSize; 399 400 if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) { 401 ASSERT (SearchKey != NULL); 402 // 403 // If this is a search by register notify and a handle was 404 // returned, update the register notification position 405 // 406 ProtNotify = SearchKey; 407 ProtNotify->Position = ProtNotify->Position->ForwardLink; 408 } 409 } 410 411 return Status; 412 } 413 414 /** 415 Function returns an array of handles that support the requested protocol 416 in a buffer allocated from pool. This is a version of SmmLocateHandle() 417 that allocates a buffer for the caller. 418 419 @param SearchType Specifies which handle(s) are to be returned. 420 @param Protocol Provides the protocol to search by. This 421 parameter is only valid for SearchType 422 ByProtocol. 423 @param SearchKey Supplies the search key depending on the 424 SearchType. 425 @param NumberHandles The number of handles returned in Buffer. 426 @param Buffer A pointer to the buffer to return the requested 427 array of handles that support Protocol. 428 429 @retval EFI_SUCCESS The result array of handles was returned. 430 @retval EFI_NOT_FOUND No handles match the search. 431 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the 432 matching results. 433 @retval EFI_INVALID_PARAMETER One or more parameters are not valid. 434 435 **/ 436 EFI_STATUS 437 EFIAPI 438 SmmLocateHandleBuffer ( 439 IN EFI_LOCATE_SEARCH_TYPE SearchType, 440 IN EFI_GUID *Protocol OPTIONAL, 441 IN VOID *SearchKey OPTIONAL, 442 IN OUT UINTN *NumberHandles, 443 OUT EFI_HANDLE **Buffer 444 ) 445 { 446 EFI_STATUS Status; 447 UINTN BufferSize; 448 449 if (NumberHandles == NULL) { 450 return EFI_INVALID_PARAMETER; 451 } 452 453 if (Buffer == NULL) { 454 return EFI_INVALID_PARAMETER; 455 } 456 457 BufferSize = 0; 458 *NumberHandles = 0; 459 *Buffer = NULL; 460 Status = SmmLocateHandle ( 461 SearchType, 462 Protocol, 463 SearchKey, 464 &BufferSize, 465 *Buffer 466 ); 467 // 468 // LocateHandleBuffer() returns incorrect status code if SearchType is 469 // invalid. 470 // 471 // Add code to correctly handle expected errors from SmmLocateHandle(). 472 // 473 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) { 474 if (Status != EFI_INVALID_PARAMETER) { 475 Status = EFI_NOT_FOUND; 476 } 477 return Status; 478 } 479 480 *Buffer = AllocatePool (BufferSize); 481 if (*Buffer == NULL) { 482 return EFI_OUT_OF_RESOURCES; 483 } 484 485 Status = SmmLocateHandle ( 486 SearchType, 487 Protocol, 488 SearchKey, 489 &BufferSize, 490 *Buffer 491 ); 492 493 *NumberHandles = BufferSize / sizeof(EFI_HANDLE); 494 if (EFI_ERROR(Status)) { 495 *NumberHandles = 0; 496 } 497 498 return Status; 499 } 500