1 1.1 jmcneill /* $NetBSD: cmdline.c,v 1.1.1.2 2021/09/30 18:50:09 jmcneill Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill #include "lib.h" 4 1.1 jmcneill 5 1.1 jmcneill #include "efiprot.h" 6 1.1.1.2 jmcneill #include "efishell.h" 7 1.1 jmcneill #include "efishellintf.h" 8 1.1 jmcneill 9 1.1 jmcneill #ifndef MAX_ARGV_CONTENTS_SIZE 10 1.1 jmcneill # define MAX_CMDLINE_SIZE 1024 11 1.1 jmcneill #endif 12 1.1 jmcneill #ifndef MAX_ARGC 13 1.1 jmcneill # define MAX_CMDLINE_ARGC 32 14 1.1 jmcneill #endif 15 1.1 jmcneill 16 1.1 jmcneill /* 17 1.1 jmcneill Parse LoadedImage options area, called only in case the regular 18 1.1 jmcneill shell protos are not available. 19 1.1 jmcneill 20 1.1 jmcneill Format of LoadedImage->LoadOptions appears to be a 21 1.1 jmcneill single-space-separated list of args (looks like the shell already 22 1.1 jmcneill pre-parses the input, it apparently folds several consecutive spaces 23 1.1 jmcneill into one): 24 1.1 jmcneill argv[0] space argv[1] (etc.) argv[N] space \0 cwd \0 other data 25 1.1 jmcneill For safety, we support the trailing \0 without a space before, as 26 1.1 jmcneill well as several consecutive spaces (-> several args). 27 1.1 jmcneill */ 28 1.1 jmcneill static 29 1.1 jmcneill INTN 30 1.1 jmcneill GetShellArgcArgvFromLoadedImage( 31 1.1 jmcneill EFI_HANDLE ImageHandle, 32 1.1 jmcneill CHAR16 **ResultArgv[] 33 1.1 jmcneill ) 34 1.1 jmcneill { 35 1.1 jmcneill EFI_STATUS Status; 36 1.1 jmcneill void *LoadedImage = NULL; 37 1.1 jmcneill static CHAR16 ArgvContents[MAX_CMDLINE_SIZE]; 38 1.1 jmcneill static CHAR16 *Argv[MAX_CMDLINE_ARGC], *ArgStart, *c; 39 1.1 jmcneill UINTN Argc = 0, BufLen; 40 1.1 jmcneill 41 1.1 jmcneill Status = uefi_call_wrapper(BS->OpenProtocol, 6, 42 1.1 jmcneill ImageHandle, 43 1.1 jmcneill &LoadedImageProtocol, 44 1.1 jmcneill &LoadedImage, 45 1.1 jmcneill ImageHandle, 46 1.1 jmcneill NULL, 47 1.1 jmcneill EFI_OPEN_PROTOCOL_GET_PROTOCOL 48 1.1 jmcneill ); 49 1.1 jmcneill if (EFI_ERROR(Status)) 50 1.1 jmcneill return -1; 51 1.1 jmcneill 52 1.1 jmcneill BufLen = ((EFI_LOADED_IMAGE *)LoadedImage)->LoadOptionsSize; 53 1.1 jmcneill if (BufLen < 2) /* We are expecting at least a \0 */ 54 1.1 jmcneill return -1; 55 1.1 jmcneill else if (BufLen > sizeof(ArgvContents)) 56 1.1 jmcneill BufLen = sizeof(ArgvContents); 57 1.1 jmcneill 58 1.1 jmcneill CopyMem(ArgvContents, ((EFI_LOADED_IMAGE *)LoadedImage)->LoadOptions, BufLen); 59 1.1 jmcneill ArgvContents[MAX_CMDLINE_SIZE - 1] = L'\0'; 60 1.1 jmcneill 61 1.1 jmcneill for (c = ArgStart = ArgvContents ; *c != L'\0' ; ++c) { 62 1.1 jmcneill if (*c == L' ') { 63 1.1 jmcneill *c = L'\0'; 64 1.1 jmcneill if (Argc < MAX_CMDLINE_ARGC) Argv[Argc++] = ArgStart; 65 1.1 jmcneill ArgStart = c + 1; 66 1.1 jmcneill } 67 1.1 jmcneill } 68 1.1 jmcneill 69 1.1 jmcneill if ((*ArgStart != L'\0') && (Argc < MAX_CMDLINE_ARGC)) 70 1.1 jmcneill Argv[Argc++] = ArgStart; 71 1.1 jmcneill 72 1.1 jmcneill // Print(L"Got argc/argv from loaded image proto\n"); 73 1.1 jmcneill *ResultArgv = Argv; 74 1.1 jmcneill return Argc; 75 1.1 jmcneill } 76 1.1 jmcneill 77 1.1 jmcneill INTN GetShellArgcArgv(EFI_HANDLE ImageHandle, CHAR16 **Argv[]) 78 1.1 jmcneill { 79 1.1 jmcneill // Code inspired from EDK2's 80 1.1 jmcneill // ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c (BSD) 81 1.1 jmcneill EFI_STATUS Status; 82 1.1 jmcneill static const EFI_GUID ShellInterfaceProtocolGuid 83 1.1 jmcneill = SHELL_INTERFACE_PROTOCOL_GUID; 84 1.1 jmcneill EFI_SHELL_PARAMETERS_PROTOCOL *EfiShellParametersProtocol = NULL; 85 1.1 jmcneill EFI_SHELL_INTERFACE *EfiShellInterfaceProtocol = NULL; 86 1.1 jmcneill 87 1.1 jmcneill Status = uefi_call_wrapper(BS->OpenProtocol, 6, 88 1.1 jmcneill ImageHandle, 89 1.1.1.2 jmcneill (EFI_GUID*)&ShellParametersProtocolGuid, 90 1.1 jmcneill (VOID **)&EfiShellParametersProtocol, 91 1.1 jmcneill ImageHandle, 92 1.1 jmcneill NULL, 93 1.1 jmcneill EFI_OPEN_PROTOCOL_GET_PROTOCOL 94 1.1 jmcneill ); 95 1.1 jmcneill if (!EFI_ERROR(Status)) 96 1.1 jmcneill { 97 1.1 jmcneill // use shell 2.0 interface 98 1.1 jmcneill // Print(L"Got argc/argv from shell intf proto\n"); 99 1.1 jmcneill *Argv = EfiShellParametersProtocol->Argv; 100 1.1 jmcneill return EfiShellParametersProtocol->Argc; 101 1.1 jmcneill } 102 1.1 jmcneill 103 1.1 jmcneill // try to get shell 1.0 interface instead. 104 1.1 jmcneill Status = uefi_call_wrapper(BS->OpenProtocol, 6, 105 1.1 jmcneill ImageHandle, 106 1.1 jmcneill (EFI_GUID*)&ShellInterfaceProtocolGuid, 107 1.1 jmcneill (VOID **)&EfiShellInterfaceProtocol, 108 1.1 jmcneill ImageHandle, 109 1.1 jmcneill NULL, 110 1.1 jmcneill EFI_OPEN_PROTOCOL_GET_PROTOCOL 111 1.1 jmcneill ); 112 1.1 jmcneill if (!EFI_ERROR(Status)) 113 1.1 jmcneill { 114 1.1 jmcneill // Print(L"Got argc/argv from shell params proto\n"); 115 1.1 jmcneill *Argv = EfiShellInterfaceProtocol->Argv; 116 1.1 jmcneill return EfiShellInterfaceProtocol->Argc; 117 1.1 jmcneill } 118 1.1 jmcneill 119 1.1 jmcneill // shell 1.0 and 2.0 interfaces failed 120 1.1 jmcneill return GetShellArgcArgvFromLoadedImage(ImageHandle, Argv); 121 1.1 jmcneill } 122