文章

ASL语言学习(5)- OVMF + QEMU 实战

本文介绍如何基于 Edk2 的 OvmfPkg 来调试 ASL 代码。

ASL语言学习(5)- OVMF + QEMU 实战

续上四篇,这一篇介绍下如何基于 Edk2 的 OvmfPkg 来调试 ASL 代码。
ASL语言学习(1)- 基本语法,作用域
ASL语言学习(2)- Debug,常用操作符
ASL语言学习(3)- 隐式转换,Method调用
ASL语言学习(4)- OpRegion 实战

Reference:
ACPI Source Language (ASL) Tutorial
ACPI Source Language (ASL) Reference
Edk2 OvmfPkg
Ubuntu Wiki - OVMF

构建 OvmfPkg 的 Bios Binary

首先我们构建Edk2的OvmfPkg。

如果完全不了解Edk2,可以先参考Getting Started with EDK II

这里简要介绍下基于WSL+GCC以及基于VS2022 Community的构建流程。

基于 WSL+GCC 构建

先贴一下我这个环境的信息

1
2
3
Linux version 5.15.153.1-microsoft-standard-WSL2
Ubuntu 22.04.5 LTS
gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)

配置环境可以参考Using EDK II with Native GCC

这里贴一下我安装的依赖

1
2
# note: iasl is replaced by acpica-tools
sudo apt install build-essential uuid-dev acpica-tools git nasm python-is-python3

在WSL中进入edk2的上一层,利用下面的命令构建(这一步可以参考Edk2 OvmfPkg )。

1
2
3
4
5
6
7
8
export WORKSPACE=$(pwd)
export PACKAGES_PATH=$WORKSPACE/edk2

cd edk2
make -C BaseTools/
. edksetup.sh

build -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc -D DEBUG_ON_SERIAL_PORT

构建好的 BIOS Binary 位于 $WORKSPACE/Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd

基于 VS2022 构建

先贴一下我这个环境的信息

1
2
3
4
5
6
Microsoft Windows [版本 10.0.19045.5371]
cl:     用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.42.34436 版
nmake:  Microsoft (R) 程序维护实用工具 14.42.34436.0 版
iasl:   ASL+ Optimizing Compiler/Disassembler version 20241212
nasm:   NASM version 2.16.01 compiled on Dec 21 2022
python: Python 3.10.13 | packaged by Anaconda, Inc.

VS2022使用的是community版本,必须安装的工作负载如下:

  • C++ 桌面开发(Desktop development with C++)
  • 使用 C++ 的 Windows 生成工具(MSVC v143)
  • Windows 10 SDK 或 Windows 11 SDK
  • Windows 通用 C 运行时
  • C++ CMake 工具

其他可酌情选择。

在command prompt/powershell中进入edk2的上一层,利用下面的命令构建(这一步可以参考Edk2 OvmfPkg )。

1
2
3
4
5
6
7
8
set WORKSPACE=%CD%
set PACKAGES_PATH=%WORKSPACE%\edk2

cd edk2
edksetup.bat
nmake -f %BASE_TOOLS_PATH%\Makefile

build -a X64 -t VS2022 -p OvmfPkg\OvmfPkgX64.dsc -D DEBUG_ON_SERIAL_PORT

构建好的 BIOS Binary 位于 %WORKSPACE%\Build\OvmfX64\DEBUG_VS2022\FV\OVMF.fd

一些相关下载链接:

iasl: ACPI Component Architecture Downloads
nasm: Netwide Assembler
Visual Studio Community

启动 QEMU 并安装 Ubuntu

接下来我们安装QEMU,并在QEMU中安装Ubuntu

安装 QEMU

QEMU可以在这里下载:QEMU Binaries for Windows (64 bit)

安装好之后可以添加安装目录到环境变量PATH中。

QEMU 中安装 Ubuntu

创建虚拟磁盘:

1
qemu-img create -f qcow2 \path\to\ubuntu-disk.qcow2 20G

启动 QEMU 安装 Ubuntu:

这里分配 4GB 内存,使用 4 核 CPU,使用用户模式网络,指定 e1000 网卡,启用 USB 鼠标,并使用 Ubuntu 22.04.5 ISO 作为安装光盘。BIOS 则使用我们前面编译的 OVMF 的 Binary。

1
2
3
4
5
6
7
qemu-system-x86_64 -pflash \path\to\OVMF.fd^
 -m 4096 -smp 4^
 -cdrom \path\to\ubuntu-22.04.5-desktop-amd64.iso ^
 -drive file=\path\to\ubuntu-disk.qcow2,format=qcow2 ^
 -vga virtio ^
 -netdev user,id=net0 -device e1000,netdev=net0 ^
 -usb -device usb-tablet

安装 Ubuntu 即一般的在虚拟机中安装的方式,一路下一步就可以了。

安装后,则直接可以从虚拟磁盘启动:

下面脚本增加了 serial output,并同时保存到serial.log文件。

1
2
3
4
5
6
7
8
qemu-system-x86_64 -pflash \path\to\OVMF.fd^
 -m 4096 -smp 4^
 -drive file=\path\to\ubuntu-disk.qcow2,format=qcow2 ^
 -vga virtio ^
 -netdev user,id=net0 -device e1000,netdev=net0 ^
 -usb -device usb-tablet^
 -chardev stdio,id=char0,logfile=\path\to\serial.log,signal=off ^
 -serial chardev:char0

调试 ASL

接下来就是在 QEMU 的 Ubuntu 中调试 ASL 代码了。

直接查看 APCI Table

相关的代码:TestAcpi in OvmfPkg

参考下面脚本

1
2
3
4
# ACPI table 都在这个路径
cd /sys/firmware/acpi/tables
# hexdump SSDT
sudo xxd SSDT

1

利用 acpidbg 调试

安装 acpidbg 工具

1
sudo apt install linux-tools-`uname -r` linux-tools-generic

举个 acpidbg 调试的例子,参考 ASL 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
  Scope (\_SB)
  {
    Device (TEST)
    {
      Name (_HID, "ACPI0012")
      Name (_STR, Unicode ("Test ACPI Device"))
      Method (_STA, 0)
      {
        Return (0x0f)
      }
    }
  }
}

调试用的命令

1
2
3
4
5
6
7
8
sudo acpidbg

# 查找TEST的NamePath,同时可以预览其值。
- find TEST
# 显示TEST的所有信息。
- dump \_SB.TEST
# 执行\_SB.TEST._STA
- ev \_SB.TEST._STA

2

关于 acpidbg 的更多用法,这里不再赘述,可以参考 Debug under Linux (Ubuntu)

实际操作 OpRegion 实战中的内容

相关的代码:TestAcpi: OpRegion

执行 SSDT 的 hexdump,可以看到 Patch 后的 OpRegion TEST 对应的Binary(图中绿色框):

3

通过 find TEST,找到 OperationRegion 的 memory 地址。
执行 ev \_SB.TEST.EXEC,看前后 memory 的变化。

4

图中 memory dump 命令 sudo hexdump -C --skip 0xBF55EE18 /dev/mem | head -n 6

本文由作者按照 CC BY 4.0 进行授权