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