6. 핸들/프로토콜 데이터 베이스 구조 - Part 1
ImageHandle에 대한 이론 및 기본 사용
ImageHandle
예제 코드를 만들어 보겠다.
우선은 ImageHandle
에 사용될 GUID 값을 생성한다.
$ uuidgen
b68d3472-70c7-4928-841b-6566032e0a23
이후 이전의 HelloWorld 어플리케이션을 기반으로한 c파일과 inf파일을 생성한다.
$ cat UefiLessonsPkg/ImageHandle/ImageHandle.inf
[Defines]
INF_VERSION = 1.25
BASE_NAME = ImageHandle
FILE_GUID = b68d3472-70c7-4928-841b-6566032e0a23
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
[Sources]
ImageHandle.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
$ cat UefiLessonsPkg/ImageHandle/ImageHandle.c
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EFI_SUCCESS;
}
애플리케이션을 새로 만들기 때문에 UefiLessonsPkg.dsc파일에 추가해야 한다.
[Components]
...
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
이렇게 하면 환경 설정이 끝나게 된다.
c 파일의 메인 함수를 보면 2개의 인자로 EFI_HANDLE ImageHandle
과 EFI_SYSTEM_TABLE *SystemTable
을 받는 것을 볼 수 있다.
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
EFI_SYSTEM_TABLE
은 이전 장에서 언급을 했으니 이번에는 ImageHandle
에 대해서 알아보겠다.
ImageHandle
매개변수는 프로그램 자체를 위한 이미지의 핸들이다. ImageHandle
의 type인 EFI_HANDLE
에 대한 정의는 아래의 링크에서 볼 수있다.
(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiBaseType.h)
/// A collection of related interfaces.
///
typedef VOID *EFI_HANDLE;
단순히 EFI_HANDLE
type은 void에 대한 포인터인 것을 알 수 있으며 그로 인해서 모든것에 대한 포인터가 될 수 있다.
실제로 위와 같은 type 구조의 포인터는 아래에 명시되어 있다. (https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Core/Dxe/Hand/Handle.h)
#define EFI_HANDLE_SIGNATURE SIGNATURE_32('h','n','d','l')
///
/// IHANDLE - contains a list of protocol handles
///
typedef struct {
UINTN Signature;
/// All handles list of IHANDLE
LIST_ENTRY AllHandles;
/// List of PROTOCOL_INTERFACE's for this handle
LIST_ENTRY Protocols;
UINTN LocateRequest;
/// The Handle Database Key value when this handle was last created or modified
UINT64 Key;
} IHANDLE;
해당 구조를 보면 LIST_ENTRY가
존재하는데 이는 이중연결리스트(double-linked list)로 구성이 된다. 그 덕분에 시스템 상의 모든 핸들로 이동이 가능하며 이러한 특성으로 인하여 이는 핸들 데이터베이스라고 불린다.
(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Base.h)
///
/// LIST_ENTRY structure definition.
///
typedef struct _LIST_ENTRY LIST_ENTRY;
///
/// _LIST_ENTRY structure definition.
///
struct _LIST_ENTRY {
LIST_ENTRY *ForwardLink;
LIST_ENTRY *BackLink;
};
이 핸들에는 연결된 프로토콜 목록이 존재한다. (프로토콜은 인터페이스와 같이 기능및 데이터 필드의 집합이다.) 핸들에 연결된 프로토콜 목록을 추적하기 위해서 해당 아래의 필드가 사용된다.
/// List of PROTOCOL_INTERFACE's for this handle
LIST_ENTRY Protocols;
이는 위에서 언급한 것과 같이 다음 구조를 가리키는 이중연결리스트(double-linked list)이다.
#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('p','i','f','c')
///
/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
/// with a protocol interface structure
///
typedef struct {
UINTN Signature;
/// Link on IHANDLE.Protocols
LIST_ENTRY Link;
/// Back pointer
IHANDLE *Handle;
/// Link on PROTOCOL_ENTRY.Protocols
LIST_ENTRY ByProtocol;
/// The protocol ID
PROTOCOL_ENTRY *Protocol;
/// The interface value
VOID *Interface;
/// OPEN_PROTOCOL_DATA list
LIST_ENTRY OpenList;
UINTN OpenListCount;
} PROTOCOL_INTERFACE;
PROTOCOL_INTERFACE
는 핸들의 이중연결리스트(double-linked list)되어 있다. 그리고 다음 구조인PROTOCOL_ENTRY
를 가리키고 있다.
#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('p','r','t','e')
///
/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
/// database. Each handler that supports this protocol is listed, along
/// with a list of registered notifies.
///
typedef struct {
UINTN Signature;
/// Link Entry inserted to mProtocolDatabase
LIST_ENTRY AllEntries;
/// ID of the protocol
EFI_GUID ProtocolID;
/// All protocol interfaces
LIST_ENTRY Protocols;
/// Registerd notification handlers
LIST_ENTRY Notify;
} PROTOCOL_ENTRY;
PROTOCOL_INTERFACE
구조는 별도의 프로토콜 데이터베이스에 존재하는 실제 PROTOCOL_ENTRY
구조를 가리키는 프록시일 뿐입니다.
위에서 시사한 점들은 아래의 그림으로 통해서 한눈에 볼 수 있다.

모든 핸들은 각
IHANDLE
구조의AllHandles
필드의 도움으로 인하여 상호 연결된다.모든 프로토콜은
PROTOCOL_ENTRY
구조의AllEntries
필드의 도움으로 상호 연결된다.각 Handle에는 Link 필드의 녹색 선을 통해 내부적으로 서로 연결된 모든
PROTOCOL_INTERFACES
의 이중 연결구조로 되어있다.각 프로토콜 항목은 사용되는 모든곳(
PROTOCOL_INTERFACES
)을 효과적으로 알고 있다.
EFI_HANDLE ImageHandle이 IHANDLE
구조인지 확인해보기 위해서 ImageHandle
을 IHANDLE
로 캐스팅하고 서명을 출력해주겠다.
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
typedef struct {
UINTN Signature;
/// All handles list of IHANDLE
LIST_ENTRY AllHandles;
/// List of PROTOCOL_INTERFACE's for this handle
LIST_ENTRY Protocols;
UINTN LocateRequest;
/// The Handle Database Key value when this handle was last created or modified
UINT64 Key;
} IHANDLE;
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
IHANDLE* MyHandle = ImageHandle;
Print(L"Signature: %c %c %c %c\n", (MyHandle->Signature >> 0) & 0xff,
(MyHandle->Signature >> 8) & 0xff,
(MyHandle->Signature >> 16) & 0xff,
(MyHandle->Signature >> 24) & 0xff);
return EFI_SUCCESS;
}
해당구조(IHANDLE/PROTOCOL_ENTRY/PROTOCOL_INTERFACE
)들은 비공개 상태이며 MdeModulePkg
외부에서 사용을 못한다. 그렇기 때문에.재정의를 해줘야한다. 이외에도 사용을 위해서 재정의를 해준 예시가 아래의 링크에 존재한다.(https://github.com/tianocore/edk2/blob/master/StandaloneMmPkg/Core/StandaloneMmCore.h)
$ . edksetup.sh
$ build
$ cp Build/UefiLessonsPkg/RELEASE_GCC5/X64/ImageHandle.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 4 seconds to skip startup.nsh or any other key to continue.
Shell> fs0:
FS0:\> ImageHandle.efi
Signature: h n d l

Last updated