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