cmdline.c 3.8 KB

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