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