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