UEFI實戰——寫一個自己的Shell命令

jiangwei0512發表於2016-09-05

說明

本文在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目錄下:

其中:

Application包含的是Shell本身,以及一些簡單的應用示例。這些應用——包括Shell本身——都可以在Shell下直接執行。

Include包含一些必須的標頭檔案。

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

在Shell Ver 2中,Shell命令都包含了庫中。比如上面的UefiShellNetwork1CommandsLib,它內部就包含了ifconfig和ping兩個命令。

在Shell Ver 2中,各個命令按照功能劃分在不同的目錄下。

本文就要按照上面的形式,來建立一個自己的Lib,並在其中實現命令。

 

建立OemLib

這裡需要說明的是inf和uni檔案:

inf用於編譯,表示的是一個模組。

uni是一個字串的檔案,用於顯示Shell命令中的一些幫助命令或者錯誤資訊。

之後需要將inf檔案新增到ShellPkg.dsc中:

這樣才能編譯到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。

選擇Boot Manager,進入Shell,執行helloworld的結果:

以上的例子可以在https://code.csdn.net/jiangwei0512/bios_git.git這個git倉庫中找到,具體的程式碼可能有些許差異。

20180614更新:

程式碼更新到了https://gitee.com/jiangwei0512/vUDK2017。

具體見ShellPkg\Library\UefiShellBeniCommandLib\目錄下的程式碼。

 

相關文章