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