1 #include "lib.h" 2 3 #include "efiprot.h" 4 #include "efishellintf.h" 5 #include "efishellparm.h" 6 7 #ifndef MAX_ARGV_CONTENTS_SIZE 8 # define MAX_CMDLINE_SIZE 1024 9 #endif 10 #ifndef MAX_ARGC 11 # define MAX_CMDLINE_ARGC 32 12 #endif 13 14 /* 15 Parse LoadedImage options area, called only in case the regular 16 shell protos are not available. 17 18 Format of LoadedImage->LoadOptions appears to be a 19 single-space-separated list of args (looks like the shell already 20 pre-parses the input, it apparently folds several consecutive spaces 21 into one): 22 argv[0] space argv[1] (etc.) argv[N] space \0 cwd \0 other data 23 For safety, we support the trailing \0 without a space before, as 24 well as several consecutive spaces (-> several args). 25 */ 26 static 27 INTN 28 GetShellArgcArgvFromLoadedImage( 29 EFI_HANDLE ImageHandle, 30 CHAR16 **ResultArgv[] 31 ) 32 { 33 EFI_STATUS Status; 34 EFI_LOADED_IMAGE *LoadedImage = NULL; 35 static CHAR16 ArgvContents[MAX_CMDLINE_SIZE]; 36 static CHAR16 *Argv[MAX_CMDLINE_ARGC], *ArgStart, *c; 37 UINTN Argc = 0, BufLen; 38 39 Status = uefi_call_wrapper(BS->OpenProtocol, 6, 40 ImageHandle, 41 &LoadedImageProtocol, 42 &LoadedImage, 43 ImageHandle, 44 NULL, 45 EFI_OPEN_PROTOCOL_GET_PROTOCOL 46 ); 47 if (EFI_ERROR(Status)) 48 return -1; 49 50 BufLen = LoadedImage->LoadOptionsSize; 51 if (BufLen < 2) /* We are expecting at least a \0 */ 52 return -1; 53 else if (BufLen > sizeof(ArgvContents)) 54 BufLen = sizeof(ArgvContents); 55 56 CopyMem(ArgvContents, LoadedImage->LoadOptions, BufLen); 57 ArgvContents[MAX_CMDLINE_SIZE - 1] = L'\0'; 58 59 for (c = ArgStart = ArgvContents ; *c != L'\0' ; ++c) { 60 if (*c == L' ') { 61 *c = L'\0'; 62 if (Argc < MAX_CMDLINE_ARGC) Argv[Argc++] = ArgStart; 63 ArgStart = c + 1; 64 } 65 } 66 67 if ((*ArgStart != L'\0') && (Argc < MAX_CMDLINE_ARGC)) 68 Argv[Argc++] = ArgStart; 69 70 // Print(L"Got argc/argv from loaded image proto\n"); 71 *ResultArgv = Argv; 72 return Argc; 73 } 74 75 INTN GetShellArgcArgv(EFI_HANDLE ImageHandle, CHAR16 **Argv[]) 76 { 77 // Code inspired from EDK2's 78 // ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c (BSD) 79 EFI_STATUS Status; 80 static const EFI_GUID EfiShellParametersProtocolGuid 81 = EFI_SHELL_PARAMETERS_PROTOCOL_GUID; 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 &EfiShellParametersProtocolGuid, 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 &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