xref: /DragonStub/lib/cmdline.c (revision 3f234f5b6ff5c16c6ddd5f2c2513fb329aecd30a)
1 #include "lib.h"
2 
3 #include "efiprot.h"
4 #include "efishellintf.h"
5 #include "efishellparm.h"
6 
7 #ifndef MAX_ARGV_CONTENTS_SIZE
8 # define MAX_CMDLINE_SIZE 1024
9 #endif
10 #ifndef MAX_ARGC
11 # define MAX_CMDLINE_ARGC 32
12 #endif
13 
14 /*
15   Parse LoadedImage options area, called only in case the regular
16   shell protos are not available.
17 
18   Format of LoadedImage->LoadOptions appears to be a
19   single-space-separated list of args (looks like the shell already
20   pre-parses the input, it apparently folds several consecutive spaces
21   into one):
22     argv[0] space argv[1] (etc.) argv[N] space \0 cwd \0 other data
23   For safety, we support the trailing \0 without a space before, as
24   well as several consecutive spaces (-> several args).
25 */
26 static
27 INTN
28 GetShellArgcArgvFromLoadedImage(
29     EFI_HANDLE ImageHandle,
30     CHAR16 **ResultArgv[]
31     )
32 {
33   EFI_STATUS Status;
34   void *LoadedImage = NULL;
35   static CHAR16 ArgvContents[MAX_CMDLINE_SIZE];
36   static CHAR16 *Argv[MAX_CMDLINE_ARGC], *ArgStart, *c;
37   UINTN Argc = 0, BufLen;
38 
39   Status = uefi_call_wrapper(BS->OpenProtocol, 6,
40                              ImageHandle,
41                              &LoadedImageProtocol,
42                              &LoadedImage,
43                              ImageHandle,
44                              NULL,
45                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
46                              );
47   if (EFI_ERROR(Status))
48     return -1;
49 
50   BufLen = ((EFI_LOADED_IMAGE *)LoadedImage)->LoadOptionsSize;
51   if (BufLen < 2)  /* We are expecting at least a \0 */
52     return -1;
53   else if (BufLen > sizeof(ArgvContents))
54     BufLen = sizeof(ArgvContents);
55 
56   CopyMem(ArgvContents, ((EFI_LOADED_IMAGE *)LoadedImage)->LoadOptions, BufLen);
57   ArgvContents[MAX_CMDLINE_SIZE - 1] = L'\0';
58 
59   for (c = ArgStart = ArgvContents ; *c != L'\0' ; ++c) {
60     if (*c == L' ') {
61       *c = L'\0';
62       if (Argc < MAX_CMDLINE_ARGC) Argv[Argc++] = ArgStart;
63       ArgStart = c + 1;
64     }
65   }
66 
67   if ((*ArgStart != L'\0') && (Argc < MAX_CMDLINE_ARGC))
68     Argv[Argc++] = ArgStart;
69 
70   // Print(L"Got argc/argv from loaded image proto\n");
71   *ResultArgv = Argv;
72   return Argc;
73 }
74 
75 INTN GetShellArgcArgv(EFI_HANDLE ImageHandle, CHAR16 **Argv[])
76 {
77   // Code inspired from EDK2's
78   // ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c (BSD)
79   EFI_STATUS Status;
80   static const EFI_GUID EfiShellParametersProtocolGuid
81       = EFI_SHELL_PARAMETERS_PROTOCOL_GUID;
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*)&EfiShellParametersProtocolGuid,
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