Post

QEMU UEFI 환경으로 부팅하기 (OVMF)

OVMF란?

QEMU는 기본적으로 SeaBIOS를 사용하여 가상 머신을 부팅합니다.

그러나 GPT 파티션이나 UEFI 기능이 필요한 최신 운영체제를 구동하기 위해서는 OVMF(오픈소스 UEFI 펌웨어)를 사용하는 것이 적합합니다.

OVMF는 QEMU나 KVM과 같은 가상 환경에서 UEFI 기반 부팅, TPM, Secure Boot 등을 지원하며, 현대적인 시스템과의 호환성을 크게 향상시켜 줍니다.

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
This post is licensed under CC BY 4.0 by the author.