UEFI/EDKII 에서는SystemTable
포인터와 SystemTable->BootServices
그리고 주요 함수 매개변수인 ImageHandle
을 사용하게 된다.
따라서 이러한 변수의 접근성을 위해 EDKII 라이브러리에는 gST
, gBS
, gImageHandle
이 전역 선언되어 있다.
(https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.c)
(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/UefiBootServicesTableLib.h)
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gST = NULL;
EFI_BOOT_SERVICES *gBS = NULL;
EFI_STATUS
EFIAPI
UefiBootServicesTableLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Cache the Image Handle
//
gImageHandle = ImageHandle;
ASSERT (gImageHandle != NULL);
//
// Cache pointer to the EFI System Table
//
gST = SystemTable;
ASSERT (gST != NULL);
//
// Cache pointer to the EFI Boot Services Table
//
gBS = SystemTable->BootServices;
ASSERT (gBS != NULL);
return EFI_SUCCESS;
}
1. gST 전역변수를 이용한 문자열 출력하기
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.c
-----
...
SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
+ gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
...
위와 같이 작성 후 다음과 같은 명령어를 이용해 빌드한다.
$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
--module=UefiLessonsPkg/HelloWorld/HelloWorld.inf \
--arch=X64 \
--buildtarget=RELEASE --tagname=GCC5
그럼 아래와 같은 빌드 에러가 발생한다.
error: ‘gST’ undeclared (first use in this function)
따라서 #include
를 이용해 헤더에 라이브러리 정보를 포함 시켜야 한다.
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.c
-----
+ #include <Library/UefiBootServicesTableLib.h>
...
*.dsc
파일에는 위 라이브러리 정보가 이미 LibraryClasses에 포함되어 있으므로 정상적으로 빌드 할 수 있으며 완성된 코드는 아래와 같다.
#include <Library/UefiBootServicesTableLib.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
return EFI_SUCCESS;
}
2. edk2 라이브러리 함수를 이용한 문자열 출력
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.c
-----
+ #include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
...
SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
+ Print(L"Bye!\n");
...
Print
함수는 UefiLib 라이브러리에 포함되어 있으며 이에 대한 정보를 소스 코드와 *.dsc
파일에 포함해야 한다.
(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/UefiLib.h)
만약 *.dsc
파일에 해당 정보를 기입하지 않을 경우 다음과 같은 에러러가 발생한다.
.c:821: undefined reference to `Print'
error 4000: Instance of library class [MemoryAllocationLib] is not found
따라서 다음과 같은 과정을 통해 LibraryClasses를 추가하도록 한다.
$ grep UefiLib -r ./ --include=*.inf | grep LIBRARY_CLASS
./MdePkg/Library/UefiLib/UefiLib.inf: LIBRARY_CLASS = UefiLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
$ grep MemoryAllocationLib -r ./ --include=*.inf | grep LIBRARY_CLASS | grep MdePkg
./MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf: LIBRARY_CLASS = MemoryAllocationLib|PEIM PEI_CORE SEC
./MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf: LIBRARY_CLASS = MemoryAllocationLib|DXE_SMM_DRIVER
./MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf: LIBRARY_CLASS = MemoryAllocationLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
$ vi UefiLessonsPkg/UefiLessonsPkg.dsc
-----
[LibraryClasses]
...
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
또한 Hellworld.inf
에도 LibraryClasses 정보를 추가해준다.
$ vi UefiLessonsPkg/HelloWorld/HelloWorld.inf
-----
[LibraryClasses]
UefiApplicationEntryPoint
+ UefiLib
이후 빌드를 진행하면 성공적인 결과를 얻을 수 있다.
$ cp Build/UefiLessonsPkg/RELEASE_GCC5/X64/HelloWorld.efi ~/UEFI_disk/
$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive format=raw,file=fat:rw:~/UEFI_disk \
-nographic \
-net none
UEFI Interactive Shell v2.2
EDK II
UEFI v2.70 (EDK II, 0x00010000)
Mapping table
FS0: Alias(s):HD0a1:;BLK1:
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
BLK0: Alias(s):
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
BLK2: Alias(s):
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Press ESC in 1 seconds to skip startup.nsh or any other key to continue.
Shell> fs0:
FS0:\> HelloWorld.efi
Hello World!
Hello again!
Bye!
FS0:\>