xref: /netbsd-src/sys/external/bsd/gnu-efi/dist/lib/hand.c (revision 35ff39e48f27cc4d27af726cb651cda505a965b4)
1 /*	$NetBSD: hand.c,v 1.5 2021/09/30 19:02:48 jmcneill Exp $	*/
2 
3 /*++
4 
5 Copyright (c) 1998  Intel Corporation
6 
7 Module Name:
8 
9     hand.c
10 
11 Abstract:
12 
13 
14 
15 
16 Revision History
17 
18 --*/
19 
20 #include "lib.h"
21 #include "efistdarg.h"                        // !!!
22 
23 
24 EFI_STATUS
LibLocateProtocol(IN EFI_GUID * ProtocolGuid,OUT VOID ** Interface)25 LibLocateProtocol (
26     IN  EFI_GUID    *ProtocolGuid,
27     OUT VOID        **Interface
28     )
29 //
30 // Find the first instance of this Protocol in the system and return it's interface
31 //
32 {
33     EFI_STATUS      Status;
34     UINTN           NumberHandles, Index;
35     EFI_HANDLE      *Handles;
36 
37 
38     *Interface = NULL;
39     Status = LibLocateHandle (ByProtocol, ProtocolGuid, NULL, &NumberHandles, &Handles);
40     if (EFI_ERROR(Status)) {
41         DEBUG((D_INFO, "LibLocateProtocol: Handle not found\n"));
42         return Status;
43     }
44 
45     for (Index=0; Index < NumberHandles; Index++) {
46         Status = uefi_call_wrapper(BS->HandleProtocol, 3, Handles[Index], ProtocolGuid, Interface);
47         if (!EFI_ERROR(Status)) {
48             break;
49         }
50     }
51 
52     if (Handles) {
53         FreePool (Handles);
54     }
55 
56     return Status;
57 }
58 
59 EFI_STATUS
LibLocateHandle(IN EFI_LOCATE_SEARCH_TYPE SearchType,IN EFI_GUID * Protocol OPTIONAL,IN VOID * SearchKey OPTIONAL,IN OUT UINTN * NoHandles,OUT EFI_HANDLE ** Buffer)60 LibLocateHandle (
61     IN EFI_LOCATE_SEARCH_TYPE       SearchType,
62     IN EFI_GUID                     *Protocol OPTIONAL,
63     IN VOID                         *SearchKey OPTIONAL,
64     IN OUT UINTN                    *NoHandles,
65     OUT EFI_HANDLE                  **Buffer
66     )
67 
68 {
69     EFI_STATUS          Status;
70     UINTN               BufferSize;
71 
72     //
73     // Initialize for GrowBuffer loop
74     //
75 
76     Status = EFI_SUCCESS;
77     *Buffer = NULL;
78     BufferSize = 50 * sizeof(EFI_HANDLE);
79 
80     //
81     // Call the real function
82     //
83 
84     while (GrowBuffer (&Status, (VOID **) Buffer, BufferSize)) {
85 
86         Status = uefi_call_wrapper(
87 			BS->LocateHandle,
88 			5,
89                         SearchType,
90                         Protocol,
91                         SearchKey,
92                         &BufferSize,
93                         *Buffer
94                         );
95 
96     }
97 
98     *NoHandles = BufferSize / sizeof (EFI_HANDLE);
99     if (EFI_ERROR(Status)) {
100         *NoHandles = 0;
101     }
102 
103     return Status;
104 }
105 
106 EFI_STATUS
LibLocateHandleByDiskSignature(IN UINT8 MBRType,IN UINT8 SignatureType,IN VOID * Signature,IN OUT UINTN * NoHandles,OUT EFI_HANDLE ** Buffer)107 LibLocateHandleByDiskSignature (
108     IN UINT8                        MBRType,
109     IN UINT8                        SignatureType,
110     IN VOID                         *Signature,
111     IN OUT UINTN                    *NoHandles,
112     OUT EFI_HANDLE                  **Buffer
113     )
114 
115 {
116     EFI_STATUS            Status;
117     UINTN                 BufferSize;
118     UINTN                 NoBlockIoHandles;
119     EFI_HANDLE            *BlockIoBuffer;
120     EFI_DEVICE_PATH       *DevicePath;
121     UINTN                 Index;
122     EFI_DEVICE_PATH       *Next, *DevPath;
123     HARDDRIVE_DEVICE_PATH *HardDriveDevicePath;
124     BOOLEAN               Match;
125     BOOLEAN               PreviousNodeIsHardDriveDevicePath;
126 
127     //
128     // Initialize for GrowBuffer loop
129     //
130 
131     Status = EFI_SUCCESS;
132     BlockIoBuffer = NULL;
133     BufferSize = 50 * sizeof(EFI_HANDLE);
134 
135     //
136     // Call the real function
137     //
138 
139     while (GrowBuffer (&Status, (VOID **)&BlockIoBuffer, BufferSize)) {
140 
141         //
142         // Get list of device handles that support the BLOCK_IO Protocol.
143         //
144 
145         Status = uefi_call_wrapper(
146 			BS->LocateHandle,
147 			5,
148                         ByProtocol,
149                         &BlockIoProtocol,
150                         NULL,
151                         &BufferSize,
152                         BlockIoBuffer
153                         );
154 
155     }
156 
157     NoBlockIoHandles = BufferSize / sizeof (EFI_HANDLE);
158     if (EFI_ERROR(Status)) {
159         NoBlockIoHandles = 0;
160     }
161 
162     //
163     // If there was an error or there are no device handles that support
164     // the BLOCK_IO Protocol, then return.
165     //
166 
167     if (NoBlockIoHandles == 0) {
168         FreePool(BlockIoBuffer);
169         *NoHandles = 0;
170         *Buffer = NULL;
171         return Status;
172     }
173 
174     //
175     // Loop through all the device handles that support the BLOCK_IO Protocol
176     //
177 
178     *NoHandles = 0;
179 
180     for(Index=0;Index<NoBlockIoHandles;Index++) {
181 
182         Status = uefi_call_wrapper(
183 				     BS->HandleProtocol,
184 					3,
185 				     BlockIoBuffer[Index],
186                                      &DevicePathProtocol,
187                                      (VOID*)&DevicePath
188                                      );
189 
190         //
191         // Search DevicePath for a Hard Drive Media Device Path node.
192         // If one is found, then see if it matches the signature that was
193         // passed in.  If it does match, and the next node is the End of the
194         // device path, and the previous node is not a Hard Drive Media Device
195         // Path, then we have found a match.
196         //
197 
198         Match = FALSE;
199 
200         if (DevicePath != NULL) {
201 
202             PreviousNodeIsHardDriveDevicePath = FALSE;
203 
204             DevPath = DevicePath;
205 
206             //
207             // Check for end of device path type
208             //
209 
210             for (; ;) {
211 
212                 if ((DevicePathType(DevPath) == MEDIA_DEVICE_PATH) &&
213                     (DevicePathSubType(DevPath) == MEDIA_HARDDRIVE_DP)) {
214 
215                     HardDriveDevicePath = (HARDDRIVE_DEVICE_PATH *)(DevPath);
216 
217                     if (PreviousNodeIsHardDriveDevicePath == FALSE) {
218 
219                         Next = NextDevicePathNode(DevPath);
220                         if (IsDevicePathEndType(Next)) {
221                             if ((HardDriveDevicePath->MBRType == MBRType) &&
222                                 (HardDriveDevicePath->SignatureType == SignatureType)) {
223                                     switch(SignatureType) {
224                                         case SIGNATURE_TYPE_MBR:
225                                             if (*((UINT32 *)(Signature)) == *(UINT32 *)(&(HardDriveDevicePath->Signature[0]))) {
226                                                 Match = TRUE;
227                                             }
228                                             break;
229                                         case SIGNATURE_TYPE_GUID:
230                                             if (CompareGuid((EFI_GUID *)Signature,(EFI_GUID *)(&(HardDriveDevicePath->Signature[0]))) == 0) {
231                                                 Match = TRUE;
232                                             }
233                                             break;
234                                     }
235                             }
236                         }
237                     }
238                     PreviousNodeIsHardDriveDevicePath = TRUE;
239                 } else {
240                     PreviousNodeIsHardDriveDevicePath = FALSE;
241                 }
242 
243                 if (IsDevicePathEnd(DevPath)) {
244                     break;
245                 }
246 
247                 DevPath = NextDevicePathNode(DevPath);
248             }
249 
250         }
251 
252         if (Match == FALSE) {
253             BlockIoBuffer[Index] = NULL;
254         } else {
255             *NoHandles = *NoHandles + 1;
256         }
257     }
258 
259     //
260     // If there are no matches, then return
261     //
262 
263     if (*NoHandles == 0) {
264         FreePool(BlockIoBuffer);
265         *NoHandles = 0;
266         *Buffer = NULL;
267         return EFI_SUCCESS;
268     }
269 
270     //
271     // Allocate space for the return buffer of device handles.
272     //
273 
274     *Buffer = AllocatePool(*NoHandles * sizeof(EFI_HANDLE));
275 
276     if (*Buffer == NULL) {
277         FreePool(BlockIoBuffer);
278         *NoHandles = 0;
279         *Buffer = NULL;
280         return EFI_OUT_OF_RESOURCES;
281     }
282 
283     //
284     // Build list of matching device handles.
285     //
286 
287     *NoHandles = 0;
288     for(Index=0;Index<NoBlockIoHandles;Index++) {
289         if (BlockIoBuffer[Index] != NULL) {
290             (*Buffer)[*NoHandles] = BlockIoBuffer[Index];
291             *NoHandles = *NoHandles + 1;
292         }
293     }
294 
295     FreePool(BlockIoBuffer);
296 
297     return EFI_SUCCESS;
298 }
299 
300 EFI_FILE_HANDLE
LibOpenRoot(IN EFI_HANDLE DeviceHandle)301 LibOpenRoot (
302     IN EFI_HANDLE               DeviceHandle
303     )
304 {
305     EFI_STATUS                  Status;
306     EFI_FILE_IO_INTERFACE       *Volume;
307     EFI_FILE_HANDLE             File;
308 
309 
310     //
311     // File the file system interface to the device
312     //
313 
314     Status = uefi_call_wrapper(BS->HandleProtocol, 3, DeviceHandle, &FileSystemProtocol, (VOID*)&Volume);
315 
316     //
317     // Open the root directory of the volume
318     //
319 
320     if (!EFI_ERROR(Status)) {
321         Status = uefi_call_wrapper(Volume->OpenVolume, 2, Volume, &File);
322     }
323 
324     //
325     // Done
326     //
327 
328     return EFI_ERROR(Status) ? NULL : File;
329 }
330 
331 EFI_FILE_INFO *
LibFileInfo(IN EFI_FILE_HANDLE FHand)332 LibFileInfo (
333     IN EFI_FILE_HANDLE      FHand
334     )
335 {
336     EFI_STATUS              Status;
337     EFI_FILE_INFO           *Buffer;
338     UINTN                   BufferSize;
339 
340     //
341     // Initialize for GrowBuffer loop
342     //
343 
344     Status = EFI_SUCCESS;
345     Buffer = NULL;
346     BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
347 
348     //
349     // Call the real function
350     //
351 
352     while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
353         Status = uefi_call_wrapper(
354 		    FHand->GetInfo,
355 			4,
356                     FHand,
357                     &GenericFileInfo,
358                     &BufferSize,
359                     Buffer
360                     );
361     }
362 
363     return Buffer;
364 }
365 
366 
367 EFI_FILE_SYSTEM_INFO *
LibFileSystemInfo(IN EFI_FILE_HANDLE FHand)368 LibFileSystemInfo (
369     IN EFI_FILE_HANDLE      FHand
370     )
371 {
372     EFI_STATUS              Status;
373     EFI_FILE_SYSTEM_INFO    *Buffer;
374     UINTN                   BufferSize;
375 
376     //
377     // Initialize for GrowBuffer loop
378     //
379 
380     Status = EFI_SUCCESS;
381     Buffer = NULL;
382     BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + 200;
383 
384     //
385     // Call the real function
386     //
387 
388     while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
389         Status = uefi_call_wrapper(
390 		    FHand->GetInfo,
391 			4,
392                     FHand,
393                     &FileSystemInfo,
394                     &BufferSize,
395                     Buffer
396                     );
397     }
398 
399     return Buffer;
400 }
401 
402 EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *
LibFileSystemVolumeLabelInfo(IN EFI_FILE_HANDLE FHand)403 LibFileSystemVolumeLabelInfo (
404     IN EFI_FILE_HANDLE      FHand
405     )
406 {
407     EFI_STATUS                        Status;
408     EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Buffer;
409     UINTN                             BufferSize;
410 
411     //
412     // Initialize for GrowBuffer loop
413     //
414 
415     Status = EFI_SUCCESS;
416     Buffer = NULL;
417     BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 200;
418 
419     //
420     // Call the real function
421     //
422 
423     while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
424         Status = uefi_call_wrapper(
425 		    FHand->GetInfo,
426 			4,
427                     FHand,
428                     &FileSystemVolumeLabelInfo,
429                     &BufferSize,
430                     Buffer
431                     );
432     }
433 
434     return Buffer;
435 }
436 
437 
438 
439 EFI_STATUS
LibInstallProtocolInterfaces(IN OUT EFI_HANDLE * Handle,...)440 LibInstallProtocolInterfaces (
441     IN OUT EFI_HANDLE           *Handle,
442     ...
443     )
444 {
445     va_list         args;
446     EFI_STATUS      Status;
447     EFI_GUID        *Protocol;
448     VOID            *Interface;
449     EFI_TPL         OldTpl;
450     UINTN           Index;
451     EFI_HANDLE      OldHandle;
452 
453     //
454     // Syncronize with notifcations
455     //
456 
457     OldTpl = uefi_call_wrapper(BS->RaiseTPL, 1, TPL_NOTIFY);
458     OldHandle = *Handle;
459 
460     //
461     // Install the protocol interfaces
462     //
463 
464     Index = 0;
465     Status = EFI_SUCCESS;
466     va_start (args, Handle);
467 
468     while (!EFI_ERROR(Status)) {
469 
470         //
471         // If protocol is NULL, then it's the end of the list
472         //
473 
474         Protocol = va_arg(args, EFI_GUID *);
475         if (!Protocol) {
476             break;
477         }
478 
479         Interface = va_arg(args, VOID *);
480 
481         //
482         // Install it
483         //
484 
485         DEBUG((D_INFO, "LibInstallProtocolInterface: %d %x\n", Protocol, Interface));
486         Status = uefi_call_wrapper(BS->InstallProtocolInterface, 4, Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);
487         if (EFI_ERROR(Status)) {
488             break;
489         }
490 
491         Index += 1;
492     }
493     va_end (args);
494 
495     va_end (args);
496 
497     //
498     // If there was an error, remove all the interfaces that were
499     // installed without any errors
500     //
501 
502     if (EFI_ERROR(Status)) {
503         va_start (args, Handle);
504         while (Index) {
505 
506             Protocol = va_arg(args, EFI_GUID *);
507             Interface = va_arg(args, VOID *);
508             uefi_call_wrapper(BS->UninstallProtocolInterface, 3, *Handle, Protocol, Interface);
509 
510             Index -= 1;
511         }
512 	va_end (args);
513 
514         *Handle = OldHandle;
515         va_end (args);
516     }
517 
518     //
519     // Done
520     //
521 
522     uefi_call_wrapper(BS->RestoreTPL, 1, OldTpl);
523     return Status;
524 }
525 
526 
527 VOID
LibUninstallProtocolInterfaces(IN EFI_HANDLE Handle,...)528 LibUninstallProtocolInterfaces (
529     IN EFI_HANDLE           Handle,
530     ...
531     )
532 {
533     va_list         args;
534     EFI_STATUS      Status;
535     EFI_GUID        *Protocol;
536     VOID            *Interface;
537 
538 
539     va_start (args, Handle);
540     for (; ;) {
541 
542         //
543         // If protocol is NULL, then it's the end of the list
544         //
545 
546         Protocol = va_arg(args, EFI_GUID *);
547         if (!Protocol) {
548             break;
549         }
550 
551         Interface = va_arg(args, VOID *);
552 
553         //
554         // Uninstall it
555         //
556 
557         Status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, Handle, Protocol, Interface);
558         if (EFI_ERROR(Status)) {
559             DEBUG((D_ERROR, "LibUninstallProtocolInterfaces: failed %g, %r\n", Protocol, Handle));
560         }
561     }
562     va_end (args);
563 }
564 
565 
566 EFI_STATUS
LibReinstallProtocolInterfaces(IN OUT EFI_HANDLE * Handle,...)567 LibReinstallProtocolInterfaces (
568     IN OUT EFI_HANDLE           *Handle,
569     ...
570     )
571 {
572     va_list         args;
573     EFI_STATUS      Status;
574     EFI_GUID        *Protocol;
575     VOID            *OldInterface, *NewInterface;
576     EFI_TPL         OldTpl;
577     UINTN           Index;
578 
579     //
580     // Syncronize with notifcations
581     //
582 
583     OldTpl = uefi_call_wrapper(BS->RaiseTPL, 1, TPL_NOTIFY);
584 
585     //
586     // Install the protocol interfaces
587     //
588 
589     Index = 0;
590     Status = EFI_SUCCESS;
591     va_start (args, Handle);
592 
593     while (!EFI_ERROR(Status)) {
594 
595         //
596         // If protocol is NULL, then it's the end of the list
597         //
598 
599         Protocol = va_arg(args, EFI_GUID *);
600         if (!Protocol) {
601             break;
602         }
603 
604         OldInterface = va_arg(args, VOID *);
605         NewInterface = va_arg(args, VOID *);
606 
607         //
608         // Reinstall it
609         //
610 
611         Status = uefi_call_wrapper(BS->ReinstallProtocolInterface, 4, Handle, Protocol, OldInterface, NewInterface);
612         if (EFI_ERROR(Status)) {
613             break;
614         }
615 
616         Index += 1;
617     }
618     va_end (args);
619 
620     va_end (args);
621 
622     //
623     // If there was an error, undo all the interfaces that were
624     // reinstalled without any errors
625     //
626 
627     if (EFI_ERROR(Status)) {
628         va_start (args, Handle);
629         while (Index) {
630 
631             Protocol = va_arg(args, EFI_GUID *);
632             OldInterface = va_arg(args, VOID *);
633             NewInterface = va_arg(args, VOID *);
634 
635             uefi_call_wrapper(BS->ReinstallProtocolInterface, 4, Handle, Protocol, NewInterface, OldInterface);
636 
637             Index -= 1;
638         }
639         va_end (args);
640     }
641 
642     //
643     // Done
644     //
645 
646     uefi_call_wrapper(BS->RestoreTPL, 1, OldTpl);
647     return Status;
648 }
649