cmdline.c revision 1.1.1.1.6.2 1 /* $NetBSD: cmdline.c,v 1.1.1.1.6.2 2019/06/10 22:08:36 christos Exp $ */
2
3 #include "lib.h"
4
5 #include "efiprot.h"
6 #include "efishellintf.h"
7 #include "efishellparm.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
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
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 EfiShellParametersProtocolGuid
83 = EFI_SHELL_PARAMETERS_PROTOCOL_GUID;
84 static const EFI_GUID ShellInterfaceProtocolGuid
85 = SHELL_INTERFACE_PROTOCOL_GUID;
86 EFI_SHELL_PARAMETERS_PROTOCOL *EfiShellParametersProtocol = NULL;
87 EFI_SHELL_INTERFACE *EfiShellInterfaceProtocol = NULL;
88
89 Status = uefi_call_wrapper(BS->OpenProtocol, 6,
90 ImageHandle,
91 (EFI_GUID*)&EfiShellParametersProtocolGuid,
92 (VOID **)&EfiShellParametersProtocol,
93 ImageHandle,
94 NULL,
95 EFI_OPEN_PROTOCOL_GET_PROTOCOL
96 );
97 if (!EFI_ERROR(Status))
98 {
99 // use shell 2.0 interface
100 // Print(L"Got argc/argv from shell intf proto\n");
101 *Argv = EfiShellParametersProtocol->Argv;
102 return EfiShellParametersProtocol->Argc;
103 }
104
105 // try to get shell 1.0 interface instead.
106 Status = uefi_call_wrapper(BS->OpenProtocol, 6,
107 ImageHandle,
108 (EFI_GUID*)&ShellInterfaceProtocolGuid,
109 (VOID **)&EfiShellInterfaceProtocol,
110 ImageHandle,
111 NULL,
112 EFI_OPEN_PROTOCOL_GET_PROTOCOL
113 );
114 if (!EFI_ERROR(Status))
115 {
116 // Print(L"Got argc/argv from shell params proto\n");
117 *Argv = EfiShellInterfaceProtocol->Argv;
118 return EfiShellInterfaceProtocol->Argc;
119 }
120
121 // shell 1.0 and 2.0 interfaces failed
122 return GetShellArgcArgvFromLoadedImage(ImageHandle, Argv);
123 }
124