38. 사용자 지정 프로토콜을 만들고 사용하기
InstallMultipleProtocolInterfaes와 UninstallMultipleProtocolInterfaces 사용
이전 장까지 우리는 프로토콜만을 사용해왔다.
이제는 실제로 프로토콜을 생성하는 드라이버를 작성할 것이다.
클래스와 유사한 프로토콜로서, SimpleClass
라는 프로토콜을 작성할 예정이다.
SimpleClass
프로토콜은 두 가지 기능을 가지게 된다. 내부 클래스변수 mNumber
에 대한 간단한 Getter와 Setter가 이에 해당한다. mNumber
의 m
은 이 모듈에 대해서 해당 변수가 지역 변수임을 의미한다.
$ cat UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.c
---
UINTN mNumber = 0;
EFI_STATUS
EFIAPI
SimpleClassProtocolSetNumber (
UINTN Number
)
{
mNumber = Number;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
SimpleClassProtocolGetNumber (
UINTN* Number
)
{
if (Number == NULL) {
return EFI_INVALID_PARAMETER;
}
*Number = mNumber;
return EFI_SUCCESS;
}
SIMPLE_CLASS_PROTOCOL mSimpleClass = {
SimpleClassProtocolGetNumber,
SimpleClassProtocolSetNumber
};
C 언어에는 클래스와 같은 키워드가 없지만, 비슷하게는 만들 수 있다. struct
를 이용하여 class
메소드를 함수에 대한 포인터 필드로 사용한다.
이제 SIMPLE_CLASS_PROTOCOL
유형의 정의를 포함하는 헤더 파일 만들어야 한다.
일반적으로 패키지에는 폴더의 프로토콜에 대한 헤더가 포함된다.
<pkg>/Include/Protocol/
따라서 UefiLessonsPkg/Include/Protocol/SimpleClass.h
헤더 파일을 생성한다.
#ifndef __SIMPLE_CLASS_PROTOCOL_H__
#define __SIMPLE_CLASS_PROTOCOL_H__
typedef struct _SIMPLE_CLASS_PROTOCOL SIMPLE_CLASS_PROTOCOL;
typedef
EFI_STATUS
(EFIAPI* SIMPLE_CLASS_GET_NUMBER)(
UINTN* Number
);
typedef
EFI_STATUS
(EFIAPI* SIMPLE_CLASS_SET_NUMBER)(
UINTN Number
);
struct _SIMPLE_CLASS_PROTOCOL {
SIMPLE_CLASS_GET_NUMBER GetNumber;
SIMPLE_CLASS_SET_NUMBER SetNumber;
};
#endif
SIMPLE_CLASS_PROTOCOL
유형을 *.c
파일에 포함시킨다.
#include <Protocol/SimpleClass.h>
다른 모듈에서 프로토콜을 이용할 수 있게 하려면, 시스템(Protocol database)에 프로토콜을 설치해 주어야 한다.
이를 위해서 InstallProtocolInterface
함수를 사용한다.
EFI_BOOT_SERVICES.InstallProtocolInterface()
Summary
Installs a protocol interface on a device handle. If the handle does not exist, it is created and added to the
list of handles in the system.
Prototype
typedef
EFI_STATUS
(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE) (
IN OUT EFI_HANDLE *Handle,
IN EFI_GUID *Protocol,
IN EFI_INTERFACE_TYPE InterfaceType,
IN VOID *Interface
);
Parameters
Handle A pointer to the EFI_HANDLE on which the interface is to be installed. If *Handle is NULL on input,
a new handle is created and returned on output. If *Handle is not NULL on input, the protocol is
added to the handle, and the handle is returned unmodified.
If *Handle is not a valid handle, then EFI_INVALID_PARAMETER is returned.
Protocol The numeric ID of the protocol interface.
InterfaceType Indicates whether Interface is supplied in native form.
Interface A pointer to the protocol interface. The Interface must adhere to the structure defined by Protocol.
NULL can be used if a structure is not associated with Protocol.
Description
The InstallProtocolInterface() function installs a protocol interface (a GUID/Protocol Interface structure pair) on a device handle.
The same GUID cannot be installed more than once onto the same handle.
EDKII 코드베이스 전체에서 InstallProtocolInterface
를 찾을 수 있지만, 동일한 UEFI 스펙에 따르면, 사실 이건 조금 구식 API이다. 여기서 제안하는 API는 다음과 같다.
EFI_BOOT_SERVICES.InstallMultipleProtocolInterfaces()
Summary:
Installs one or more protocol interfaces into the boot services environment.
Prototype:
typedef
EFI_STATUS
EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) (
IN OUT EFI_HANDLE *Handle,
...
);
Parameters:
Handle The pointer to a handle to install the new protocol interfaces on, or a pointer to NULL if a new handle is to be
allocated.
... A variable argument list containing pairs of protocol GUIDs and protocol interfaces.
Description:
This function installs a set of protocol interfaces into the boot services environment. It removes
arguments from the variable argument list in pairs. The first item is always a pointer to the protocol’s
GUID, and the second item is always a pointer to the protocol’s interface. These pairs are used to call the
boot service EFI_BOOT_SERVICES.InstallProtocolInterface() to add a protocol interface to
Handle. If Handle is NULL on entry, then a new handle will be allocated. The pairs of arguments are
removed in order from the variable argument list until a NULL protocol GUID value is found.
우리 예제에서 드라이버를 작성할 때, 드라이버 INF 파일에서 집입점으로 선언할 SimpleClassProtocolDriverEntryPoint
함수에서 InstallMultipleProtocolInterfaces
를 사용하겠다.
EFI_HANDLE mSimpleClassHandle = NULL;
EFI_STATUS
EFIAPI
SimpleClassProtocolDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
Print(L"Hello from SimpleClassProtocol driver");
EFI_STATUS Status = gBS->InstallMultipleProtocolInterfaces(
&mSimpleClassHandle,
&gSimpleClassProtocolGuid,
&mSimpleClass,
NULL
);
if (!EFI_ERROR(Status))
Print(L", handle=%p\n", mSimpleClassHandle);
else
Print(L"\n", mSimpleClassHandle);
return Status;
}
여기에 mSimpleClasshandle
의 주소를 출력하도록 Print
문도 추가해준다.
mSimpleClassHandle
및 mSimpleClass
는 동일한 *.c
파일(따라서, 앞에 m
이 접두사로 쓰인)에서 선언되며, gSimpleClassProtocolGuid
(g
는 전역을 의미) 패키지 DEC 파일에서 선언하므로, 다른 모듈이 이 파일을 포함하고 프로토콜을 사용할 수 있다.
$ vi UefiLessonsPkg/UefiLessonsPkg.dec
---
[Protocols]
gSimpleClassProtocolGuid = { 0xb5510eea, 0x6f11, 0x4e4b, { 0xad, 0x0f, 0x35, 0xce, 0x17, 0xbd, 0x7a, 0x67 }}
최종적으로, 이를 INF 파일에 넣어준다.
$ vi UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.inf
---
[Defines]
INF_VERSION = 1.25
BASE_NAME = SimpleClassProtocol
FILE_GUID = 51d6a90a-c021-4472-b2c1-5fdd1b7f2196
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = SimpleClassProtocolDriverEntryPoint <---- entry point that actually calls 'InstallMultipleProtocolInterfaces'
[Sources]
SimpleClassProtocol.c
[Packages]
MdePkg/MdePkg.dec
UefiLessonsPkg/UefiLessonsPkg.dec <---- we need to add this to get access to the GUID value 'gSimpleClassProtocolGuid'
[Protocols]
gSimpleClassProtocolGuid <---- protocols that are used in module
[LibraryClasses]
UefiDriverEntryPoint
UefiLib
SimpleClassUser
지금부터는 우리가 프로토콜을 사용할 애플리케이션을 작성할 것이다. 이 프로토콜은 앱 이미지 핸들에설치되지 않았으므로, 먼저 LocateHandleBuffer
API로 해당 프로토콜이 있는 모든 핸들을 찾은 다음, 각 핸들에서 OpenProtocol
을 호출해야 한다.
이는 다른 EDKII 패키지의 다른 프로토콜과 다르지 않다.
$ cat UefiLessonsPkg/SimpleClassUser/SimpleClassUser.c
---
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Protocol/SimpleClass.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINTN HandleCount;
EFI_HANDLE* HandleBuffer;
UINTN Index;
SIMPLE_CLASS_PROTOCOL* SimpleClass;
EFI_STATUS Status = gBS->LocateHandleBuffer (
ByProtocol,
&gSimpleClassProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
Print(L"Error! Can't find any handle with gSimpleClassProtocolGuid: %r\n", Status);
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
Print(L"Handle = %p\n", HandleBuffer[Index]);
Status = gBS->OpenProtocol(
HandleBuffer[Index],
&gSimpleClassProtocolGuid,
(VOID **)&SimpleClass,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR(Status)) {
<...>
} else {
Print(L"Error! Can't open SimpleClass protocol: %r\n", Status);
}
}
return Status;
}
프로토콜을 다음과 같이 사용한다.
현재 숫자 값을 가져와 출력
숫자 값에 5를 더하고 세팅
다시 현재 값을 가져와 출력
UINTN Number;
Status = SimpleClass->GetNumber(&Number);
if (!EFI_ERROR(Status)) {
Print(L"Number before=%d\n", Number);
} else {
Print(L"Error! Can't get number: %r\n", Status);
}
Status = SimpleClass->SetNumber(Number+5);
if (EFI_ERROR(Status))
Print(L"Error! Can't set number: %r\n", Status);
Status = SimpleClass->GetNumber(&Number);
if (!EFI_ERROR(Status)) {
Print(L"Number after=%d\n", Number);
} else {
Print(L"Error! Can't get number: %r\n", Status);
}
프로토콜 유저의 앱 INF 파일은 매우 간단하다.
$ vi UefiLessonsPkg/SimpleClassUser/SimpleClassUser.inf
---
[Defines]
INF_VERSION = 1.25
BASE_NAME = SimpleClassUser
FILE_GUID = 466eed70-8def-44ea-9fb4-9012b266ec8c
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
[Sources]
SimpleClassUser.c
[Packages]
MdePkg/MdePkg.dec
UefiLessonsPkg/UefiLessonsPkg.dec <---- we need to add it to get access to the 'gSimpleClassProtocolGuid'
[Protocols]
gSimpleClassProtocolGuid <----- add used protocol guids
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
패키지의 [Components]
섹션의 SimpleClassProtocol
과 SimpleClassUser
를 모두 추가한다.
[Components]
...
UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.inf
UefiLessonsPkg/SimpleClassUser/SimpleClassUser.inf
Testing
이제 빌드하고 결과를 QEMU 공유 폴더에 복사하여 OVMF를 실행한다.
SimpleClassUser
를 먼저 실행하면, 오류가 발생할 것이다.
FS0:\> SimpleClassUser.efi
Error! Can't find any handle with gSimpleClassProtocolGuid: Not Found
에러 코드에서도 보이듯이, 아직 우리가 만든 프로토콜이 시스템이 설치되지 않았다. 이를 설치하고 애플리케이션을 실행시키면 된다.
FS0:\> load SimpleClassProtocol.efi
Hello from SimpleClassProtocol driver, handle=6695318
Image 'FS0:\SimpleClassProtocol.efi' loaded at 6645000 - Success
FS0:\> SimpleClassUser.efi
Handle = 6695318
Number before=0
Number after=5
dh
를 사용하여 드라이버 및 해당 프로토콜에 대한 핸들을 볼 수 있다.
FS0:\> dh
...
C6: ImageDevicePath(..C1)/\SimpleClassProtocol.efi) LoadedImage(\SimpleClassProtocol.efi)
C7: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67
(핸들 번호는 본인 환경에 맞게 바꿔 생각해주면 된다.)
SimpleClassUser.efi
를 다시 실행하면, 숫자가 5에서 10으로 증가한다. 변수가 SimpleClassUser.efi
외부에 저장된다는 것을 의미한다. 예상해보면, 이는 핸들 C7
이 있는 프로토콜에 저장된다는 것을 짐작할 수 있다.
FS0:\> SimpleClassUser.efi
Handle = 6695318
Number before=5
Number after=10
load
명령어를 다시 사용하면, SimpleClassProtocol.efi
드라이버의 사본을 로드할 수 있다.
FS0:\> load SimpleClassProtocol.efi
Hello from SimpleClassProtocol driver, handle=6635498
Image 'FS0:\SimpleClassProtocol.efi' loaded at 6631000 - Success
이제 시스템 C7 및 C9에는 두 개의 프로토콜 핸들이 존재한다.
FS0:\> dh
...
C6: ImageDevicePath(..C1)/\SimpleClassProtocol.efi) LoadedImage(\SimpleClassProtocol.efi)
C7: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67
C8: ImageDevicePath(..C1)/\SimpleClassProtocol.efi) LoadedImage(\SimpleClassProtocol.efi)
C9: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67
SimpleClassUser.efi
애플리케이션을 다시 실행하면, 시스템 2개의 또 다른 버전이 존재하는 것을 볼 수 있다.
FS0:\> SimpleClassUser.efi
Handle = 6695318
Number before=10
Number after=15
Handle = 6635498
Number before=0
Number after=5
아직 이 드라이버에는 unload 기능을 구현하지 않았으므로 언로드할 수는 없다.
여기까지의 완성 코드
$ cat UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.c
---
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Protocol/SimpleClass.h>
EFI_HANDLE mSimpleClassHandle = NULL;
UINTN mNumber = 0;
EFI_STATUS
EFIAPI
SimpleClassProtocolSetNumber (
UINTN Number
)
{
mNumber = Number;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
SimpleClassProtocolGetNumber (
UINTN* Number
)
{
if (Number == NULL) {
return EFI_INVALID_PARAMETER;
}
*Number = mNumber;
return EFI_SUCCESS;
}
SIMPLE_CLASS_PROTOCOL mSimpleClass = {
SimpleClassProtocolGetNumber,
SimpleClassProtocolSetNumber
};
EFI_STATUS
EFIAPI
SimpleClassProtocolDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
Print(L"Hello from SimpleClassProtocol driver");
EFI_STATUS Status = gBS->InstallMultipleProtocolInterfaces(
&mSimpleClassHandle,
&gSimpleClassProtocolGuid,
&mSimpleClass,
NULL
);
if (!EFI_ERROR(Status))
Print(L", handle=%p\n", mSimpleClassHandle);
else
Print(L"\n", mSimpleClassHandle);
return Status;
}
$ cat UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.inf
---
[Defines]
INF_VERSION = 1.25
BASE_NAME = SimpleClassProtocol
FILE_GUID = 51d6a90a-c021-4472-b2c1-5fdd1b7f2196
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = SimpleClassProtocolDriverEntryPoint
[Sources]
SimpleClassProtocol.c
[Packages]
MdePkg/MdePkg.dec
UefiLessonsPkg/UefiLessonsPkg.dec
[Protocols]
gSimpleClassProtocolGuid
[LibraryClasses]
UefiDriverEntryPoint
UefiLib
$ cat UefiLessonsPkg/SimpleClassUser/SimpleClassUser.c
---
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Protocol/SimpleClass.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINTN HandleCount;
EFI_HANDLE* HandleBuffer;
UINTN Index;
SIMPLE_CLASS_PROTOCOL* SimpleClass;
EFI_STATUS Status = gBS->LocateHandleBuffer (
ByProtocol,
&gSimpleClassProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
Print(L"Error! Can't find any handle with gSimpleClassProtocolGuid: %r\n", Status);
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
Print(L"Handle = %p\n", HandleBuffer[Index]);
Status = gBS->OpenProtocol(
HandleBuffer[Index],
&gSimpleClassProtocolGuid,
(VOID **)&SimpleClass,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR(Status)) {
UINTN Number;
Status = SimpleClass->GetNumber(&Number);
if (!EFI_ERROR(Status)) {
Print(L"Number before=%d\n", Number);
} else {
Print(L"Error! Can't get number: %r\n", Status);
}
Status = SimpleClass->SetNumber(Number+5);
if (EFI_ERROR(Status))
Print(L"Error! Can't set number: %r\n", Status);
Status = SimpleClass->GetNumber(&Number);
if (!EFI_ERROR(Status)) {
Print(L"Number after=%d\n", Number);
} else {
Print(L"Error! Can't get number: %r\n", Status);
}
} else {
Print(L"Error! Can't open SimpleClass protocol: %r\n", Status);
}
}
return Status;
}
$ cat UefiLessonsPkg/SimpleClassUser/SimpleClassUser.inf
---
[Defines]
INF_VERSION = 1.25
BASE_NAME = SimpleClassUser
FILE_GUID = 466eed70-8def-44ea-9fb4-9012b266ec8c
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
[Sources]
SimpleClassUser.c
[Packages]
MdePkg/MdePkg.dec
UefiLessonsPkg/UefiLessonsPkg.dec
[Protocols]
gSimpleClassProtocolGuid
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
IMAGE_UNLOAD
이제 프로토콜 드라이브에서 언로드 기능을 구현하도록 하자.
$ vi UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.inf
---
[Defines]
...
UNLOAD_IMAGE = SimpleClassProtocolDriverUnload
SimpleClassProtocol.c
에는 다음 함수를 추가해준다.
$ vi UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.c
---
EFI_STATUS
EFIAPI
SimpleClassProtocolDriverUnload (
IN EFI_HANDLE ImageHandle
)
{
Print(L"Bye-bye from SimpleClassProtocol driver, handle=%p\n", mSimpleClassHandle);
return EFI_SUCCESS;
}
테스트 해보자. 다시 드라이버를 빌드하여 로드하고 앱을 실행한다.
FS0:\> load SimpleClassProtocol.efi
Hello from SimpleClassProtocol driver, handle=665B618
Image 'FS0:\SimpleClassProtocol.efi' loaded at 6646000 - Success
FS0:\> SimpleClassUser.efi
Handle = 665B618
Number before=0
Number after=5
FS0:\> dh
...
C6: ImageDevicePath(..C1)/\SimpleClassProtocol.efi) LoadedImage(\SimpleClassProtocol.efi)
C7: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67
프로토콜 핸들에 대한 언로드를 수행할 수 없었지만, 드라이버에 대한 unload 기능을 구현해주었으니 언로드를 시도한다.
FS0:\> unload c7
Unload - Handle [665B618]. [y/n]?
y
Unload - Handle [665B618] Result Invalid Parameter.
FS0:\> unload c6
Unload - Handle [665FF18]. [y/n]?
y
Bye-bye from SimpleClassProtocol driver, handle=665B618
Unload - Handle [665FF18] Result Success.
하지만, 아직 핸들(C7)이 남아있을 것이다.
FS0:\> dh
...
C7: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67
이제 애플리케이션을 실행하려하면 예외가 발생한다. OpenProtocol
호출은 프로토콜에 대해 동일한 주소를 제공하나, 이제 이 메모리는 해제되고 SimpleClass -> GetNumber
와 같은 프로토콜 함수에 대한 호출은 시스템에서 충돌이 발생한다.
FS0:\> SimpleClassUser.efi
Handle = 665B618
!!!! X64 Exception Type - 0D(#GP - General Protection) CPU Apic ID - 00000000 !!!!
ExceptionData - 0000000000000000
RIP - AFAFAFAFAFAFAFAF, CS - 0000000000000038, RFLAGS - 0000000000000246
RAX - 0000000006647740, RCX - 0000000007EBC468, RDX - 0000000000000000
RBX - 00000000079EE018, RSP - 0000000007EBC418, RBP - 0000000007EBC468
RSI - 0000000000000000, RDI - 000000000665EA18
R8 - 00000000000000AF, R9 - 000000000665EA18, R10 - 000000008005C440
R11 - 0000000000000000, R12 - 0000000000000000, R13 - 00000000066353E4
R14 - 0000000007EBC460, R15 - 0000000006636040
DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030
GS - 0000000000000030, SS - 0000000000000030
CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 0000000007C01000
CR4 - 0000000000000668, CR8 - 0000000000000000
DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000
DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400
GDTR - 00000000079DE000 0000000000000047, LDTR - 0000000000000000
IDTR - 00000000072AD018 0000000000000FFF, TR - 0000000000000000
FXSAVE_STATE - 0000000007EBC070
이 문제를 해결하려면 드라이버 언로드시 시스템에서 프로토콜을 제거해야 한다.
Protocol Interface 제거하기
프로토콜 인터페이스 설치와 마찬가지로 UEFI API에는 프로토콜 제거를 위한 두 가지 함수가 존재한다. 한 가지는 더 이상 사용되지 않고(UninstallProtocolInterface
), 하나는 새로운 함수(UninstallMultipleProtocolInterface
)이다.
EFI_BOOT_SERVICES.UninstallProtocolInterface()
Summary:
Removes a protocol interface from a device handle. It is recommended that UninstallMultipleProtocolInterfaces() be used in place of
UninstallProtocolInterface().
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE) (
IN EFI_HANDLE Handle,
IN EFI_GUID *Protocol,
IN VOID *Interface
);
Parameters:
Handle The handle on which the interface was installed. If Handle is not a
valid handle, then EFI_INVALID_PARAMETER is returned.
Protocol The numeric ID of the interface.
Interface A pointer to the interface. NULL can be used if a structure is not associated with Protocol.
Description:
The UninstallProtocolInterface() function removes a protocol interface from the handle on
which it was previously installed. The Protocol and Interface values define the protocol interface to
remove from the handle.
If the last protocol interface is removed from a handle, the handle is freed and is no longer valid.
EFI_BOOT_SERVICES.UninstallMultipleProtocolInterfaces()
Summary:
Removes one or more protocol interfaces into the boot services environment.
Prototype:
typedef
EFI_STATUS
EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES) (
IN EFI_HANDLE Handle,
...
);
Parameters:
Handle The handle to remove the protocol interfaces from.
... A variable argument list containing pairs of protocol GUIDs and protocol interfaces.
Description:
This function removes a set of protocol interfaces from the boot services environment. It removes
arguments from the variable argument list in pairs. The first item is always a pointer to the protocol’s
GUID, and the second item is always a pointer to the protocol’s interface. These pairs are used to call the
boot service EFI_BOOT_SERVICES.UninstallProtocolInterface() to remove a protocol
interface from Handle. The pairs of arguments are removed in order from the variable argument list until
a NULL protocol GUID value is found
드라이버 언로드에서 UninstallMultipleProtocolInterfaces
를 호출해 보겠다.
EFI_STATUS
EFIAPI
SimpleClassProtocolDriverUnload (
IN EFI_HANDLE ImageHandle
)
{
Print(L"Bye-bye from SimpleClassProtocol driver, handle=%p\n", mSimpleClassHandle);
EFI_STATUS Status = gBS->UninstallMultipleProtocolInterfaces(
mSimpleClassHandle,
&gSimpleClassProtocolGuid,
&mSimpleClass,
NULL
);
return Status;
}
이제 예제를 다시 빌드하여 실행해보자.
드라이버를 로드하고 앱을 다시 한 번 실행해본다.
FS0:\> load SimpleClassProtocol.efi
Hello from SimpleClassProtocol driver, handle=665F118
Image 'FS0:\SimpleClassProtocol.efi' loaded at 6645000 - Success
FS0:\> SimpleClassUser.efi
Handle = 665F118
Number before=0
Number after=5
FS0:\> dh
...
C6: ImageDevicePath(..C1)/\SimpleClassProtocol.efi) LoadedImage(\SimpleClassProtocol.efi)
C7: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67
다른 드라이버 복사본을 로드하고 앱을 다시 실행한다.
FS0:\> load SimpleClassProtocol.efi
Hello from SimpleClassProtocol driver, handle=6636898
Image 'FS0:\SimpleClassProtocol.efi' loaded at 6630000 - Success
FS0:\> SimpleClassUser.efi
Handle = 665F118
Number before=5
Number after=10
Handle = 6636898
Number before=0
Number after=5
FS0:\> dh
...
C6: ImageDevicePath(..C1)/\SimpleClassProtocol.efi) LoadedImage(\SimpleClassProtocol.efi)
C7: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67
C8: ImageDevicePath(..C1)/\SimpleClassProtocol.efi) LoadedImage(\SimpleClassProtocol.efi)
C9: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67
이제 시스템 두 개의 프로토콜/드라이버가 있다. 첫 번째 프로토콜/드라이버를 언로드하자.
FS0:\> unload c6
Unload - Handle [665F018]. [y/n]?
y
Bye-bye from SimpleClassProtocol driver, handle=665F118
Unload - Handle [665F018] Result Success.
FS0:\> dh
C8: ImageDevicePath(..C1)/\SimpleClassProtocol.efi) LoadedImage(\SimpleClassProtocol.efi)
C9: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67
앱을 다시 실행하면, 시스템에 SimpleClass
프로토콜이 있는 핸들 하나만 있고, 유효하며 다른 프로토콜 제거 프로세스에 의해 완전히 방해받지 않는다는 것을 알 수 있다.
FS0:\> SimpleClassUser.efi
Handle = 6636898
Number before=5
Number after=10
Last updated