]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Locate.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 search 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
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 search 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 SmmGetNextLocateByRegisterNotify (
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
115 return Handle;
116 }
117
118 /**
119 Routine to get the next Handle, when you are searching for a given protocol.
120
121 @param Position Information about which Handle to search for.
122 @param Interface Return the interface structure for the matching
123 protocol.
124
125 @return An pointer to IHANDLE if the next Position is not the end of the list.
126 Otherwise,NULL is returned.
127
128 **/
129 IHANDLE *
130 SmmGetNextLocateByProtocol (
131 IN OUT LOCATE_POSITION *Position,
132 OUT VOID **Interface
133 )
134 {
135 IHANDLE *Handle;
136 LIST_ENTRY *Link;
137 PROTOCOL_INTERFACE *Prot;
138
139 Handle = NULL;
140 *Interface = NULL;
141 for ( ; ;) {
142 //
143 // Next entry
144 //
145 Link = Position->Position->ForwardLink;
146 Position->Position = Link;
147
148 //
149 // If not at the end, return the handle
150 //
151 if (Link == &Position->ProtEntry->Protocols) {
152 Handle = NULL;
153 break;
154 }
155
156 //
157 // Get the handle
158 //
159 Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
160 Handle = Prot->Handle;
161 *Interface = Prot->Interface;
162
163 //
164 // If this handle has not been returned this request, then
165 // return it now
166 //
167 if (Handle->LocateRequest != mEfiLocateHandleRequest) {
168 Handle->LocateRequest = mEfiLocateHandleRequest;
169 break;
170 }
171 }
172
173 return Handle;
174 }
175
176 /**
177 Return the first Protocol Interface that matches the Protocol GUID. If
178 Registration is pasased in return a Protocol Instance that was just add
179 to the system. If Registration is NULL return the first Protocol Interface
180 you find.
181
182 @param Protocol The protocol to search for
183 @param Registration Optional Registration Key returned from
184 RegisterProtocolNotify()
185 @param Interface Return the Protocol interface (instance).
186
187 @retval EFI_SUCCESS If a valid Interface is returned
188 @retval EFI_INVALID_PARAMETER Invalid parameter
189 @retval EFI_NOT_FOUND Protocol interface not found
190
191 **/
192 EFI_STATUS
193 EFIAPI
194 SmmLocateProtocol (
195 IN EFI_GUID *Protocol,
196 IN VOID *Registration OPTIONAL,
197 OUT VOID **Interface
198 )
199 {
200 EFI_STATUS Status;
201 LOCATE_POSITION Position;
202 PROTOCOL_NOTIFY *ProtNotify;
203 IHANDLE *Handle;
204
205 if ((Interface == NULL) || (Protocol == NULL)) {
206 return EFI_INVALID_PARAMETER;
207 }
208
209 *Interface = NULL;
210 Status = EFI_SUCCESS;
211
212 //
213 // Set initial position
214 //
215 Position.Protocol = Protocol;
216 Position.SearchKey = Registration;
217 Position.Position = &gHandleList;
218
219 mEfiLocateHandleRequest += 1;
220
221 if (Registration == NULL) {
222 //
223 // Look up the protocol entry and set the head pointer
224 //
225 Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
226 if (Position.ProtEntry == NULL) {
227 return EFI_NOT_FOUND;
228 }
229
230 Position.Position = &Position.ProtEntry->Protocols;
231
232 Handle = SmmGetNextLocateByProtocol (&Position, Interface);
233 } else {
234 Handle = SmmGetNextLocateByRegisterNotify (&Position, Interface);
235 }
236
237 if (Handle == NULL) {
238 Status = EFI_NOT_FOUND;
239 } else if (Registration != NULL) {
240 //
241 // If this is a search by register notify and a handle was
242 // returned, update the register notification position
243 //
244 ProtNotify = Registration;
245 ProtNotify->Position = ProtNotify->Position->ForwardLink;
246 }
247
248 return Status;
249 }
250
251 /**
252 Locates the requested handle(s) and returns them in Buffer.
253
254 @param SearchType The type of search to perform to locate the
255 handles
256 @param Protocol The protocol to search for
257 @param SearchKey Dependant on SearchType
258 @param BufferSize On input the size of Buffer. On output the
259 size of data returned.
260 @param Buffer The buffer to return the results in
261
262 @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
263 returned in BufferSize.
264 @retval EFI_INVALID_PARAMETER Invalid parameter
265 @retval EFI_SUCCESS Successfully found the requested handle(s) and
266 returns them in Buffer.
267
268 **/
269 EFI_STATUS
270 EFIAPI
271 SmmLocateHandle (
272 IN EFI_LOCATE_SEARCH_TYPE SearchType,
273 IN EFI_GUID *Protocol OPTIONAL,
274 IN VOID *SearchKey OPTIONAL,
275 IN OUT UINTN *BufferSize,
276 OUT EFI_HANDLE *Buffer
277 )
278 {
279 EFI_STATUS Status;
280 LOCATE_POSITION Position;
281 PROTOCOL_NOTIFY *ProtNotify;
282 CORE_GET_NEXT GetNext;
283 UINTN ResultSize;
284 IHANDLE *Handle;
285 IHANDLE **ResultBuffer;
286 VOID *Interface;
287
288 if (BufferSize == NULL) {
289 return EFI_INVALID_PARAMETER;
290 }
291
292 if ((*BufferSize > 0) && (Buffer == NULL)) {
293 return EFI_INVALID_PARAMETER;
294 }
295
296 GetNext = NULL;
297
298 //
299 // Set initial position
300 //
301 Position.Protocol = Protocol;
302 Position.SearchKey = SearchKey;
303 Position.Position = &gHandleList;
304
305 ResultSize = 0;
306 ResultBuffer = (IHANDLE **)Buffer;
307 Status = EFI_SUCCESS;
308
309 //
310 // Get the search function based on type
311 //
312 switch (SearchType) {
313 case AllHandles:
314 GetNext = SmmGetNextLocateAllHandles;
315 break;
316
317 case ByRegisterNotify:
318 GetNext = SmmGetNextLocateByRegisterNotify;
319 //
320 // Must have SearchKey for locate ByRegisterNotify
321 //
322 if (SearchKey == NULL) {
323 Status = EFI_INVALID_PARAMETER;
324 }
325
326 break;
327
328 case ByProtocol:
329 GetNext = SmmGetNextLocateByProtocol;
330 if (Protocol == NULL) {
331 Status = EFI_INVALID_PARAMETER;
332 break;
333 }
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
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 SmmLocateHandle()
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 SmmLocateHandleBuffer (
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 = SmmLocateHandle (
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 SmmLocateHandle().
469 //
470 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
471 if (Status != EFI_INVALID_PARAMETER) {
472 Status = EFI_NOT_FOUND;
473 }
474
475 return Status;
476 }
477
478 *Buffer = AllocatePool (BufferSize);
479 if (*Buffer == NULL) {
480 return EFI_OUT_OF_RESOURCES;
481 }
482
483 Status = SmmLocateHandle (
484 SearchType,
485 Protocol,
486 SearchKey,
487 &BufferSize,
488 *Buffer
489 );
490
491 *NumberHandles = BufferSize / sizeof (EFI_HANDLE);
492 if (EFI_ERROR (Status)) {
493 *NumberHandles = 0;
494 }
495
496 return Status;
497 }