xref: /netbsd/sys/external/bsd/gnu-efi/dist/lib/cmdline.c (revision 51e65385)
1 /*	$NetBSD: cmdline.c,v 1.1.1.2 2021/09/30 18:50:09 jmcneill Exp $	*/
2 
3 #include "lib.h"
4 
5 #include "efiprot.h"
6 #include "efishell.h"
7 #include "efishellintf.h"
8 
9 #ifndef MAX_ARGV_CONTENTS_SIZE
10 # define MAX_CMDLINE_SIZE 1024
11 #endif
12 #ifndef MAX_ARGC
13 # define MAX_CMDLINE_ARGC 32
14 #endif
15 
16 /*
17   Parse LoadedImage options area, called only in case the regular
18   shell protos are not available.
19 
20   Format of LoadedImage->LoadOptions appears to be a
21   single-space-separated list of args (looks like the shell already
22   pre-parses the input, it apparently folds several consecutive spaces
23   into one):
24     argv[0] space argv[1] (etc.) argv[N] space \0 cwd \0 other data
25   For safety, we support the trailing \0 without a space before, as
26   well as several consecutive spaces (-> several args).
27 */
28 static
29 INTN
GetShellArgcArgvFromLoadedImage(EFI_HANDLE ImageHandle,CHAR16 ** ResultArgv[])30 GetShellArgcArgvFromLoadedImage(
31     EFI_HANDLE ImageHandle,
32     CHAR16 **ResultArgv[]
33     )
34 {
35   EFI_STATUS Status;
36   void *LoadedImage = NULL;
37   static CHAR16 ArgvContents[MAX_CMDLINE_SIZE];
38   static CHAR16 *Argv[MAX_CMDLINE_ARGC], *ArgStart, *c;
39   UINTN Argc = 0, BufLen;
40 
41   Status = uefi_call_wrapper(BS->OpenProtocol, 6,
42                              ImageHandle,
43                              &LoadedImageProtocol,
44                              &LoadedImage,
45                              ImageHandle,
46                              NULL,
47                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
48                              );
49   if (EFI_ERROR(Status))
50     return -1;
51 
52   BufLen = ((EFI_LOADED_IMAGE *)LoadedImage)->LoadOptionsSize;
53   if (BufLen < 2)  /* We are expecting at least a \0 */
54     return -1;
55   else if (BufLen > sizeof(ArgvContents))
56     BufLen = sizeof(ArgvContents);
57 
58   CopyMem(ArgvContents, ((EFI_LOADED_IMAGE *)LoadedImage)->LoadOptions, BufLen);
59   ArgvContents[MAX_CMDLINE_SIZE - 1] = L'\0';
60 
61   for (c = ArgStart = ArgvContents ; *c != L'\0' ; ++c) {
62     if (*c == L' ') {
63       *c = L'\0';
64       if (Argc < MAX_CMDLINE_ARGC) Argv[Argc++] = ArgStart;
65       ArgStart = c + 1;
66     }
67   }
68 
69   if ((*ArgStart != L'\0') && (Argc < MAX_CMDLINE_ARGC))
70     Argv[Argc++] = ArgStart;
71 
72   // Print(L"Got argc/argv from loaded image proto\n");
73   *ResultArgv = Argv;
74   return Argc;
75 }
76 
GetShellArgcArgv(EFI_HANDLE ImageHandle,CHAR16 ** Argv[])77 INTN GetShellArgcArgv(EFI_HANDLE ImageHandle, CHAR16 **Argv[])
78 {
79   // Code inspired from EDK2's
80   // ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c (BSD)
81   EFI_STATUS Status;
82   static const EFI_GUID ShellInterfaceProtocolGuid
83       = SHELL_INTERFACE_PROTOCOL_GUID;
84   EFI_SHELL_PARAMETERS_PROTOCOL *EfiShellParametersProtocol = NULL;
85   EFI_SHELL_INTERFACE *EfiShellInterfaceProtocol = NULL;
86 
87   Status = uefi_call_wrapper(BS->OpenProtocol, 6,
88                              ImageHandle,
89                              (EFI_GUID*)&ShellParametersProtocolGuid,
90                              (VOID **)&EfiShellParametersProtocol,
91                              ImageHandle,
92                              NULL,
93                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
94                              );
95   if (!EFI_ERROR(Status))
96   {
97     // use shell 2.0 interface
98     // Print(L"Got argc/argv from shell intf proto\n");
99     *Argv = EfiShellParametersProtocol->Argv;
100     return EfiShellParametersProtocol->Argc;
101   }
102 
103   // try to get shell 1.0 interface instead.
104   Status = uefi_call_wrapper(BS->OpenProtocol, 6,
105                              ImageHandle,
106                              (EFI_GUID*)&ShellInterfaceProtocolGuid,
107                              (VOID **)&EfiShellInterfaceProtocol,
108                              ImageHandle,
109                              NULL,
110                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
111                              );
112   if (!EFI_ERROR(Status))
113   {
114     // Print(L"Got argc/argv from shell params proto\n");
115     *Argv = EfiShellInterfaceProtocol->Argv;
116     return EfiShellInterfaceProtocol->Argc;
117   }
118 
119   // shell 1.0 and 2.0 interfaces failed
120   return GetShellArgcArgvFromLoadedImage(ImageHandle, Argv);
121 }
122