💻
UEFI 프로젝트
  • 🧑‍🏫프로젝트 개요
  • 📖UEFI 개념
    • 1. BIOS의 과거
    • 2. UEFI 개념
    • 3. BIOS vs UEFI
    • 4. UEFI 부팅 단계
  • 🖥️UEFI 개발
    • UEFI 개발 시작하기
      • 0. EDK II 빌드 환경 구성
      • 1. 간단한 EFI application 만들기
      • 2. 간단한 Pkg 만들기
      • 3. Hello World 출력하기
      • 4. 라이브러리와 Hello World
      • 5. Conf를 통한 Build 단순화
    • 핸들 및 프로토콜
      • 6. 핸들/프로토콜 데이터 베이스 구조 - Part 1
      • 7. 핸들/프로토콜 데이터 베이스 구조 - Part 2
      • 8. HandleProtocol API 함수 & ImageHandle 프로토콜을 통한 정보
      • 9. ProtocolsPerHandle API를 통한 ImageHandle 프로토콜 가져오기
      • 10. EFI_STATUS 타입 과 EFI_ERROR 매크로
    • 메모리 맵
      • 11. EFI 메모리 맵 정보 얻기
      • 12. EFI 메모리 맵을 리눅스 커널 스타일로 바꾸기
    • 명령줄 인수를 받는 간단한 앱 만들기
      • 13.ShellAppMain Entry point
      • 14.gRT->GetNextVariableName API를 사용하여 모든 변수 이름 및 GUID 가져오기
    • 부팅 옵션
      • 15. gRT->GetVariable API를 사용하여 부팅 변수 가져오기 및 구문 분석
      • 16. OVMF 이미지 내에 부팅 옵션 추가
      • 17. 부팅 옵션에 WaitForEvent 함수 추가
      • 18. ReadKeyStroke 함수로 사용자 입력 처리
      • 19. bcfg 명령어를 사용한 부팅 옵션 수정
    • PCD
      • 20. PCD 소개
      • 21. PCD 변수에 대한 Overriding
      • 22. Feature Flag PCD와 BOOLEAN FixedAtBuild PCD의 비교
      • 23. PatchableInModule PCD 및 GenPatchPcdTable/PatchPcdValue 유틸리티를 통해 PCD를 변경하는 방법
      • 24. Dynamic/DynamiEx PCDs
      • 25. PCD 더 알아보기
    • 테이블
      • 26. EFI_CONFIGURATION_TABLE에서 참조되는 테이블
      • 27. dmem/EFI_SMBIOS_PROTOCOL/smbiosview를 통해서 SMBIOS 정보 가져오기
      • 28. EFI_SHELL_PROTOCOL을 통하여 ACPI 테이블을 파일에 저장하기
      • 29. EFI_ACPI_SDT_PROTOCOL 및 ShellLib를 사용하여 ACPI BGRT 테이블에서 BMP 이미지 저장하기
    • PCI
      • 30. PCI 루트 브리지 찾은 후 시스템의 모든 PCI 기능 가져오기
      • 31. ShellLib/PrintLib 함수를 사용해 PCI Vendor/Device 정보 가져오기
      • 32. EFI_PCI_IO_PROTOCOL을 사용해 PCI Option ROM 이미지 표시
      • 33. EfiRom 유틸리티를 사용한 PCI Option ROM 이미지 파싱 및 생성
    • 드라이버 및 라이브러리
      • 34. 간단한 UEFI 드라이버 생성
      • 35. 애플리케이션에서 사용할 간단한 라이브러리 생성
      • 36. Library의 constructor와 destructor, NULL Library
      • 37. Shell에 acpiview 명령을 추가하는 방법 조사
      • 38. 사용자 지정 프로토콜을 만들고 사용하기
      • 39. RegisterKeyNotify / UnrigisterKeyNotify 함수를 사용해 단축키 기능을 추가하는 드라이버 만들기
      • 40. Key #### NVRAM 변수
    • 디버그
      • 41. DEBUG 출력문 내부 구조와 DEBUG 문 제어를 위한 PCD 분석, 그리고 OVMF 부트 로그 가져오기
      • 42. GDB를 이용한 Driver/Application 및 OVMF Debug
    • HII
      • 43. HII 데이터베이스 개념 및 출력
      • 44. HII 데이터베이스 내부
      • 45. EFI_HII_DATABASE_PROTOCOL의 NewPackageList를 사용하여 문자열 패키지가 포함된 문자열 목록 게시
      • 46. EFI_HII_DATABASE_PROTOCOL의 NewPackageList를 사용하여 문자열 패키지가 포함된 HII 패키지 목록 게시
      • 47. EFI_HII_DATABASE_PROTOCOL의 NewPackageList를 사용하여 문자열 패키지가 포함된 HII 패키지 목록 게시
      • 48. UNI 파일 및 HiiLib를 사용하여 HII String 패키지 게시 및 작업하기
      • 49.MODULE_UNI_FILE/PACKAGE_UNI_FILE/[UserExtensions.TianoCore."ExtraFiles"]의 도움으로 UNI 파일 선언하기
      • 50.UEFI_HII_RESOURCE_SECTION을 사용하여 문자열 패키지와 함께 HII 패키지 목록 게시하기
      • 51. UEFI APP에 메뉴얼 추가하기(shell의 -?와 help 옵션)
      • 52. Russian 글꼴 추가 - Part 1.
      • 53. Russian 글꼴 추가 - Part 2.
      • 54. EFI_HII_STRING_PROTOCOL의 NewString 및 SetString 함수를 사용하여 다른 언어에 대한 문자열 패키지를 동적으로 추가
      • 55. PlatformLangCodes EFI 변수 수정 및 다른 언어를 동적 추가하기
      • 56. 코드에서 FILE_GUID 및 BASE_NAME을 가져오기
    • VFR
      • 57. VFR을 사용해 간단한 폼 생성 및 EFI_FORM_BROWSER2_PROTOCOL.SendForm()를 통해 화면에 폼 표시하기
      • 58. VFR 요소 : subtitle 및 text
      • 59. 간단한 폼 애플리케이션을 UEFI 드라이버 Form으로 변환하기
      • 60. gRT->SetVariable() 함수를 사용한 UEFI 변수 생성, 변경 및 삭제
      • 61.dmpstore 명령을 사용하여 변수를 파일에 저장/로드하기
      • 62. UEFI Device path의 구조
      • 63. checkbox를 가진 HII 폼 만들기
      • 64. checkbox를 가진 HII폼 만들기
      • 65. VFR 추가 입력 요소 Part 1: number
      • 66. VFR 추가 입력 요소 Part 2: string
      • 67. VFR 추가 입력 요소 Part 3: date & time
      • 68. VFR 추가 입력 요소 Part 3: oneof & orderedlist
      • 69. VFR의 조건부 키워드
      • 70. VFR의 상수 및 연산자가 내장된 기본 조건문
      • 71. 기본 VFR 내장 문자열용 함수
      • 72. label 키워드를 이용하여 HII 양식에 동적 요소 추가하기
      • 73. VFR question 기본값 설정
  • 🔐UEFI 보안
    • 1. 개요
    • 2. 공격 벡터
    • 3. mitigation
    • 4. 정적 분석 방법
    • 5. 동적 분석 방법
Powered by GitBook
On this page
  1. UEFI 개발
  2. 부팅 옵션

16. OVMF 이미지 내에 부팅 옵션 추가

Previous15. gRT->GetVariable API를 사용하여 부팅 변수 가져오기 및 구문 분석Next17. 부팅 옵션에 WaitForEvent 함수 추가

Last updated 2 years ago

이전 장에서는 현재 부팅 옵션을 보여주는 애플리케이션을 개발했다.

FS0:\> ShowBootVariables.efi
Boot0000
UiApp
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)

Boot0001
UEFI QEMU DVD-ROM QM00003
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)

Boot0002
UEFI QEMU HARDDISK QM00001
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)

Boot0003*
EFI Internal Shell
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)

출력된 GUID에 대한 정보를 확인하려면 아래의 링크를 통해 확인할 수 있다.

  • FILE_GUID = 7C04A583-9E3E-4f1c-AD65-E05268D0B4D1 # gUefiShellFileGuid

  • FILE_GUID = 462CAA21-7614-4503-836E-8AB6F4662331 - UiApp module is driver for BDS phase

*.fdf 파일에는 SEC, PEI 또는 DXE 단계의 볼륨을 포함하여 모든 볼륨에 배치되는 드라이버와 애플리케이션의 리스트를 가지고 있다.

...

[FV.SECFV]
FvNameGuid         = 763BED0D-DE9F-48F5-81F1-3E90E1B1A015
BlockSize          = 0x1000
FvAlignment        = 16
...
INF <...>
...

[FV.PEIFV]
FvNameGuid         = 6938079B-B503-4E3D-9D24-B28337A25806
BlockSize          = 0x10000
FvAlignment        = 16
...
INF <...>
...

[FV.DXEFV]
FvForceRebase      = FALSE
FvNameGuid         = 7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1        ### <---- this is a GUID from our output
BlockSize          = 0x10000
FvAlignment        = 16
...
INF  ShellPkg/Application/Shell/Shell.inf          <--- this apps are placed in the FV.DXEFV firmware volume
...
INF  MdeModulePkg/Application/UiApp/UiApp.inf

부팅 옵션에 HelloWorld 애플리케이션을 부팅 옵션에 추가해볼 것이다. 따라서 EFI Shell 애플리케이션이 어떻게 OVMF에 추가되어 있는지 살펴본다.

먼저 OVMF 이미지에 애플리케이션을 추가해야 한다. UefiLessonsPkg/HelloWorld/HelloWorld.inf 경로를 OvmfPkg/OvmfPkgX64.fdf 파일에 있는 [FV.DXEFV]의 ShellPkg/Application/Shell/Shell.inf 아래에 추가한다.

[FV.DXEFV]
FvForceRebase      = FALSE
FvNameGuid         = 7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1
BlockSize          = 0x10000
FvAlignment        = 16
...

  INF  ShellPkg/Application/Shell/Shell.inf
+ INF  UefiLessonsPkg/HelloWorld/HelloWorld.inf
...

추가한 후 새로 OVMF를 빌드하려고 하면 아래와 같은 에러가 발생한다. 해당 오류는 OvmfPkg/OvmfPkgX64.dsc에 HelloWorld 애플리케이션에 대한 정보가 추가되지 않아 발생하는 에러이다.

$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
...
build.py...
 : error F001: Module /home/kostr/tiano/edk2/UefiLessonsPkg/HelloWorld/HelloWorld.inf NOT found in DSC file; Is it really a binary module?
...

OvmfPkg/OvmfPkgX64.dsc에 HelloWorld 애플리케이션에 대한 정보를 추가하기 위해 아래와 같이 [Components] 섹션에 있는 ShellPkg 아래에 처음에 만들었던 HelloWorld.inf의 경로를 추가한다. Shell.inf의 {...} 안에는 해당 애플리케이션에서 필요한 정보가 작성되어 있는 것이므로 HelloWorld 애플리케이션은 작성해야 할 정보가 없어 HelloWorld.inf의 경로만 작성해주면 된다.

[Components]
  ...
  ShellPkg/Application/Shell/Shell.inf {
   ...
  }
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
  ...

HelloWorld.inf의 경로를 추가하고 OVMF를 다시 빌드하면 에러없이 컴파일되는 것을 볼 수 있다.

$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5

OVMF 이미지에 HelloWorld 애플리케이션이 추가되었지만 부팅 옵션에는 아직 보이지 않는다.

ShowBootVariables.efi 애플리케이션을 사용할 때 UEFI Shell 부팅 옵션에 EFI Internel Shell에 대한 설명이 있었다. 해당 부분을 EDKII 코드베이스를 통해 검색한다.

$ grep "EFI Internal Shell" -r ./ --exclude=Build
./ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c:    &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
./OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c:    &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
./OvmfPkg/Library/PlatformBootManagerLibBhyve/BdsPlatform.c:    &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
./OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c:    &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE

결과로 나온 파일들 중에서 관심을 가져야 할 파일은 ./OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c 이다.

VOID
EFIAPI
PlatformBootManagerAfterConsole (
  VOID
  )
{
  ...
  //
  // Register UEFI Shell
  //
  PlatformRegisterFvBootOption (
    &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
    );

  ...
}

BdsPlatform.c 파일에서 Guid를 통해 부팅 옵션에 등록하는 것을 볼 수 있다. gUefiShellFileGuid가 어디서 사용되는지 찾아본다.

$ grep "gUefiShellFileGuid" -r ./ --exclude=Build

./OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c:    &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
./OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf:  gUefiShellFileGuid
./ShellPkg/Application/Shell/Shell.inf:  FILE_GUID                      = 7C04A583-9E3E-4f1c-AD65-E05268D0B4D1 # gUefiShellFileGuid
./ShellPkg/ShellPkg.dec:  gUefiShellFileGuid              = {0x7c04a583, 0x9e3e, 0x4f1c, {0xad, 0x65, 0xe0, 0x52, 0x68, 0xd0, 0xb4, 0xd1}}

출력된 결과를 보면 gUefiShellFileGuid가 작성된 ShellPkg/ShellPkg.dec 파일이 존재하는 것을 볼 수 있다. 이것과 같이 UefiLessons도 UefiLessons/UefiLessons.dec 파일을 생성해 주어야 한다. GUID는 UefiLessons/HelloWorld/HelloWorld.inf에 작성했던 값과 동일한 gHelloWorldFileGuid를 생성한다.

[Defines]
  DEC_SPECIFICATION              = 0x00010005
  PACKAGE_NAME                   = UefiLessonsPkg
  PACKAGE_GUID                   = 7e7edbba-ca2c-4177-a3f0-d3371358773a
  PACKAGE_VERSION                = 1.01

[Guids]
  # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
  gHelloWorldFileGuid            = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
  

HelloWorld 애플리케이션의 GUID를 OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf 파일에 추가한다.

[Guids]
 ...
  gUefiShellFileGuid
+ gHelloWorldFileGuid

이제 OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c 파일에서 gHelloWorldFileGuid를 사용할 수 있게 되었다. 따라서 해당 파일에 아래와 같이 추가한다.

VOID
EFIAPI
PlatformBootManagerAfterConsole (
  VOID
  )
{
  ...
  //
  // Register UEFI Shell
  //
  PlatformRegisterFvBootOption (
    &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
    );

  //
  // Register HelloWorld app
  //
  PlatformRegisterFvBootOption (
    &gHelloWorldFileGuid, L"Hello World", LOAD_OPTION_ACTIVE
    );
  ...
}

아직까지는 OVMF를 빌드하려고 하면 아래와 같은 에러가 발생한다.

$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
...

build.py...
/home/kostr/tiano/edk2/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf(87): error 4000: Value of Guid [gHelloWorldFileGuid] is not found under [Guids] section in
        /home/kostr/tiano/edk2/MdePkg/MdePkg.dec
        /home/kostr/tiano/edk2/MdeModulePkg/MdeModulePkg.dec
        /home/kostr/tiano/edk2/SourceLevelDebugPkg/SourceLevelDebugPkg.dec
        /home/kostr/tiano/edk2/OvmfPkg/OvmfPkg.dec
        /home/kostr/tiano/edk2/SecurityPkg/SecurityPkg.dec
        /home/kostr/tiano/edk2/ShellPkg/ShellPkg.dec
...

에러는OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf에 UefiLessonsPkg.dec 의 경로를 추가하지 않았기 때문이다. 따라서 [Pakages]에 추가한다.

[Packages]
  ...
  ShellPkg/ShellPkg.dec
  UefiLessonsPkg/UefiLessonsPkg.dec

OVMF를 다시 빌드하면 에러없이 되는 것을 확인할 수 있다.

$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5

ShowBootVariables.efi를 통해 확인해보면 부팅 옵션에 HelloWorld가 추가된 것을 볼 수 있다.

추가적으로 추가한 HelloWorld 애플리케이션의 정보가 제대로 되어 있는지 확인하려면 bcfg boot dump 명령어를 통해 확인할 수 있다.

7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1는 OVMF 이미지의 펌웨어 볼륨에 대한 GUID이다.

전체 EDKII FDF 파일 사양 확인

위 링크를 통해 EFI Shell은 간단한 UEFI_APPLICATION인 것을 알 수 있다. 지금까지 여러 애플리케이션을 만들어봤으니 이번에는 부팅 옵션에 애플리케이션을 추가한다.

EDKII 패키지 선언(.dec) 파일 형식 사양 :

🖥️
https://github.com/tianocore/edk2/blob/master/ShellPkg/Application/Shell/Shell.inf
https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Application/UiApp/UiApp.inf
https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.fdf
https://edk2-docs.gitbook.io/edk-ii-fdf-specification/
https://github.com/tianocore/edk2/blob/master/ShellPkg/Application/Shell/Shell.inf
https://edk2-docs.gitbook.io/edk-ii-dec-specification/
ShowBootVariables.efi를 통한 부팅 옵션 확인
bcfg boot dump 결과