1 #include "lib.h"
2
3 #include "efiprot.h"
4 #include "efishell.h"
5 #include "efishellintf.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
GetShellArgcArgvFromLoadedImage(EFI_HANDLE ImageHandle,CHAR16 ** ResultArgv[])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
GetShellArgcArgv(EFI_HANDLE ImageHandle,CHAR16 ** Argv[])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 ShellInterfaceProtocolGuid
81 = SHELL_INTERFACE_PROTOCOL_GUID;
82 EFI_SHELL_PARAMETERS_PROTOCOL *EfiShellParametersProtocol = NULL;
83 EFI_SHELL_INTERFACE *EfiShellInterfaceProtocol = NULL;
84
85 Status = uefi_call_wrapper(BS->OpenProtocol, 6,
86 ImageHandle,
87 (EFI_GUID*)&ShellParametersProtocolGuid,
88 (VOID **)&EfiShellParametersProtocol,
89 ImageHandle,
90 NULL,
91 EFI_OPEN_PROTOCOL_GET_PROTOCOL
92 );
93 if (!EFI_ERROR(Status))
94 {
95 // use shell 2.0 interface
96 // Print(L"Got argc/argv from shell intf proto\n");
97 *Argv = EfiShellParametersProtocol->Argv;
98 return EfiShellParametersProtocol->Argc;
99 }
100
101 // try to get shell 1.0 interface instead.
102 Status = uefi_call_wrapper(BS->OpenProtocol, 6,
103 ImageHandle,
104 (EFI_GUID*)&ShellInterfaceProtocolGuid,
105 (VOID **)&EfiShellInterfaceProtocol,
106 ImageHandle,
107 NULL,
108 EFI_OPEN_PROTOCOL_GET_PROTOCOL
109 );
110 if (!EFI_ERROR(Status))
111 {
112 // Print(L"Got argc/argv from shell params proto\n");
113 *Argv = EfiShellInterfaceProtocol->Argv;
114 return EfiShellInterfaceProtocol->Argc;
115 }
116
117 // shell 1.0 and 2.0 interfaces failed
118 return GetShellArgcArgvFromLoadedImage(ImageHandle, Argv);
119 }
120