第十六章 Shell 及常用 Shell 命令

作者:Maxwell Li
日期:2017/12/20
未经作者允许,禁止转载本文任何内容。如需转载请留言。


[TOC]

16.1 Shell 的编译与执行

ShellPkg 目录下包含了 Shell 的源代码,可以通过以下命令编译获得 shell.efi。

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

将32位或64位的 shell.efi 复制到 ESP 分区的 efi\boot 目录下并重命名为 BootIA32.efi 或 BootX64.efi,启动 UEFI 系统时就会执行 BootIA32.efi 或 BootX64.efi 从而进入 Shell。

该方式启动 Shell 时通常不带参数(使用系统参数)。

  • UEFI 进入 Shell 时,会将 Shell Protocol 安装到 Shell 的 ImageHandle 上。然后 UEFI 系统中的应用才可以使用 Shell Protocol 服务。
  • 进入 UEFI 后, Shell 首先检查 efi\Boot\ 目录下是否有 startup.nsh 脚本。
    • 如果有,则执行该脚本,然后进入 Shell 命令行等待用户输入;
    • 如果没有,则直接进入命令行等待用户输入。
  • 执行外部命令时:
    1. Shell 先用 Load Image Protocol 将可执行文件载入内存生成 Image;
    2. 在该 Image 上安装 Shell Parameter Protocol;
    3. 调用这个 Image 的入口函数从而执行该外部命令。

Shell 启动参数:

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

Shell 启动参数表

启动参数 作用
-nostartup 进入 Shell 时不执行脚本 startup.nsh
-noconsoleout Shell 标准输出不显示
-noconsolein Shell 无标准输入
-delay[:n] 指定等待 startup.nsh 启动的时间。默认是5秒,-delay:0 表示立即执行
-nointerrupt 不支持 <Ctrl+C> 的终止程序功能
-nomap 启动后不显示块设备的 map 信息
-noversion 启动后不显示 version
-startup 进入 Shell 是执行脚本 startup.nsh

当 ShellOpt-optitions 和 options 中均不包含 -startup 时,可以使用 file-name [file-name-options] 指定 Shell 启动后要执行的文件。如果启动参数中既有 -startup 又有 file-name [file-name-options],则 file-name [file-name-options] 被忽略。

16.2 Shell 服务

Shell 为程序开发者提供了两种使用 Shell 服务的方式:使用 Shell Protocol 和 Shell Parameters Protocol;使用 UEFIShellLib 提供的函数。

Shell Protocol 提供服务

EFI_SHELL_PROTOCOL 结构体如下:

typedef struct _EFI_SHELL_PROTOCOL {
  EFI_SHELL_EXECUTE                         Execute;                    // 执行 Shell 命令行命令
  EFI_SHELL_GET_ENV                         GetEnv;                     // 获得环境变量的值
  EFI_SHELL_SET_ENV                         SetEnv;                     // 设置环境变量的值
  EFI_SHELL_GET_ALIAS                       GetAlias;                   // 获得 Shell 命令的别名
  EFI_SHELL_SET_ALIAS                       SetAlias;                   // 设置 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;                     // 设置设备的 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;              // 是否正在执行脚本
  EFI_SHELL_IS_ROOT_SHELL                   IsRootShell;                // 是否为 Root
  EFI_SHELL_ENABLE_PAGE_BREAK               EnablePageBreak;            // 启动分屏显示模式
  EFI_SHELL_DISABLE_PAGE_BREAK              DisablePageBreak;           // 禁止分屏显示模式
  EFI_SHELL_GET_PAGE_BREAK                  GetPageBreak;               // 获取当前分屏显示模式状态
  EFI_SHELL_GET_DEVICE_NAME                 GetDeviceName;              // 获取设备的名字
  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;                   // 打开设备的根目录
  EFI_SHELL_OPEN_ROOT_BY_HANDLE             OpenRootByHandle;           // 打开 Handle 指定的设备根目录
  EFI_EVENT                                 ExecutionBreak;             // 用户按下“Ctrl+C”时触发该事件
  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 服务函数原型如下:

typedef EFI_STATUS (EFIAPI *EFI_SHELL_EXECUTE) (
  IN EFI_HANDLE   *ParentImageHandle,      // 执行 Execute 函数的 ImageHandle
  IN CHAR16       *CommandLine OPTIONAL,   // Shell 命令行命令
  IN CHAR16       **Environment OPTIONAL,  // 环境变量
  OUT EFI_STATUS  *StatusCode OPTIONAL     // Shell 命令返回值
  );

该函数会启动一个子 Shell,并在子 Shell 中执行指定命令,命令的退出码将作为 Execute 函数的返回值。

  • 参数 ParentImageHandle 是执行 Execute 命令的 Image 的 ImageHandle,通常是 gImageHandle;
  • 参数 CommandLine 是启动 Shell 时的命令行参数;
  • 参数 Environment 是字符串数组,数组以 NULL 为最后一项,其余每一项表示一个环境变量,格式为 Var=Value;
    • 如果 Environment 为 NULL,当前的环境变量会传递到子 Shell 中,从子 Shell 返回时,对环境变量的更改被保存。
    • 如果 Environment 不为 NULL,子 Shell 使用指定的环境变量,从子 Shell 返回时,对环境变量的更改被丢弃。
  • 参数 StatusCode 是 Shell 命令的返回值,该返回值通过 exit 命令设置。

基本上对于所有 Shell Protocol 中的函数,在 UefiShellLib 中都有与之对应的函数。例如 Shell Protocol 中的 Execute 函数, UefiShellLib 提供了对应的 ShellExecute 函数,函数原型如下:

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,表示现实调试信息。

UefiShellLib 的初始化

gEfiShellProtocol 是 EFI_SHELL_PROTOCOL* 类型的变量,由 UefiShellLib 提供。Library 可以提供构造函数,构造函数在 ENTRY_POINT 之前执行。在 UefiSHellLib 的工程文件中定义了 CONSTRUCTOR 和 DESTRUCTOR。引用 UeifShellLib 时,“Status=ShellLibConstructor(ImageHandle, SystemTable);”会被添加到 ProcessLibraryConstructorList 函数中,从而在调用 ShellAppMain 之前执行。

16.3 Shell 脚本

在 UEFI Shell 中可以执行 Shell 脚本,Shell 脚本是以 .nsh 为扩展名的文件,在脚本中可以执行 Shell 命令和外部命令,也可以使用内置的流程控制命令 for、endfor、goto、if、else、endif、exit。

if 语句比较运算符

运算符 含义
gt 大于
lt 小于
ne 等于
ugt 无符号值大于
ult 无符号值小于
eq 相等
ge 大于或等于
le 小于或等于
= = 相等
uge 无符号值大于或等于
ule 无符号值小于或等于

if语句布尔函数说明

布尔函数 当返回值为 TRUE 时 当返回值为 FALSE 时
isInt(para) para 是数字 para 不是数字
Exists file file 存在 file 不存在
Avaliable file file 存在于 path 指定的目录或当前目录 均不存在
Profile para para 匹配 profile 中某项 para 不匹配 profile 中任一项

16.4 Shell 内置命令

16.4.1 调试设备的相关命令

deme 命令用于查看内存或设备内存。address、size 都是十六进制数,-MMIO 指定地址为设备内存。

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

mm 命令用于查看或修改 MEM(系统内存)、MMIO(设备内存)、IO(寄存器)、PCI(PCI 配置空间)、PCIE(PCIE 配置空间)。

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

address 为地址;value 为要写入的值;-w 后跟访问宽度;-n 表示非交互模式,若不指定 -n,则该命令会进入交互模式。

pci 命令显示 PCI 设备列表或显示 PCI 配置空间。

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

不带参数的 pci 命令用于列出所有 PCI 设备。带参数时,总线号(Bus)\设备号(Dev)\功能号(Func)用于指定 PCI 设备。-s Seg 用于指定 Segment。Func 和 Seg 默认值为0。

16.4.2 驱动相关命令

dh 命令用于列出系统中的所有设备信息,或某个设备的相关信息。

dh [-l<lang>] [handle | -p <prot_id>] [-d] [-v]
  • -l<lang> 表使用指定的语言显示。
  • handle 是指 UEFI Handle 在系统中的编号。
  • -p <prot_id> 列出所有安装了 protocol prot_id 的设备信息。
  • -d 用于列出驱动相关信息。
  • -v 用于输出 verbose 信息。

device 命令用于显示所有被驱动管理的设备。

drivers 命令用于列出系统中的 driver。

Connect 命令用于加载驱动到设备上并启动加载的驱动。

Connect [[DeviceHandle] [DriverHandle] | [-c] | [-r]]
  • -c 用于连接控制台设备。
  • -r 用于递归扫描所有 handle,发现匹配的设备和驱动就加进来,没有 -r,新产生的设备将不会被连接。

load 命令用于加载驱动。

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

-nc 表示只加载驱动到内存,不进行 connect。不带 -nc 选项时,load 加载驱动后会调用 connect 将该驱动加载到匹配的设备上。

unload 命令用于将驱动从内存中清楚。

unload [-n] [-v] Handle

-n 表示在执行 unload 过程中跳过所有提示信息,不需要用户确认。

16.4.3 网络相关命令

ifconfig 命令用于配置网络设备。

ifconfig [-?] [-c [Name]] [-l [Name]] [-s <Name> dhcp | <static <IP><MASK><Geteway>> [permanent]]
  • Name是网络适配器的名字。
  • -c 用于清除网络适配器的配置。
  • -l 用于列出网络适配器的配置。
  • -s 用于设备网络适配器的IP地址。

ping命令用于 ping 目标机器。

ping [ -n number] [-l size] TargetIP
  • -l size 用于发送 size 字节的数据。
  • -n number 表示发送数据的次数。
16-1.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容

  • 作者:Maxwell Li日期:2017/12/09未经作者允许,禁止转载本文任何内容。如需转载请留言。 [TOC...
    Maxwell_Li阅读 2,578评论 0 0
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,380评论 0 5
  • 作者:Maxwell Li日期:2017/12/05未经作者允许,禁止转载本文任何内容。如需转载请留言。 [TOC...
    Maxwell_Li阅读 6,477评论 0 1
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,158评论 2 33
  • 4.x86 CPU架构设计 4.1.x86硬件需求 对于通用交换机硬件需求,请参阅“交换机硬件需求”章节描述。 x...
    半天妖阅读 5,416评论 0 1