第十六章 Shell 及常用 Shell 命令

作者:Maxwell Li
日期:2017/12/20
未經(jīng)作者允許,禁止轉(zhuǎn)載本文任何內(nèi)容。如需轉(zhuǎn)載請(qǐng)留言。


[TOC]

16.1 Shell 的編譯與執(zhí)行

ShellPkg 目錄下包含了 Shell 的源代碼,可以通過以下命令編譯獲得 shell.efi。

build -a IA32 -p ShellPkg\ShellPkg.dsc
build -a X64 -p ShellPkg\ShellPkg.dsc

將32位或64位的 shell.efi 復(fù)制到 ESP 分區(qū)的 efi\boot 目錄下并重命名為 BootIA32.efi 或 BootX64.efi,啟動(dòng) UEFI 系統(tǒng)時(shí)就會(huì)執(zhí)行 BootIA32.efi 或 BootX64.efi 從而進(jìn)入 Shell。

該方式啟動(dòng) Shell 時(shí)通常不帶參數(shù)(使用系統(tǒng)參數(shù))。

  • UEFI 進(jìn)入 Shell 時(shí),會(huì)將 Shell Protocol 安裝到 Shell 的 ImageHandle 上。然后 UEFI 系統(tǒng)中的應(yīng)用才可以使用 Shell Protocol 服務(wù)。
  • 進(jìn)入 UEFI 后, Shell 首先檢查 efi\Boot\ 目錄下是否有 startup.nsh 腳本。
    • 如果有,則執(zhí)行該腳本,然后進(jìn)入 Shell 命令行等待用戶輸入;
    • 如果沒有,則直接進(jìn)入命令行等待用戶輸入。
  • 執(zhí)行外部命令時(shí):
    1. Shell 先用 Load Image Protocol 將可執(zhí)行文件載入內(nèi)存生成 Image;
    2. 在該 Image 上安裝 Shell Parameter Protocol;
    3. 調(diào)用這個(gè) Image 的入口函數(shù)從而執(zhí)行該外部命令。

Shell 啟動(dòng)參數(shù):

shell.efi [ShellOpt-options] [options] [file-name [file-name-options]]

Shell 啟動(dòng)參數(shù)表

啟動(dòng)參數(shù) 作用
-nostartup 進(jìn)入 Shell 時(shí)不執(zhí)行腳本 startup.nsh
-noconsoleout Shell 標(biāo)準(zhǔn)輸出不顯示
-noconsolein Shell 無標(biāo)準(zhǔn)輸入
-delay[:n] 指定等待 startup.nsh 啟動(dòng)的時(shí)間。默認(rèn)是5秒,-delay:0 表示立即執(zhí)行
-nointerrupt 不支持 <Ctrl+C> 的終止程序功能
-nomap 啟動(dòng)后不顯示塊設(shè)備的 map 信息
-noversion 啟動(dòng)后不顯示 version
-startup 進(jìn)入 Shell 是執(zhí)行腳本 startup.nsh

當(dāng) ShellOpt-optitions 和 options 中均不包含 -startup 時(shí),可以使用 file-name [file-name-options] 指定 Shell 啟動(dòng)后要執(zhí)行的文件。如果啟動(dòng)參數(shù)中既有 -startup 又有 file-name [file-name-options],則 file-name [file-name-options] 被忽略。

16.2 Shell 服務(wù)

Shell 為程序開發(fā)者提供了兩種使用 Shell 服務(wù)的方式:使用 Shell Protocol 和 Shell Parameters Protocol;使用 UEFIShellLib 提供的函數(shù)。

Shell Protocol 提供服務(wù)

EFI_SHELL_PROTOCOL 結(jié)構(gòu)體如下:

typedef struct _EFI_SHELL_PROTOCOL {
  EFI_SHELL_EXECUTE                         Execute;                    // 執(zhí)行 Shell 命令行命令
  EFI_SHELL_GET_ENV                         GetEnv;                     // 獲得環(huán)境變量的值
  EFI_SHELL_SET_ENV                         SetEnv;                     // 設(shè)置環(huán)境變量的值
  EFI_SHELL_GET_ALIAS                       GetAlias;                   // 獲得 Shell 命令的別名
  EFI_SHELL_SET_ALIAS                       SetAlias;                   // 設(shè)置 Shell 命令的別名
  EFI_SHELL_GET_HELP_TEXT                   GetHelpText;                // 獲得 Shell 命令的幫助信息
  EFI_SHELL_GET_DEVICE_PATH_FROM_MAP        GetDevicePathFromMap;       // 從 Map 名獲得 DevicePath
  EFI_SHELL_GET_MAP_FROM_DEVICE_PATH        GetMapFromDevicePath;       // 從 DevicePath 獲得 Map 名
  EFI_SHELL_GET_DEVICE_PATH_FROM_FILE_PATH  GetDevicePathFromFilePath;
  EFI_SHELL_GET_FILE_PATH_FROM_DEVICE_PATH  GetFilePathFromDevicePath;
  EFI_SHELL_SET_MAP                         SetMap;                     // 設(shè)置設(shè)備的 Map 名
  EFI_SHELL_GET_CUR_DIR                     GetCurDir;
  EFI_SHELL_SET_CUR_DIR                     SetCurDir;
  EFI_SHELL_OPEN_FILE_LIST                  OpenFileList;
  EFI_SHELL_FREE_FILE_LIST                  FreeFileList;
  EFI_SHELL_REMOVE_DUP_IN_FILE_LIST         RemoveDupInFileList;
  EFI_SHELL_BATCH_IS_ACTIVE                 BatchIsActive;              // 是否正在執(zhí)行腳本
  EFI_SHELL_IS_ROOT_SHELL                   IsRootShell;                // 是否為 Root
  EFI_SHELL_ENABLE_PAGE_BREAK               EnablePageBreak;            // 啟動(dòng)分屏顯示模式
  EFI_SHELL_DISABLE_PAGE_BREAK              DisablePageBreak;           // 禁止分屏顯示模式
  EFI_SHELL_GET_PAGE_BREAK                  GetPageBreak;               // 獲取當(dāng)前分屏顯示模式狀態(tài)
  EFI_SHELL_GET_DEVICE_NAME                 GetDeviceName;              // 獲取設(shè)備的名字
  EFI_SHELL_GET_FILE_INFO                   GetFileInfo;
  EFI_SHELL_SET_FILE_INFO                   SetFileInfo;
  EFI_SHELL_OPEN_FILE_BY_NAME               OpenFileByName;
  EFI_SHELL_CLOSE_FILE                      CloseFile;
  EFI_SHELL_CREATE_FILE                     CreateFile;
  EFI_SHELL_READ_FILE                       ReadFile;
  EFI_SHELL_WRITE_FILE                      WriteFile;
  EFI_SHELL_DELETE_FILE                     DeleteFile;
  EFI_SHELL_DELETE_FILE_BY_NAME             DeleteFileByName;
  EFI_SHELL_GET_FILE_POSITION               GetFilePosition;
  EFI_SHELL_SET_FILE_POSITION               SetFilePosition;
  EFI_SHELL_FLUSH_FILE                      FlushFile;
  EFI_SHELL_FIND_FILES                      FindFiles;
  EFI_SHELL_FIND_FILES_IN_DIR               FindFilesInDir;
  EFI_SHELL_GET_FILE_SIZE                   GetFileSize;
  EFI_SHELL_OPEN_ROOT                       OpenRoot;                   // 打開設(shè)備的根目錄
  EFI_SHELL_OPEN_ROOT_BY_HANDLE             OpenRootByHandle;           // 打開 Handle 指定的設(shè)備根目錄
  EFI_EVENT                                 ExecutionBreak;             // 用戶按下“Ctrl+C”時(shí)觸發(fā)該事件
  UINT32                                    MajorVersion;
  UINT32                                    MinorVersion;
  // Added for Shell 2.1
  EFI_SHELL_REGISTER_GUID_NAME              RegisterGuidName;
  EFI_SHELL_GET_GUID_NAME                   GetGuidName;
  EFI_SHELL_GET_GUID_FROM_NAME              GetGuidFromName;
  EFI_SHELL_GET_ENV_EX                      GetEnvEx;
} EFI_SHELL_PROTOCOL;

EFI_SHELL_PROTOCOL 的 Execute 服務(wù)函數(shù)原型如下:

typedef EFI_STATUS (EFIAPI *EFI_SHELL_EXECUTE) (
  IN EFI_HANDLE   *ParentImageHandle,      // 執(zhí)行 Execute 函數(shù)的 ImageHandle
  IN CHAR16       *CommandLine OPTIONAL,   // Shell 命令行命令
  IN CHAR16       **Environment OPTIONAL,  // 環(huán)境變量
  OUT EFI_STATUS  *StatusCode OPTIONAL     // Shell 命令返回值
  );

該函數(shù)會(huì)啟動(dòng)一個(gè)子 Shell,并在子 Shell 中執(zhí)行指定命令,命令的退出碼將作為 Execute 函數(shù)的返回值。

  • 參數(shù) ParentImageHandle 是執(zhí)行 Execute 命令的 Image 的 ImageHandle,通常是 gImageHandle;
  • 參數(shù) CommandLine 是啟動(dòng) Shell 時(shí)的命令行參數(shù);
  • 參數(shù) Environment 是字符串?dāng)?shù)組,數(shù)組以 NULL 為最后一項(xiàng),其余每一項(xiàng)表示一個(gè)環(huán)境變量,格式為 Var=Value;
    • 如果 Environment 為 NULL,當(dāng)前的環(huán)境變量會(huì)傳遞到子 Shell 中,從子 Shell 返回時(shí),對(duì)環(huán)境變量的更改被保存。
    • 如果 Environment 不為 NULL,子 Shell 使用指定的環(huán)境變量,從子 Shell 返回時(shí),對(duì)環(huán)境變量的更改被丟棄。
  • 參數(shù) StatusCode 是 Shell 命令的返回值,該返回值通過 exit 命令設(shè)置。

基本上對(duì)于所有 Shell Protocol 中的函數(shù),在 UefiShellLib 中都有與之對(duì)應(yīng)的函數(shù)。例如 Shell Protocol 中的 Execute 函數(shù), UefiShellLib 提供了對(duì)應(yīng)的 ShellExecute 函數(shù),函數(shù)原型如下:

EFI_STATUS EFIAPI ShellExecute (
  IN EFI_HANDLE   *ParentHandle,
  IN CHAR16       *CommandLine OPTIONAL,
  IN BOOLEAN      Output OPTIONAL,
  IN CHAR16       **EnvironmentVariables OPTIONAL,
  OUT EFI_STATUS  *Status OPTIONAL
  )

Output 為 TURE,表示現(xiàn)實(shí)調(diào)試信息。

UefiShellLib 的初始化

gEfiShellProtocol 是 EFI_SHELL_PROTOCOL* 類型的變量,由 UefiShellLib 提供。Library 可以提供構(gòu)造函數(shù),構(gòu)造函數(shù)在 ENTRY_POINT 之前執(zhí)行。在 UefiSHellLib 的工程文件中定義了 CONSTRUCTOR 和 DESTRUCTOR。引用 UeifShellLib 時(shí),“Status=ShellLibConstructor(ImageHandle, SystemTable);”會(huì)被添加到 ProcessLibraryConstructorList 函數(shù)中,從而在調(diào)用 ShellAppMain 之前執(zhí)行。

16.3 Shell 腳本

在 UEFI Shell 中可以執(zhí)行 Shell 腳本,Shell 腳本是以 .nsh 為擴(kuò)展名的文件,在腳本中可以執(zhí)行 Shell 命令和外部命令,也可以使用內(nèi)置的流程控制命令 for、endfor、goto、if、else、endif、exit。

if 語句比較運(yùn)算符

運(yùn)算符 含義
gt 大于
lt 小于
ne 等于
ugt 無符號(hào)值大于
ult 無符號(hào)值小于
eq 相等
ge 大于或等于
le 小于或等于
= = 相等
uge 無符號(hào)值大于或等于
ule 無符號(hào)值小于或等于

if語句布爾函數(shù)說明

布爾函數(shù) 當(dāng)返回值為 TRUE 時(shí) 當(dāng)返回值為 FALSE 時(shí)
isInt(para) para 是數(shù)字 para 不是數(shù)字
Exists file file 存在 file 不存在
Avaliable file file 存在于 path 指定的目錄或當(dāng)前目錄 均不存在
Profile para para 匹配 profile 中某項(xiàng) para 不匹配 profile 中任一項(xiàng)

16.4 Shell 內(nèi)置命令

16.4.1 調(diào)試設(shè)備的相關(guān)命令

deme 命令用于查看內(nèi)存或設(shè)備內(nèi)存。address、size 都是十六進(jìn)制數(shù),-MMIO 指定地址為設(shè)備內(nèi)存。

dmem [-b] [address] [size] [-MMIO]

mm 命令用于查看或修改 MEM(系統(tǒng)內(nèi)存)、MMIO(設(shè)備內(nèi)存)、IO(寄存器)、PCI(PCI 配置空間)、PCIE(PCIE 配置空間)。

mm address [value] [-w 1|2|4|8] [-MEM| -MMIO | -IO | -PCI | -PCIE] [-n]

address 為地址;value 為要寫入的值;-w 后跟訪問寬度;-n 表示非交互模式,若不指定 -n,則該命令會(huì)進(jìn)入交互模式。

pci 命令顯示 PCI 設(shè)備列表或顯示 PCI 配置空間。

pci [Bus Dev [Func] [-s Seg] [-i]]

不帶參數(shù)的 pci 命令用于列出所有 PCI 設(shè)備。帶參數(shù)時(shí),總線號(hào)(Bus)\設(shè)備號(hào)(Dev)\功能號(hào)(Func)用于指定 PCI 設(shè)備。-s Seg 用于指定 Segment。Func 和 Seg 默認(rèn)值為0。

16.4.2 驅(qū)動(dòng)相關(guān)命令

dh 命令用于列出系統(tǒng)中的所有設(shè)備信息,或某個(gè)設(shè)備的相關(guān)信息。

dh [-l<lang>] [handle | -p <prot_id>] [-d] [-v]
  • -l<lang> 表使用指定的語言顯示。
  • handle 是指 UEFI Handle 在系統(tǒng)中的編號(hào)。
  • -p <prot_id> 列出所有安裝了 protocol prot_id 的設(shè)備信息。
  • -d 用于列出驅(qū)動(dòng)相關(guān)信息。
  • -v 用于輸出 verbose 信息。

device 命令用于顯示所有被驅(qū)動(dòng)管理的設(shè)備。

drivers 命令用于列出系統(tǒng)中的 driver。

Connect 命令用于加載驅(qū)動(dòng)到設(shè)備上并啟動(dòng)加載的驅(qū)動(dòng)。

Connect [[DeviceHandle] [DriverHandle] | [-c] | [-r]]
  • -c 用于連接控制臺(tái)設(shè)備。
  • -r 用于遞歸掃描所有 handle,發(fā)現(xiàn)匹配的設(shè)備和驅(qū)動(dòng)就加進(jìn)來,沒有 -r,新產(chǎn)生的設(shè)備將不會(huì)被連接。

load 命令用于加載驅(qū)動(dòng)。

load [-nc] file [file2 ...]

-nc 表示只加載驅(qū)動(dòng)到內(nèi)存,不進(jìn)行 connect。不帶 -nc 選項(xiàng)時(shí),load 加載驅(qū)動(dòng)后會(huì)調(diào)用 connect 將該驅(qū)動(dòng)加載到匹配的設(shè)備上。

unload 命令用于將驅(qū)動(dòng)從內(nèi)存中清楚。

unload [-n] [-v] Handle

-n 表示在執(zhí)行 unload 過程中跳過所有提示信息,不需要用戶確認(rèn)。

16.4.3 網(wǎng)絡(luò)相關(guān)命令

ifconfig 命令用于配置網(wǎng)絡(luò)設(shè)備。

ifconfig [-?] [-c [Name]] [-l [Name]] [-s <Name> dhcp | <static <IP><MASK><Geteway>> [permanent]]
  • Name是網(wǎng)絡(luò)適配器的名字。
  • -c 用于清除網(wǎng)絡(luò)適配器的配置。
  • -l 用于列出網(wǎng)絡(luò)適配器的配置。
  • -s 用于設(shè)備網(wǎng)絡(luò)適配器的IP地址。

ping命令用于 ping 目標(biāo)機(jī)器。

ping [ -n number] [-l size] TargetIP
  • -l size 用于發(fā)送 size 字節(jié)的數(shù)據(jù)。
  • -n number 表示發(fā)送數(shù)據(jù)的次數(shù)。
16-1.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。