locate.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. locate.c
  5. Abstract:
  6. This module implements support for locating handles.
  7. Author:
  8. Evan Green 5-Mar-2014
  9. Environment:
  10. Firmware
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "ueficore.h"
  16. //
  17. // ---------------------------------------------------------------- Definitions
  18. //
  19. //
  20. // ------------------------------------------------------ Data Type Definitions
  21. //
  22. typedef struct _EFI_LOCATE_POSITION {
  23. EFI_GUID *Protocol;
  24. VOID *SearchKey;
  25. PLIST_ENTRY Position;
  26. PEFI_PROTOCOL_ENTRY ProtocolEntry;
  27. } EFI_LOCATE_POSITION, *PEFI_LOCATE_POSITION;
  28. typedef
  29. PEFI_HANDLE_DATA
  30. (*PEFI_CORE_GET_NEXT_HANDLE) (
  31. PEFI_LOCATE_POSITION Position,
  32. VOID **Interface
  33. );
  34. /*++
  35. Routine Description:
  36. This routine gets the next handle when searching for handles.
  37. Arguments:
  38. Position - Supplies a pointer to the current position. This will be updated.
  39. Interface - Supplies a pointer where the interface structure for the
  40. matching protocol will be returned.
  41. Return Value:
  42. EFI_SUCCESS if a handle was returned.
  43. EFI_NOT_FOUND if no handles match the search.
  44. EFI_INVALID_PARAMETER if the protocol is NULL, device path is NULL, or a
  45. handle matched and the device is NULL.
  46. --*/
  47. //
  48. // ----------------------------------------------- Internal Function Prototypes
  49. //
  50. PEFI_HANDLE_DATA
  51. EfipCoreGetNextHandle (
  52. PEFI_LOCATE_POSITION Position,
  53. VOID **Interface
  54. );
  55. PEFI_HANDLE_DATA
  56. EfipCoreGetNextHandleByRegisterNotify (
  57. PEFI_LOCATE_POSITION Position,
  58. VOID **Interface
  59. );
  60. PEFI_HANDLE_DATA
  61. EfipCoreGetNextHandleByProtocol (
  62. PEFI_LOCATE_POSITION Position,
  63. VOID **Interface
  64. );
  65. //
  66. // -------------------------------------------------------------------- Globals
  67. //
  68. UINTN EfiLocateHandleRequest;
  69. //
  70. // ------------------------------------------------------------------ Functions
  71. //
  72. EFIAPI
  73. EFI_STATUS
  74. EfiCoreLocateDevicePath (
  75. EFI_GUID *Protocol,
  76. EFI_DEVICE_PATH_PROTOCOL **DevicePath,
  77. EFI_HANDLE *Device
  78. )
  79. /*++
  80. Routine Description:
  81. This routine attempts to locate the handle to a device on the device path
  82. that supports the specified protocol.
  83. Arguments:
  84. Protocol - Supplies a pointer to the protocol to search for.
  85. DevicePath - Supplies a pointer that on input contains a pointer to the
  86. device path. On output, the path pointer is modified to point to the
  87. remaining part of the device path.
  88. Device - Supplies a pointer where the handle of the device will be
  89. returned.
  90. Return Value:
  91. EFI_SUCCESS if a handle was returned.
  92. EFI_NOT_FOUND if no handles match the search.
  93. EFI_INVALID_PARAMETER if the protocol is NULL, device path is NULL, or a
  94. handle matched and the device is NULL.
  95. --*/
  96. {
  97. EFI_HANDLE BestDevice;
  98. INTN BestMatch;
  99. EFI_HANDLE Handle;
  100. UINTN HandleCount;
  101. EFI_HANDLE *Handles;
  102. UINTN Index;
  103. EFI_DEVICE_PATH_PROTOCOL *SearchPath;
  104. INTN Size;
  105. EFI_DEVICE_PATH_PROTOCOL *SourcePath;
  106. INTN SourceSize;
  107. EFI_STATUS Status;
  108. if ((Protocol == NULL) || (DevicePath == NULL) || (*DevicePath == NULL)) {
  109. return EFI_INVALID_PARAMETER;
  110. }
  111. BestDevice = NULL;
  112. SourcePath = *DevicePath;
  113. SearchPath = SourcePath;
  114. while (EfiCoreIsDevicePathEnd(SearchPath) == FALSE) {
  115. //
  116. // If the device path is a multi-instance device path, this function
  117. // will operate on the first instance.
  118. //
  119. if (EfiCoreIsDevicePathEndInstance(SearchPath) != FALSE) {
  120. break;
  121. }
  122. SearchPath = EfiCoreGetNextDevicePathNode(SearchPath);
  123. }
  124. SourceSize = (UINTN)SearchPath - (UINTN)SourcePath;
  125. //
  126. // Get a list of all handles that support the given protocol.
  127. //
  128. Status = EfiCoreLocateHandleBuffer(ByProtocol,
  129. Protocol,
  130. NULL,
  131. &HandleCount,
  132. &Handles);
  133. if ((EFI_ERROR(Status)) || (HandleCount == 0)) {
  134. return EFI_NOT_FOUND;
  135. }
  136. BestMatch = -1;
  137. for (Index = 0; Index < HandleCount; Index += 1) {
  138. Handle = Handles[Index];
  139. Status = EfiCoreHandleProtocol(Handle,
  140. &EfiDevicePathProtocolGuid,
  141. (VOID **)&SearchPath);
  142. if (EFI_ERROR(Status)) {
  143. continue;
  144. }
  145. //
  146. // Check if the device path is the first part of the source path.
  147. //
  148. Size = EfiCoreGetDevicePathSize(SearchPath) -
  149. sizeof(EFI_DEVICE_PATH_PROTOCOL);
  150. ASSERT(Size >= 0);
  151. if ((Size <= SourceSize) &&
  152. (EfiCoreCompareMemory(SourcePath, SearchPath, (UINTN)Size) == 0)) {
  153. //
  154. // If the size is equal to the best match, then there is a
  155. // duplicate device path for two different device handles.
  156. //
  157. ASSERT(Size != BestMatch);
  158. if (Size > BestMatch) {
  159. BestMatch = Size;
  160. BestDevice = Handle;
  161. }
  162. }
  163. }
  164. EfiCoreFreePool(Handles);
  165. //
  166. // If there wasn't any match, then no parts of the device path where found.
  167. // This is unexpected, since there should be a "root level" device path
  168. // in the system.
  169. //
  170. if (BestMatch == -1) {
  171. return EFI_NOT_FOUND;
  172. }
  173. if (Device == NULL) {
  174. return EFI_INVALID_PARAMETER;
  175. }
  176. *Device = BestDevice;
  177. //
  178. // Return the remaining part of the device path.
  179. //
  180. *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)SourcePath) +
  181. BestMatch);
  182. return EFI_SUCCESS;
  183. }
  184. EFIAPI
  185. EFI_STATUS
  186. EfiCoreLocateHandleBuffer (
  187. EFI_LOCATE_SEARCH_TYPE SearchType,
  188. EFI_GUID *Protocol,
  189. VOID *SearchKey,
  190. UINTN *HandleCount,
  191. EFI_HANDLE **Buffer
  192. )
  193. /*++
  194. Routine Description:
  195. This routine returns an array of handles that support the requested
  196. protocol in a buffer allocated from pool.
  197. Arguments:
  198. SearchType - Supplies the search behavior.
  199. Protocol - Supplies a pointer to the protocol to search by.
  200. SearchKey - Supplies a pointer to the search key.
  201. HandleCount - Supplies a pointer where the number of handles will be
  202. returned.
  203. Buffer - Supplies a pointer where an array will be returned containing the
  204. requested handles.
  205. Return Value:
  206. EFI_SUCCESS on success.
  207. EFI_NOT_FOUND if no handles match the search.
  208. EFI_INVALID_PARAMETER if the handle count or buffer is NULL.
  209. EFI_OUT_OF_RESOURCES if an allocation failed.
  210. --*/
  211. {
  212. UINTN BufferSize;
  213. EFI_STATUS Status;
  214. if ((HandleCount == NULL) || (Buffer == NULL)) {
  215. return EFI_INVALID_PARAMETER;
  216. }
  217. BufferSize = 0;
  218. *HandleCount = 0;
  219. *Buffer = NULL;
  220. Status = EfiCoreLocateHandle(SearchType,
  221. Protocol,
  222. SearchKey,
  223. &BufferSize,
  224. *Buffer);
  225. if ((EFI_ERROR(Status)) && (Status != EFI_BUFFER_TOO_SMALL)) {
  226. if (Status != EFI_INVALID_PARAMETER) {
  227. Status = EFI_NOT_FOUND;
  228. }
  229. return Status;
  230. }
  231. *Buffer = EfiCoreAllocateBootPool(BufferSize);
  232. if (*Buffer == NULL) {
  233. return EFI_OUT_OF_RESOURCES;
  234. }
  235. Status = EfiCoreLocateHandle(SearchType,
  236. Protocol,
  237. SearchKey,
  238. &BufferSize,
  239. *Buffer);
  240. *HandleCount = BufferSize / sizeof(EFI_HANDLE);
  241. if (EFI_ERROR(Status)) {
  242. *HandleCount = 0;
  243. }
  244. return Status;
  245. }
  246. EFIAPI
  247. EFI_STATUS
  248. EfiCoreLocateHandle (
  249. EFI_LOCATE_SEARCH_TYPE SearchType,
  250. EFI_GUID *Protocol,
  251. VOID *SearchKey,
  252. UINTN *BufferSize,
  253. EFI_HANDLE *Buffer
  254. )
  255. /*++
  256. Routine Description:
  257. This routine returns an array of handles that support a specified protocol.
  258. Arguments:
  259. SearchType - Supplies which handle(s) are to be returned.
  260. Protocol - Supplies an optional pointer to the protocols to search by.
  261. SearchKey - Supplies an optional pointer to the search key.
  262. BufferSize - Supplies a pointer that on input contains the size of the
  263. result buffer in bytes. On output, the size of the result array will be
  264. returned (even if the buffer was too small).
  265. Buffer - Supplies a pointer where the results will be returned.
  266. Return Value:
  267. EFI_SUCCESS on success.
  268. EFI_NOT_FOUND if no handles match the search.
  269. EFI_BUFFER_TOO_SMALL if the given buffer wasn't big enough to hold all the
  270. results.
  271. EFI_INVALID_PARAMETER if the serach type is invalid, one of the parameters
  272. required by the given search type was NULL, one or more matches are found
  273. and the buffer size is NULL, or the buffer size is large enough and the
  274. buffer is NULL.
  275. --*/
  276. {
  277. PEFI_CORE_GET_NEXT_HANDLE GetNextHandleFunction;
  278. PEFI_HANDLE_DATA Handle;
  279. VOID *Interface;
  280. EFI_LOCATE_POSITION Position;
  281. PEFI_PROTOCOL_NOTIFY ProtocolNotify;
  282. PEFI_HANDLE_DATA *ResultBuffer;
  283. UINTN ResultSize;
  284. EFI_STATUS Status;
  285. if ((BufferSize == NULL) || ((*BufferSize > 0) && (Buffer == NULL))) {
  286. return EFI_INVALID_PARAMETER;
  287. }
  288. GetNextHandleFunction = NULL;
  289. Position.Protocol = Protocol;
  290. Position.SearchKey = SearchKey;
  291. Position.Position = &EfiHandleList;
  292. ResultSize = 0;
  293. ResultBuffer = (PEFI_HANDLE_DATA *)Buffer;
  294. Status = EFI_SUCCESS;
  295. EfiCoreAcquireLock(&EfiProtocolDatabaseLock);
  296. switch (SearchType) {
  297. case AllHandles:
  298. GetNextHandleFunction = EfipCoreGetNextHandle;
  299. break;
  300. case ByRegisterNotify:
  301. GetNextHandleFunction = EfipCoreGetNextHandleByRegisterNotify;
  302. if (SearchKey == NULL) {
  303. Status = EFI_INVALID_PARAMETER;
  304. break;
  305. }
  306. break;
  307. case ByProtocol:
  308. GetNextHandleFunction = EfipCoreGetNextHandleByProtocol;
  309. if (Protocol == NULL) {
  310. Status = EFI_INVALID_PARAMETER;
  311. break;
  312. }
  313. Position.ProtocolEntry = EfipCoreFindProtocolEntry(Protocol, FALSE);
  314. if (Position.ProtocolEntry == NULL) {
  315. Status = EFI_NOT_FOUND;
  316. break;
  317. }
  318. Position.Position = &(Position.ProtocolEntry->ProtocolList);
  319. break;
  320. default:
  321. Status = EFI_INVALID_PARAMETER;
  322. break;
  323. }
  324. if (EFI_ERROR(Status)) {
  325. EfiCoreReleaseLock(&EfiProtocolDatabaseLock);
  326. return Status;
  327. }
  328. ASSERT(GetNextHandleFunction != NULL);
  329. EfiLocateHandleRequest += 1;
  330. while (TRUE) {
  331. //
  332. // Get the next handle.
  333. //
  334. Handle = GetNextHandleFunction(&Position, &Interface);
  335. if (Handle == NULL) {
  336. break;
  337. }
  338. //
  339. // Increase the resulting buffer size, and if this handle fits, return
  340. // it.
  341. //
  342. ResultSize += sizeof(Handle);
  343. if (ResultSize <= *BufferSize) {
  344. *ResultBuffer = Handle;
  345. ResultBuffer += 1;
  346. }
  347. }
  348. //
  349. // If the result is a zero length buffer, then there were no matching
  350. // handles.
  351. //
  352. if (ResultSize == 0) {
  353. Status = EFI_NOT_FOUND;
  354. } else {
  355. //
  356. // Return the resulting buffer size. If it's larger than what was
  357. // passed in, then set the error code.
  358. //
  359. if (ResultSize > *BufferSize) {
  360. Status = EFI_BUFFER_TOO_SMALL;
  361. }
  362. *BufferSize = ResultSize;
  363. //
  364. // If this is a search by register notify and a handle was returned,
  365. // update the register notification position.
  366. //
  367. if ((SearchType == ByRegisterNotify) && (!EFI_ERROR(Status))) {
  368. ASSERT(SearchKey != NULL);
  369. ProtocolNotify = SearchKey;
  370. ProtocolNotify->Position = ProtocolNotify->Position->Next;
  371. }
  372. }
  373. EfiCoreReleaseLock(&EfiProtocolDatabaseLock);
  374. return Status;
  375. }
  376. EFIAPI
  377. EFI_STATUS
  378. EfiCoreLocateProtocol (
  379. EFI_GUID *Protocol,
  380. VOID *Registration,
  381. VOID **Interface
  382. )
  383. /*++
  384. Routine Description:
  385. This routine returns the first protocol instance that matches the given
  386. protocol.
  387. Arguments:
  388. Protocol - Supplies a pointer to the protocol to search by.
  389. Registration - Supplies a pointer to an optional registration key
  390. returned from RegisterProtocolNotify.
  391. Interface - Supplies a pointer where a pointer to the first interface that
  392. matches will be returned on success.
  393. Return Value:
  394. EFI_SUCCESS on success.
  395. EFI_NOT_FOUND if no protocol instances matched the search.
  396. EFI_INVALID_PARAMETER if the interface is NULL.
  397. --*/
  398. {
  399. PEFI_HANDLE_DATA Handle;
  400. EFI_LOCATE_POSITION Position;
  401. PEFI_PROTOCOL_NOTIFY ProtocolNotify;
  402. EFI_STATUS Status;
  403. if (Interface == NULL) {
  404. return EFI_INVALID_PARAMETER;
  405. }
  406. if (Protocol == NULL) {
  407. return EFI_NOT_FOUND;
  408. }
  409. *Interface = NULL;
  410. Status = EFI_SUCCESS;
  411. Position.Protocol = Protocol;
  412. Position.SearchKey = Registration;
  413. Position.Position = &EfiHandleList;
  414. EfiCoreAcquireLock(&EfiProtocolDatabaseLock);
  415. EfiLocateHandleRequest += 1;
  416. if (Registration != NULL) {
  417. Position.ProtocolEntry = EfipCoreFindProtocolEntry(Protocol, FALSE);
  418. if (Position.ProtocolEntry == NULL) {
  419. Status = EFI_NOT_FOUND;
  420. goto CoreLocateProtocolEnd;
  421. }
  422. Position.Position = &(Position.ProtocolEntry->ProtocolList);
  423. Handle = EfipCoreGetNextHandleByProtocol(&Position, Interface);
  424. } else {
  425. Handle = EfipCoreGetNextHandleByRegisterNotify(&Position, Interface);
  426. }
  427. if (Handle == NULL) {
  428. Status = EFI_NOT_FOUND;
  429. //
  430. // If this is a search by register notify and a handle was returned,
  431. // update the register notify position.
  432. //
  433. } else if (Registration != NULL) {
  434. ProtocolNotify = Registration;
  435. ProtocolNotify->Position = ProtocolNotify->Position->Next;
  436. }
  437. CoreLocateProtocolEnd:
  438. EfiCoreReleaseLock(&EfiProtocolDatabaseLock);
  439. return Status;
  440. }
  441. //
  442. // --------------------------------------------------------- Internal Functions
  443. //
  444. PEFI_HANDLE_DATA
  445. EfipCoreGetNextHandle (
  446. PEFI_LOCATE_POSITION Position,
  447. VOID **Interface
  448. )
  449. /*++
  450. Routine Description:
  451. This routine gets the next handle when searching for all handles.
  452. Arguments:
  453. Position - Supplies a pointer to the current position. This will be updated.
  454. Interface - Supplies a pointer where the interface structure for the
  455. matching protocol will be returned.
  456. Return Value:
  457. EFI_SUCCESS if a handle was returned.
  458. EFI_NOT_FOUND if no handles match the search.
  459. EFI_INVALID_PARAMETER if the protocol is NULL, device path is NULL, or a
  460. handle matched and the device is NULL.
  461. --*/
  462. {
  463. PEFI_HANDLE_DATA Handle;
  464. Position->Position = Position->Position->Next;
  465. Handle = NULL;
  466. *Interface = NULL;
  467. if (Position->Position != &EfiHandleList) {
  468. Handle = LIST_VALUE(Position->Position, EFI_HANDLE_DATA, ListEntry);
  469. ASSERT(Handle->Magic == EFI_HANDLE_MAGIC);
  470. }
  471. return Handle;
  472. }
  473. PEFI_HANDLE_DATA
  474. EfipCoreGetNextHandleByRegisterNotify (
  475. PEFI_LOCATE_POSITION Position,
  476. VOID **Interface
  477. )
  478. /*++
  479. Routine Description:
  480. This routine gets the next handle when searching for register protocol
  481. notifies.
  482. Arguments:
  483. Position - Supplies a pointer to the current position. This will be updated.
  484. Interface - Supplies a pointer where the interface structure for the
  485. matching protocol will be returned.
  486. Return Value:
  487. EFI_SUCCESS if a handle was returned.
  488. EFI_NOT_FOUND if no handles match the search.
  489. EFI_INVALID_PARAMETER if the protocol is NULL, device path is NULL, or a
  490. handle matched and the device is NULL.
  491. --*/
  492. {
  493. PLIST_ENTRY CurrentEntry;
  494. PEFI_HANDLE_DATA Handle;
  495. PEFI_PROTOCOL_INTERFACE ProtocolInterface;
  496. PEFI_PROTOCOL_NOTIFY ProtocolNotify;
  497. Handle = NULL;
  498. *Interface = NULL;
  499. ProtocolNotify = Position->SearchKey;
  500. if (ProtocolNotify != NULL) {
  501. ASSERT(ProtocolNotify->Magic == EFI_PROTOCOL_NOTIFY_MAGIC);
  502. Position->SearchKey = NULL;
  503. //
  504. // If not at the end of the list, get the next handle.
  505. //
  506. CurrentEntry = ProtocolNotify->Position->Next;
  507. if (CurrentEntry != &(ProtocolNotify->Protocol->ProtocolList)) {
  508. ProtocolInterface = LIST_VALUE(CurrentEntry,
  509. EFI_PROTOCOL_INTERFACE,
  510. ProtocolListEntry);
  511. ASSERT(ProtocolInterface->Magic == EFI_PROTOCOL_INTERFACE_MAGIC);
  512. Handle = ProtocolInterface->Handle;
  513. *Interface = ProtocolInterface->Interface;
  514. }
  515. }
  516. return Handle;
  517. }
  518. PEFI_HANDLE_DATA
  519. EfipCoreGetNextHandleByProtocol (
  520. PEFI_LOCATE_POSITION Position,
  521. VOID **Interface
  522. )
  523. /*++
  524. Routine Description:
  525. This routine gets the next handle when searching for a given protocol.
  526. Arguments:
  527. Position - Supplies a pointer to the current position. This will be updated.
  528. Interface - Supplies a pointer where the interface structure for the
  529. matching protocol will be returned.
  530. Return Value:
  531. EFI_SUCCESS if a handle was returned.
  532. EFI_NOT_FOUND if no handles match the search.
  533. EFI_INVALID_PARAMETER if the protocol is NULL, device path is NULL, or a
  534. handle matched and the device is NULL.
  535. --*/
  536. {
  537. PLIST_ENTRY CurrentEntry;
  538. PEFI_HANDLE_DATA Handle;
  539. PEFI_PROTOCOL_INTERFACE ProtocolInterface;
  540. Handle = NULL;
  541. *Interface = NULL;
  542. while (TRUE) {
  543. CurrentEntry = Position->Position->Next;
  544. Position->Position = CurrentEntry;
  545. //
  546. // If at the end, stop.
  547. //
  548. if (CurrentEntry == &(Position->ProtocolEntry->ProtocolList)) {
  549. Handle = NULL;
  550. break;
  551. }
  552. //
  553. // Get the handle.
  554. //
  555. ProtocolInterface = LIST_VALUE(CurrentEntry,
  556. EFI_PROTOCOL_INTERFACE,
  557. ProtocolListEntry);
  558. ASSERT(ProtocolInterface->Magic == EFI_PROTOCOL_INTERFACE_MAGIC);
  559. Handle = ProtocolInterface->Handle;
  560. *Interface = ProtocolInterface->Interface;
  561. //
  562. // If this handle has not been returned this request, then return it
  563. // now.
  564. //
  565. if (Handle->LocateRequest != EfiLocateHandleRequest) {
  566. Handle->LocateRequest = EfiLocateHandleRequest;
  567. break;
  568. }
  569. }
  570. return Handle;
  571. }