QEMU UEFI 환경으로 부팅하기 (OVMF)
OVMF란?
QEMU는 기본 bios로 SeaBios를 사용합니다. SeaBios는 GPT를 지원하지 않습니다. 이 때문에 다른 PC에서 설치한 운영체제를 QEMU로 부팅하려고 하면 실패하는 경우가 많습니다 (대부분의 최신 메인보드는 UEFI를 지원하기 때문에, GPT 테이블을 이용하고 있을 확률이 높습니다).
이때 필요한 게 OVMF입니다. OVMF는 QEMU에서도 UEFI 환경을 이용할 수 있도록 해줍니다. OVMF는 opensource UEFI 펌웨어로써, 가상화 환경에서 사용하는데 특화되어 있습니다.
또한 OVMF는 NVMe, Virtio, USB 등 다양한 디바이스 드라이버를 포함하고 있습니다. 따라서 storage device passthrough를 통해 QEMU 환경에서 부팅하려고 할 때도 필수적입니다.
마지막으로, OVMF는 TPM(Trusted Platform Module)을 지원합니다. Windows 11 같은 경우에는 TPM 기능을 지원하지 않으면 운영체제를 설치할 수가 없습니다. 따라서 QEMU에서 Windows 11을 구동시키려 하는 분도 OVMF 사용이 필수적입니다. (SeaBios도 update를 통해 TPM을 지원한다고 합니다.)
OVMF 설치
Ubuntu에서 다음 명령어를 통해 ovmf 펌웨어를 다운받을 수 있습니다.
1
sudo apt install ovmf
설치된 파일은 다음과 같이 확인할 수 있습니다.
1
ls /usr/share/ovmf/OVMF.fd
OVMF 실행 (QEMU command)
다음 argument를 추가해 줍니다.
1
-bios /usr/share/ovmf/OVMF.fd
전체 명령어 예시는 다음과 같습니다.
1
2
3
4
5
6
7
8
#!/bin/bash
qemu-system-x86_64 \
-enable-kvm -m 8G \
-cpu host -smp 4 \
-drive file=/dev/sda,format=raw,if=none,id=img \
-device nvme,drive=img,serial=1234 \
-bios /usr/share/ovmf/OVMF.fd \
-vnc localhost:1
만약 UEFI 설정 화면에 진입하고 싶다면, QEMU 실행 직후에 F2키를 연속해서 눌러주면 됩니다.
OVMF 빌드
관심이 있는 분들은 직접 빌드할 수도 있습니다. 다음 순서로 진행합니다.
- 도구 및 라이브러리를 설치합니다.
1 2 3
sudo apt-get update sudo apt-get install build-essential uuid-dev nasm iasl gcc git nasm python3-distutils python3-pip sudo apt-get install qemu
- OVMF는 EDK II 프로젝트의 일부입니다. EDK II 소스 코드를 다운로드합니다.
1 2
git clone https://github.com/tianocore/edk2.git cd edk2
- 빌드에 필요한 의존성 도구를 설치합니다.
1
pip3 install --user -r pip-requirements.txt
- submodule을 초기화해 줍니다.
1
git submodule update --init
- 환경 변수를 설정합니다. edksetup.sh 스크립트를 실행합니다.
1 2
. edksetup.sh make -C BaseTools
- build를 수행합니다.
1
build -a X64 -t GCC5 -b RELEASE -p OvmfPkg/OvmfPkgX64.dsc
- 빌드 결과물은 다음 경로에서 찾아볼 수 있습니다.
1
ls -l Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd
OVMF에 드라이버 추가하기
OVMF는 EDK II 프로젝트의 일부입니다. EDK II 프로젝트는 UEFI 펌웨어를 구현하기 위한 오픈소스 프로젝트로, 다양한 개발자들과 회사들이 참여해서 개발 중입니다. 이에 따라서 지원하는 디바이스의 종류도 매우 다양합니다.
하지만 OVMF가 이 디바이스들을 다 지원하지는 않습니다. OVMF설정에서 기본값으로 포함되어 있지 않기 때문입니다. 간단한 코드 수정을 통해 해당 드라이버들을 포함해 줄 수 있습니다.
EDK II 프로젝트에서 디바이스 드라이버들은 edk2/MdeModulePkg 디렉터리에 모아져 있습니다. 예를 들어 UFS(Universal Flash Storage)를 검색해 보면 MdeModulePkg내에 UFS 드라이버가 존재한다는 것을 확인할 수 있습니다.
1
2
3
4
5
$ find MdeModulePkg/ -type f -iname "*ufs*"
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPeiExtra.uni
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.h
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf
...
따라서 OVMF의 dsc와 fdf파일에 다음 코드를 추가하여 UFS 디바이스를 지원하도록 할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 8f5cd23b2e..5b83f836aa 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -906,6 +906,8 @@
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
+ MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf
+ MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index b6e8f43566..32cef0ce90 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -302,6 +302,8 @@ INF MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
INF MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
INF MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
+INF MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf
+INF MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf