]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Locate.c
MdeModulePkg PiSmmCore: Set ForwardLink to NULL in RemoveOldEntry()
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Locate.c
1 /** @file
2 Locate handle functions
3
4 Copyright (c) 2009 - 2017, 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) || (Protocol == NULL)) {
209 return EFI_INVALID_PARAMETER;
210 }
211
212 *Interface = NULL;
213 Status = EFI_SUCCESS;
214
215 //
216 // Set initial position
217 //
218 Position.Protocol = Protocol;
219 Position.SearchKey = Registration;
220 Position.Position = &gHandleList;
221
222 mEfiLocateHandleRequest += 1;
223
224 if (Registration == NULL) {
225 //
226 // Look up the protocol entry and set the head pointer
227 //
228 Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
229 if (Position.ProtEntry == NULL) {
230 return EFI_NOT_FOUND;
231 }
232 Position.Position = &Position.ProtEntry->Protocols;
233
234 Handle = SmmGetNextLocateByProtocol (&Position, Interface);
235 } else {
236 Handle = SmmGetNextLocateByRegisterNotify (&Position, Interface);
237 }
238
239 if (Handle == NULL) {
240 Status = EFI_NOT_FOUND;
241 } else if (Registration != NULL) {
242 //
243 // If this is a search by register notify and a handle was
244 // returned, update the register notification position
245 //
246 ProtNotify = Registration;
247 ProtNotify->Position = ProtNotify->Position->ForwardLink;
248 }
249
250 return Status;
251 }
252
253 /**
254 Locates the requested handle(s) and returns them in Buffer.
255
256 @param SearchType The type of search to perform to locate the
257 handles
258 @param Protocol The protocol to search for
259 @param SearchKey Dependant on SearchType
260 @param BufferSize On input the size of Buffer. On output the
261 size of data returned.
262 @param Buffer The buffer to return the results in
263
264 @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
265 returned in BufferSize.
266 @retval EFI_INVALID_PARAMETER Invalid parameter
267 @retval EFI_SUCCESS Successfully found the requested handle(s) and
268 returns them in Buffer.
269
270 **/
271 EFI_STATUS
272 EFIAPI
273 SmmLocateHandle (
274 IN EFI_LOCATE_SEARCH_TYPE SearchType,
275 IN EFI_GUID *Protocol OPTIONAL,
276 IN VOID *SearchKey OPTIONAL,
277 IN OUT UINTN *BufferSize,
278 OUT EFI_HANDLE *Buffer
279 )
280 {
281 EFI_STATUS Status;
282 LOCATE_POSITION Position;
283 PROTOCOL_NOTIFY *ProtNotify;
284 CORE_GET_NEXT GetNext;
285 UINTN ResultSize;
286 IHANDLE *Handle;
287 IHANDLE **ResultBuffer;
288 VOID *Interface;
289
290 if (BufferSize == NULL) {
291 return EFI_INVALID_PARAMETER;
292 }
293
294 if ((*BufferSize > 0) && (Buffer == NULL)) {
295 return EFI_INVALID_PARAMETER;
296 }
297
298 GetNext = NULL;
299
300 //
301 // Set initial position
302 //
303 Position.Protocol = Protocol;
304 Position.SearchKey = SearchKey;
305 Position.Position = &gHandleList;
306
307 ResultSize = 0;
308 ResultBuffer = (IHANDLE **) Buffer;
309 Status = EFI_SUCCESS;
310
311 //
312 // Get the search function based on type
313 //
314 switch (SearchType) {
315 case AllHandles:
316 GetNext = SmmGetNextLocateAllHandles;
317 break;
318
319 case ByRegisterNotify:
320 GetNext = SmmGetNextLocateByRegisterNotify;
321 //
322 // Must have SearchKey for locate ByRegisterNotify
323 //
324 if (SearchKey == NULL) {
325 Status = EFI_INVALID_PARAMETER;
326 }
327 break;
328
329 case ByProtocol:
330 GetNext = SmmGetNextLocateByProtocol;
331 if (Protocol == NULL) {
332 Status = EFI_INVALID_PARAMETER;
333 break;
334 }
335 //
336 // Look up the protocol entry and set the head pointer
337 //
338 Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
339 if (Position.ProtEntry == NULL) {
340 Status = EFI_NOT_FOUND;
341 break;
342 }
343 Position.Position = &Position.ProtEntry->Protocols;
344 break;
345
346 default:
347 Status = EFI_INVALID_PARAMETER;
348 break;
349 }
350
351 if (EFI_ERROR(Status)) {
352 return Status;
353 }
354
355 //
356 // Enumerate out the matching handles
357 //
358 mEfiLocateHandleRequest += 1;
359 for (; ;) {
360 //
361 // Get the next handle. If no more handles, stop
362 //
363 Handle = GetNext (&Position, &Interface);
364 if (NULL == Handle) {
365 break;
366 }
367
368 //
369 // Increase the resulting buffer size, and if this handle
370 // fits return it
371 //
372 ResultSize += sizeof(Handle);
373 if (ResultSize <= *BufferSize) {
374 *ResultBuffer = Handle;
375 ResultBuffer += 1;
376 }
377 }
378
379 //
380 // If the result is a zero length buffer, then there were no
381 // matching handles
382 //
383 if (ResultSize == 0) {
384 Status = EFI_NOT_FOUND;
385 } else {
386 //
387 // Return the resulting buffer size. If it's larger than what
388 // was passed, then set the error code
389 //
390 if (ResultSize > *BufferSize) {
391 Status = EFI_BUFFER_TOO_SMALL;
392 }
393
394 *BufferSize = ResultSize;
395
396 if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {
397 ASSERT (SearchKey != NULL);
398 //
399 // If this is a search by register notify and a handle was
400 // returned, update the register notification position
401 //
402 ProtNotify = SearchKey;
403 ProtNotify->Position = ProtNotify->Position->ForwardLink;
404 }
405 }
406
407 return Status;
408 }
409
410 /**
411 Function returns an array of handles that support the requested protocol
412 in a buffer allocated from pool. This is a version of SmmLocateHandle()
413 that allocates a buffer for the caller.
414
415 @param SearchType Specifies which handle(s) are to be returned.
416 @param Protocol Provides the protocol to search by. This
417 parameter is only valid for SearchType
418 ByProtocol.
419 @param SearchKey Supplies the search key depending on the
420 SearchType.
421 @param NumberHandles The number of handles returned in Buffer.
422 @param Buffer A pointer to the buffer to return the requested
423 array of handles that support Protocol.
424
425 @retval EFI_SUCCESS The result array of handles was returned.
426 @retval EFI_NOT_FOUND No handles match the search.
427 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
428 matching results.
429 @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
430
431 **/
432 EFI_STATUS
433 EFIAPI
434 SmmLocateHandleBuffer (
435 IN EFI_LOCATE_SEARCH_TYPE SearchType,
436 IN EFI_GUID *Protocol OPTIONAL,
437 IN VOID *SearchKey OPTIONAL,
438 IN OUT UINTN *NumberHandles,
439 OUT EFI_HANDLE **Buffer
440 )
441 {
442 EFI_STATUS Status;
443 UINTN BufferSize;
444
445 if (NumberHandles == NULL) {
446 return EFI_INVALID_PARAMETER;
447 }
448
449 if (Buffer == NULL) {
450 return EFI_INVALID_PARAMETER;
451 }
452
453 BufferSize = 0;
454 *NumberHandles = 0;
455 *Buffer = NULL;
456 Status = SmmLocateHandle (
457 SearchType,
458 Protocol,
459 SearchKey,
460 &BufferSize,
461 *Buffer
462 );
463 //
464 // LocateHandleBuffer() returns incorrect status code if SearchType is
465 // invalid.
466 //
467 // Add code to correctly handle expected errors from SmmLocateHandle().
468 //
469 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
470 if (Status != EFI_INVALID_PARAMETER) {
471 Status = EFI_NOT_FOUND;
472 }
473 return Status;
474 }
475
476 *Buffer = AllocatePool (BufferSize);
477 if (*Buffer == NULL) {
478 return EFI_OUT_OF_RESOURCES;
479 }
480
481 Status = SmmLocateHandle (
482 SearchType,
483 Protocol,
484 SearchKey,
485 &BufferSize,
486 *Buffer
487 );
488
489 *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
490 if (EFI_ERROR(Status)) {
491 *NumberHandles = 0;
492 }
493
494 return Status;
495 }