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