xref: /DragonStub/lib/cmdline.c (revision 2a1200f36faf0d67c7150686e44c578c19a897ef)
1530d68baSNigel Croxon #include "lib.h"
2530d68baSNigel Croxon 
3530d68baSNigel Croxon #include "efiprot.h"
4*773f30afSJiaqing Zhao #include "efishell.h"
5530d68baSNigel Croxon #include "efishellintf.h"
6530d68baSNigel Croxon 
7530d68baSNigel Croxon #ifndef MAX_ARGV_CONTENTS_SIZE
8530d68baSNigel Croxon # define MAX_CMDLINE_SIZE 1024
9530d68baSNigel Croxon #endif
10530d68baSNigel Croxon #ifndef MAX_ARGC
11530d68baSNigel Croxon # define MAX_CMDLINE_ARGC 32
12530d68baSNigel Croxon #endif
13530d68baSNigel Croxon 
14530d68baSNigel Croxon /*
15530d68baSNigel Croxon   Parse LoadedImage options area, called only in case the regular
16530d68baSNigel Croxon   shell protos are not available.
17530d68baSNigel Croxon 
18530d68baSNigel Croxon   Format of LoadedImage->LoadOptions appears to be a
19530d68baSNigel Croxon   single-space-separated list of args (looks like the shell already
20530d68baSNigel Croxon   pre-parses the input, it apparently folds several consecutive spaces
21530d68baSNigel Croxon   into one):
22530d68baSNigel Croxon     argv[0] space argv[1] (etc.) argv[N] space \0 cwd \0 other data
23530d68baSNigel Croxon   For safety, we support the trailing \0 without a space before, as
24530d68baSNigel Croxon   well as several consecutive spaces (-> several args).
25530d68baSNigel Croxon */
26530d68baSNigel Croxon static
27530d68baSNigel Croxon INTN
GetShellArgcArgvFromLoadedImage(EFI_HANDLE ImageHandle,CHAR16 ** ResultArgv[])28530d68baSNigel Croxon GetShellArgcArgvFromLoadedImage(
29530d68baSNigel Croxon     EFI_HANDLE ImageHandle,
30530d68baSNigel Croxon     CHAR16 **ResultArgv[]
31530d68baSNigel Croxon     )
32530d68baSNigel Croxon {
33530d68baSNigel Croxon   EFI_STATUS Status;
34087d22afSNigel Croxon   void *LoadedImage = NULL;
35530d68baSNigel Croxon   static CHAR16 ArgvContents[MAX_CMDLINE_SIZE];
36530d68baSNigel Croxon   static CHAR16 *Argv[MAX_CMDLINE_ARGC], *ArgStart, *c;
37530d68baSNigel Croxon   UINTN Argc = 0, BufLen;
38530d68baSNigel Croxon 
39530d68baSNigel Croxon   Status = uefi_call_wrapper(BS->OpenProtocol, 6,
40530d68baSNigel Croxon                              ImageHandle,
41530d68baSNigel Croxon                              &LoadedImageProtocol,
42530d68baSNigel Croxon                              &LoadedImage,
43530d68baSNigel Croxon                              ImageHandle,
44530d68baSNigel Croxon                              NULL,
45530d68baSNigel Croxon                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
46530d68baSNigel Croxon                              );
47530d68baSNigel Croxon   if (EFI_ERROR(Status))
48530d68baSNigel Croxon     return -1;
49530d68baSNigel Croxon 
50087d22afSNigel Croxon   BufLen = ((EFI_LOADED_IMAGE *)LoadedImage)->LoadOptionsSize;
51530d68baSNigel Croxon   if (BufLen < 2)  /* We are expecting at least a \0 */
52530d68baSNigel Croxon     return -1;
53530d68baSNigel Croxon   else if (BufLen > sizeof(ArgvContents))
54530d68baSNigel Croxon     BufLen = sizeof(ArgvContents);
55530d68baSNigel Croxon 
56087d22afSNigel Croxon   CopyMem(ArgvContents, ((EFI_LOADED_IMAGE *)LoadedImage)->LoadOptions, BufLen);
57530d68baSNigel Croxon   ArgvContents[MAX_CMDLINE_SIZE - 1] = L'\0';
58530d68baSNigel Croxon 
59530d68baSNigel Croxon   for (c = ArgStart = ArgvContents ; *c != L'\0' ; ++c) {
60530d68baSNigel Croxon     if (*c == L' ') {
61530d68baSNigel Croxon       *c = L'\0';
62530d68baSNigel Croxon       if (Argc < MAX_CMDLINE_ARGC) Argv[Argc++] = ArgStart;
63530d68baSNigel Croxon       ArgStart = c + 1;
64530d68baSNigel Croxon     }
65530d68baSNigel Croxon   }
66530d68baSNigel Croxon 
67530d68baSNigel Croxon   if ((*ArgStart != L'\0') && (Argc < MAX_CMDLINE_ARGC))
68530d68baSNigel Croxon     Argv[Argc++] = ArgStart;
69530d68baSNigel Croxon 
70530d68baSNigel Croxon   // Print(L"Got argc/argv from loaded image proto\n");
71530d68baSNigel Croxon   *ResultArgv = Argv;
72530d68baSNigel Croxon   return Argc;
73530d68baSNigel Croxon }
74530d68baSNigel Croxon 
GetShellArgcArgv(EFI_HANDLE ImageHandle,CHAR16 ** Argv[])75530d68baSNigel Croxon INTN GetShellArgcArgv(EFI_HANDLE ImageHandle, CHAR16 **Argv[])
76530d68baSNigel Croxon {
77530d68baSNigel Croxon   // Code inspired from EDK2's
78530d68baSNigel Croxon   // ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c (BSD)
79530d68baSNigel Croxon   EFI_STATUS Status;
80530d68baSNigel Croxon   static const EFI_GUID ShellInterfaceProtocolGuid
81530d68baSNigel Croxon       = SHELL_INTERFACE_PROTOCOL_GUID;
82530d68baSNigel Croxon   EFI_SHELL_PARAMETERS_PROTOCOL *EfiShellParametersProtocol = NULL;
83530d68baSNigel Croxon   EFI_SHELL_INTERFACE *EfiShellInterfaceProtocol = NULL;
84530d68baSNigel Croxon 
85530d68baSNigel Croxon   Status = uefi_call_wrapper(BS->OpenProtocol, 6,
86530d68baSNigel Croxon                              ImageHandle,
87*773f30afSJiaqing Zhao                              (EFI_GUID*)&ShellParametersProtocolGuid,
88530d68baSNigel Croxon                              (VOID **)&EfiShellParametersProtocol,
89530d68baSNigel Croxon                              ImageHandle,
90530d68baSNigel Croxon                              NULL,
91530d68baSNigel Croxon                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
92530d68baSNigel Croxon                              );
93530d68baSNigel Croxon   if (!EFI_ERROR(Status))
94530d68baSNigel Croxon   {
95530d68baSNigel Croxon     // use shell 2.0 interface
96530d68baSNigel Croxon     // Print(L"Got argc/argv from shell intf proto\n");
97530d68baSNigel Croxon     *Argv = EfiShellParametersProtocol->Argv;
98530d68baSNigel Croxon     return EfiShellParametersProtocol->Argc;
99530d68baSNigel Croxon   }
100530d68baSNigel Croxon 
101530d68baSNigel Croxon   // try to get shell 1.0 interface instead.
102530d68baSNigel Croxon   Status = uefi_call_wrapper(BS->OpenProtocol, 6,
103530d68baSNigel Croxon                              ImageHandle,
10409027207SNigel Croxon                              (EFI_GUID*)&ShellInterfaceProtocolGuid,
105530d68baSNigel Croxon                              (VOID **)&EfiShellInterfaceProtocol,
106530d68baSNigel Croxon                              ImageHandle,
107530d68baSNigel Croxon                              NULL,
108530d68baSNigel Croxon                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
109530d68baSNigel Croxon                              );
110530d68baSNigel Croxon   if (!EFI_ERROR(Status))
111530d68baSNigel Croxon   {
112530d68baSNigel Croxon     // Print(L"Got argc/argv from shell params proto\n");
113530d68baSNigel Croxon     *Argv = EfiShellInterfaceProtocol->Argv;
114530d68baSNigel Croxon     return EfiShellInterfaceProtocol->Argc;
115530d68baSNigel Croxon   }
116530d68baSNigel Croxon 
117530d68baSNigel Croxon   // shell 1.0 and 2.0 interfaces failed
118530d68baSNigel Croxon   return GetShellArgcArgvFromLoadedImage(ImageHandle, Argv);
119530d68baSNigel Croxon }
120