命令 shell_编写自己的 Shell 命令(下)

有些时候,我们编写的 EFI 程序不希望有人改动,这个时候就可以考虑将程序“藏”到 Shell 中。本文就实验将 RU.EFI 编译到 Shell 中。为了更好的理解本文的方案,最好先阅读理解前介绍过的如何将一个 EFI 程序包含在另外的 EFI中运行的方法【参考1】。具体方法是将下面的代码直接插入上一篇的 lzc.c 中:

      //      // print it...      //      if (ShellStatus == SHELL_SUCCESS) {        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LZC_OUTPUT),gShellLevel3HiiHandle);        //Your code        DP=FileDevicePath(NULL,L"fso:\\fake.efi");        Print(L"%s\n",ConvertDevicePathToText(DP,TRUE,FALSE));            //        // Load the image with:        // FALSE - not from boot manager and NULL, 0 being not already in memory        //        Status = gBS->LoadImage(                        FALSE,                        ImageHandle,                        DP,                        (VOID*)&Hello2_efi[0],                        sizeof(Hello2_efi),                        &NewHandle);             if (EFI_ERROR(Status)) {                Print(L"Load image Error!  [%r]\n",Status);                return 0;        }        //        // now start the image, passing up exit data if the caller requested it        //        Status = gBS->StartImage(                     NewHandle,                     &ExitDataSizePtr,                     NULL              );        if (EFI_ERROR(Status)) {                Print(L"\nError during StartImage [%X]\n",Status);                return 0;        }                       Status = gBS->UnloadImage(NewHandle);                                if (EFI_ERROR(Status)) {                Print(L"Un-Load image Error! %r\n",Status);                return 0;        }

但是,运行结果显示无法加载,错误原因是 Invalid Parameter。同样的代码单独编译后完全可以在 Shell 下运行。

经过VS2015 动态调试发现,gBS->LoadImage()传递的 ImageHandle 参数为 0,就是说下面这个函数入口处的 ImageHandle 直接被赋值为0.

/**  Function for 'lzc' command.  @param[in] ImageHandle  Handle to the Image (NULL if Internal).  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).**/SHELL_STATUSEFIAPIShellCommandRunLzc (  IN EFI_HANDLE        ImageHandle,  IN EFI_SYSTEM_TABLE  *SystemTable  )

经过研究,产生问题的原因是下面代码,因此在调用每一个命令的时候,入口上的 ImageHandle 直接就赋值为0.

edk202008\ShellPkg\Library\UefiShellCommandLib\UefiShellCommandLib.c

/**  Checks if a command string has been registered for CommandString and if so it runs  the previously registered handler for that command with the command line.  If CommandString is NULL, then ASSERT().  If Sections is specified, then each section name listed will be compared in a casesensitive  manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,  it will be appended to the returned help text. If the section does not exist, no  information will be returned. If Sections is NULL, then all help text information  available will be returned.  @param[in]  CommandString          Pointer to the command name.  This is the name                                     found on the command line in the shell.  @param[in, out] RetVal             Pointer to the return vaule from the command handler.  @param[in, out]  CanAffectLE       indicates whether this command's return value                                     needs to be placed into LASTERROR environment variable.  @retval RETURN_SUCCESS            The handler was run.  @retval RETURN_NOT_FOUND          The CommandString did not match a registered                                    command name.  @sa SHELL_RUN_COMMAND**/RETURN_STATUSEFIAPIShellCommandRunCommandHandler (  IN CONST CHAR16               *CommandString,  IN OUT SHELL_STATUS           *RetVal,  IN OUT BOOLEAN                *CanAffectLE OPTIONAL  )………………      if (RetVal != NULL) {        *RetVal = Node->CommandHandler(NULL, gST);      } else {        Node->CommandHandler(NULL, gST);      }      return (RETURN_SUCCESS);

搜索其他命令作为参考,都没有使用ImageHandle作为参数,但是有使用 gImageHandle。于是,就使用 gImageHandle 作为参数。最终代码如下:

/** @file  Main file for LABZ Command Test shell level 3 function.  (C) Copyright 2015 Hewlett-Packard Development Company, L.P.  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.   SPDX-License-Identifier: BSD-2-Clause-Patent**/#include "UefiShellLevel3CommandsLib.h"#include  #include #include  /**  Function for 'lzc' command.  @param[in] ImageHandle  Handle to the Image (NULL if Internal).  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).**/SHELL_STATUSEFIAPIShellCommandRunLzc (  IN EFI_HANDLE        ImageHandle,  IN EFI_SYSTEM_TABLE  *SystemTable  ){  EFI_STATUS          Status;  LIST_ENTRY          *Package;  CHAR16              *ProblemParam;  SHELL_STATUS        ShellStatus;  EFI_DEVICE_PATH  *DP;  EFI_HANDLE      NewHandle;  UINTN           ExitDataSizePtr;           ProblemParam        = NULL;  ShellStatus         = SHELL_SUCCESS;  //CpuBreakpoint();  //  // initialize the shell lib (we must be in non-auto-init...)  //  Status = ShellInitialize();  ASSERT_EFI_ERROR(Status);  //  // parse the command line  //  Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);  if (EFI_ERROR(Status)) {    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"lzc", ProblemParam);      FreePool(ProblemParam);      ShellStatus = SHELL_INVALID_PARAMETER;    } else {      ASSERT(FALSE);    }  } else {    //    // check for "-?"    //    if (ShellCommandLineGetFlag(Package, L"-?")) {      ASSERT(FALSE);    } else if (ShellCommandLineGetRawValue(Package, 1) != NULL) {      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"lzc");      ShellStatus = SHELL_INVALID_PARAMETER;    } else {      //      // print it...      //      if (ShellStatus == SHELL_SUCCESS) {        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LZC_OUTPUT),gShellLevel3HiiHandle);                //Your code start        DP=FileDevicePath(NULL,L"fso:\\fake.efi");        Print(L"%s\n",ConvertDevicePathToText(DP,TRUE,FALSE));            //        // Load the image with:        // FALSE - not from boot manager and NULL, 0 being not already in memory        //        Status = gBS->LoadImage(                        FALSE,                        gImageHandle,                        DP,                        (VOID*)&RU_efi[0],                        sizeof(RU_efi),                        &NewHandle);        if (EFI_ERROR(Status)) {                Print(L"Load image Error!  [%r]\n",Status);                return 0;        }        //        // now start the image, passing up exit data if the caller requested it        //        Status = gBS->StartImage(                     NewHandle,                     &ExitDataSizePtr,                     NULL              );        if (EFI_ERROR(Status)) {                Print(L"\nError during StartImage [%X]\n",Status);                return 0;        }                       Status = gBS->UnloadImage(NewHandle);                                if (EFI_ERROR(Status)) {                Print(L"Un-Load image Error! %r\n",Status);                return 0;        }         //Your code end              }    }    //    // free the command line package    //    ShellCommandLineFreeVarList (Package);  }  return (ShellStatus);}

编译之后可以在 WinHost 下运行 lzc 命令(RU涉及到硬件的直接访问,界面闪现就会退出)。

7d2215e9d49902d68fae2bca32ba7208.png

模拟器里面的 Shell 运行自定义的 command

使用 build -a X64 -p ShellPkg\ShellPkg.dsc 命令后可以得到包含了 lzc 命令的 Shell ,放置到 U盘 \EFI\Boot\ 下,改名为  BootX64.efi 后即可从 U盘直接启, 有兴趣的朋友可以自己动手实验。

本文提到的代码可以在原文链接看到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值