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