xref: /netbsd-src/sys/external/bsd/gnu-efi/dist/lib/hand.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: hand.c,v 1.4 2018/08/16 18:22:05 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
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
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
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
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 *
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 *
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 *
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
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 
494     va_end (args);
495 
496     //
497     // If there was an error, remove all the interfaces that were
498     // installed without any errors
499     //
500 
501     if (EFI_ERROR(Status)) {
502         va_start (args, Handle);
503         while (Index) {
504 
505             Protocol = va_arg(args, EFI_GUID *);
506             Interface = va_arg(args, VOID *);
507             uefi_call_wrapper(BS->UninstallProtocolInterface, 3, *Handle, Protocol, Interface);
508 
509             Index -= 1;
510         }
511 	va_end (args);
512 
513         *Handle = OldHandle;
514     }
515 
516     //
517     // Done
518     //
519 
520     uefi_call_wrapper(BS->RestoreTPL, 1, OldTpl);
521     return Status;
522 }
523 
524 
525 VOID
526 LibUninstallProtocolInterfaces (
527     IN EFI_HANDLE           Handle,
528     ...
529     )
530 {
531     va_list         args;
532     EFI_STATUS      Status;
533     EFI_GUID        *Protocol;
534     VOID            *Interface;
535 
536 
537     va_start (args, Handle);
538     for (; ;) {
539 
540         //
541         // If protocol is NULL, then it's the end of the list
542         //
543 
544         Protocol = va_arg(args, EFI_GUID *);
545         if (!Protocol) {
546             break;
547         }
548 
549         Interface = va_arg(args, VOID *);
550 
551         //
552         // Uninstall it
553         //
554 
555         Status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, Handle, Protocol, Interface);
556         if (EFI_ERROR(Status)) {
557             DEBUG((D_ERROR, "LibUninstallProtocolInterfaces: failed %g, %r\n", Protocol, Handle));
558         }
559     }
560     va_end (args);
561 }
562 
563 
564 EFI_STATUS
565 LibReinstallProtocolInterfaces (
566     IN OUT EFI_HANDLE           *Handle,
567     ...
568     )
569 {
570     va_list         args;
571     EFI_STATUS      Status;
572     EFI_GUID        *Protocol;
573     VOID            *OldInterface, *NewInterface;
574     EFI_TPL         OldTpl;
575     UINTN           Index;
576 
577     //
578     // Syncronize with notifcations
579     //
580 
581     OldTpl = uefi_call_wrapper(BS->RaiseTPL, 1, TPL_NOTIFY);
582 
583     //
584     // Install the protocol interfaces
585     //
586 
587     Index = 0;
588     Status = EFI_SUCCESS;
589     va_start (args, Handle);
590 
591     while (!EFI_ERROR(Status)) {
592 
593         //
594         // If protocol is NULL, then it's the end of the list
595         //
596 
597         Protocol = va_arg(args, EFI_GUID *);
598         if (!Protocol) {
599             break;
600         }
601 
602         OldInterface = va_arg(args, VOID *);
603         NewInterface = va_arg(args, VOID *);
604 
605         //
606         // Reinstall it
607         //
608 
609         Status = uefi_call_wrapper(BS->ReinstallProtocolInterface, 4, Handle, Protocol, OldInterface, NewInterface);
610         if (EFI_ERROR(Status)) {
611             break;
612         }
613 
614         Index += 1;
615     }
616 
617     va_end (args);
618 
619     //
620     // If there was an error, undo all the interfaces that were
621     // reinstalled without any errors
622     //
623 
624     if (EFI_ERROR(Status)) {
625         va_start (args, Handle);
626         while (Index) {
627 
628             Protocol = va_arg(args, EFI_GUID *);
629             OldInterface = va_arg(args, VOID *);
630             NewInterface = va_arg(args, VOID *);
631 
632             uefi_call_wrapper(BS->ReinstallProtocolInterface, 4, Handle, Protocol, NewInterface, OldInterface);
633 
634             Index -= 1;
635         }
636 	va_end (args);
637     }
638 
639     //
640     // Done
641     //
642 
643     uefi_call_wrapper(BS->RestoreTPL, 1, OldTpl);
644     return Status;
645 }
646