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