1 /* $NetBSD: cmdline.c,v 1.1.1.1 2018/08/16 18:17:47 jmcneill 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