UEFI实战——写一个自己的Shell命令

说明

本文在UDK2015的基础上,写一个Shell命令,并在Shell下运行。

UEFI下的Shell有两个版本,一个是Shellver 1的版本,对应EdkShellPkg;另一个是Shell Ver 2的版本,对应ShellPkg。

目前UDK2015中已经没有EdkShellPkg的源码了,需要另外下载。

所以本文以ShellPkg中的源代码为基础。

光一个Shell没有办法直接运行,本文将Shell依附在OVMF上,因此本文编译使用的是OvmfPkgX64.dsc。

使用OVMF的好处是可以通过qemu来运行,另外一个好处是,OvmfPkgX64.dsc已经包含了ShellPKg.dsc,因此不需要额外做什么操作。

关于OVMF的编译可以参考UEFI实战——OVMF基础。

 

添加源代码

前面已经讲到,Shell的源码位于ShellPkg目录下:

UEFI实战——写一个自己的Shell命令_第1张图片

其中:

Application包含的是Shell本身,以及一些简单的应用示例。这些应用——包括Shell本身——都可以在Shell下直接运行。

Include包含一些必须的头文件。

Library包含了Shell所需的基本库和Shell下可以执行的命令:

UEFI实战——写一个自己的Shell命令_第2张图片

在Shell Ver 2中,Shell命令都包含了库中。比如上面的UefiShellNetwork1CommandsLib,它内部就包含了ifconfig和ping两个命令。

在Shell Ver 2中,各个命令按照功能划分在不同的目录下。

本文就要按照上面的形式,来创建一个自己的Lib,并在其中实现命令。

 

创建OemLib

UEFI实战——写一个自己的Shell命令_第3张图片

这里需要说明的是inf和uni文件:

inf用于编译,表示的是一个模块。

uni是一个字符串的文件,用于显示Shell命令中的一些帮助命令或者错误信息。

之后需要将inf文件添加到ShellPkg.dsc中:

UEFI实战——写一个自己的Shell命令_第4张图片

这样才能编译到OVMF中去。

 

具体的代码

#include "UefiShellOemCommandLib.h"

CONST CHAR16 gShellOemFileName[] = L"ShellCommand";
EFI_HANDLE gShellOemHiiHandle = NULL;

/**
  Return the file name of the help text file if not using HII.

  @return The string pointer to the file name.
**/
CONST CHAR16*
EFIAPI
ShellCommandGetManFileNameOem (
  VOID
  )
{
  return gShellOemFileName;
}

/**
  Constructor for the Shell xxx Command library.

  Install the handlers for xxx UEFI Shell command.

  @param ImageHandle            The image handle of the process.
  @param SystemTable            The EFI System Table pointer.

  @retval EFI_SUCCESS           The Shell command handlers were installed sucessfully.
  @retval EFI_UNSUPPORTED       The Shell level required was not found.
**/
EFI_STATUS
EFIAPI
ShellOemCommandLibConstructor (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  gShellOemHiiHandle = NULL;

  //
  // check our bit of the profiles mask
  //
  if ((PcdGet8 (PcdShellProfileMask) & BIT3) == 0) {
    return EFI_SUCCESS;
  }

  gShellOemHiiHandle = HiiAddPackages (
                          &gShellOemHiiGuid, gImageHandle,			// gShellOemHiiGuid需要在ShellLibHiiGuid.h和ShellPkg.dec中定义,并声明在UefiShellOemCommandLib.inf
                          UefiShellOemCommandLibStrings, NULL		// UefiShellOemCommandLibStrings就对应到UefiShellOemCommandLib.uni
                          );
  if (gShellOemHiiHandle == NULL) {
    return EFI_DEVICE_ERROR;
  }
  //
  // Install our Shell command handler
  //
  ShellCommandRegisterCommandName (
     L"helloworld", ShellCommandRunHelloWorld, ShellCommandGetManFileNameOem, 0,
     L"helloworld", TRUE , gShellOemHiiHandle, STRING_TOKEN (STR_GET_HELP_OEM)	// STR_GET_HELP_OEM在UefiShellOemCommandLib.uni中定义
     );

  return EFI_SUCCESS;
}

/**
  Destructor for the library.  free any resources.

  @param ImageHandle            The image handle of the process.
  @param SystemTable            The EFI System Table pointer.
**/
EFI_STATUS
EFIAPI
ShellOemCommandLibDestructor (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  if (gShellOemHiiHandle != NULL) {
    HiiRemovePackages (gShellOemHiiHandle);
  }
  return EFI_SUCCESS;
}

其它文件的代码略。

 

运行结果

运行qemu,在打开qemu窗口后按键,会进行UEFI的Front Page。

UEFI实战——写一个自己的Shell命令_第5张图片

选择Boot Manager,进入Shell,运行helloworld的结果:

UEFI实战——写一个自己的Shell命令_第6张图片

以上的例子可以在https://code.csdn.net/jiangwei0512/bios_git.git这个git仓库中找到,具体的代码可能有些许差异。

20180614更新:

代码更新到了https://gitee.com/jiangwei0512/vUDK2017。

具体见ShellPkg\Library\UefiShellBeniCommandLib\目录下的代码。

 

你可能感兴趣的:(UEFI开发基础)