맞춤형 UEFI 프로토콜을 만드는 방법
UEFI 프로토콜 설명
DXE 드라이버는 프로토콜을 생성하여 장치에 대한 액세스를 추상화합니다. 예를 들어 Tcg2Protocol을 사용하여 MMIO 또는 포트 IO와 같은 것을 통해 액세스하는 대신 TPM2.0 기능에 액세스할 수 있습니다. 프로토콜은 함수 포인터를 포함하는 데이터 구조이며 실제 함수의 내용은 해당 프로토콜을 설치한 DXE 드라이버에 있습니다. 프로토콜(데이터 구조) 자체도 해당 DXE 드라이버(일반적으로 .data 섹션)에 있습니다.
(EDK2 UEFI Driver Writer's Guide 3.6.2의 이미지)
각 프로토콜에는 자체 GUID가 있으며 다른 UEFI 모듈이 이 프로토콜을 찾는 데 사용됩니다. 여러 프로토콜을 그룹화할 수 있으며 이 그룹은 핸들로 식별됩니다. 따라서 먼저
gBS->LocateHandle
를 사용하여 Handle을 찾은 다음 내부의 Protocol을 찾을 수 있습니다. 그러나 GUID로 프로토콜을 직접 찾는 데 사용하는 것이 더 간단할 수 있습니다gBS->LocateProtocol
.프로토콜은 모든 UEFI 모듈을 통해 액세스할 수 있어야 하므로 단일 데이터베이스에 저장됩니다. 이 데이터베이스에 프로토콜을 저장하기 위해서는 프로토콜을 생성한 DXE Driver가 내부
gBS->InstallMultipleProtocolInterfaces
를 사용해야 합니다.구현
MyDxe2.inf
inf 파일부터 시작하겠습니다. 요점은
gEfiDummyProtocol
에 [Protocols]
를 쓰는 것입니다. 이 DXE 드라이버가 생성하고 소비하는 프로토콜을 작성해야 합니다.[Defines]
INF_VERSION = 0x00010006
BASE_NAME = MyDxe2
FILE_GUID = 9d46dccd-ea11-4808-93e9-9b7021889b2d
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = MyDxeEntry
[Sources]
MyDxe2.h
MyDxe2.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
UefiBootServicesTableLib
UefiLib
PrintLib
[Protocols]
gEfiDummyProtocolGuid ## PRODUCES
[Depex]
TRUE
MyDxe2.h
이것은 헤더 파일입니다. 이것은 주로
EFI_DUMMY_PROTOCOL
또는 DUMMY_FUNC1
와 같은 유형을 정의하므로 MyDxe2.c에서 사용할 수 있습니다. gEfiDummyProtocolGuid
의 정의는 별도의 곳에서 정의한다.#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiBootServicesTableLib.h>
typedef EFI_STATUS (EFIAPI *DUMMY_FUNC1)();
typedef EFI_STATUS (EFIAPI *DUMMY_FUNC2)();
// e9811f61-14bd-4637-8d17-aec540d8f508
#define EFI_DUMMY_PROTOCOL_GUID \
{ 0xe9811f61, 0x14bd, 0x4637, { 0x8d, 0x17, 0xae, 0xc5, 0x40, 0xd8, 0xf5, 0x08 } }
extern EFI_GUID gEfiDummyProtocolGuid;
typedef struct _EFI_DUMMY_PROTOCOL {
DUMMY_FUNC1 DummyFunc1;
DUMMY_FUNC2 DummyFunc2;
} EFI_DUMMY_PROTOCOL;
MyDxe2.c
DXE 드라이버의 내용입니다.
mDummy
는 이 프로토콜의 실제 데이터 구조이며 이 프로토콜은 gBS->InstallMultipleProtocolInterfaces
에 의해 설치됩니다. DummyFunc1
및 DummyFunc2
의 내용은 무엇이든 가능하지만 이 예에서는 "DummyFuncN called"메시지를 MyDxeStatus
라는 UEFI 변수에 저장하므로 프로토콜이 실제로 올바르게 실행되고 있는지 확인할 수 있습니다. .#include "MyDxe2.h"
UINT32 myvarSize = 30;
CHAR8 myvarValue[30] = {0};
CHAR16 myvarName[30] = L"MyDxeStatus";
// eefbd379-9f5c-4a92-a157-ae4079eb1448
EFI_GUID myvarGUID = { 0xeefbd379, 0x9f5c, 0x4a92, { 0xa1, 0x57, 0xae, 0x40, 0x79, 0xeb, 0x14, 0x48 }};
EFI_HANDLE mDummyHandle = NULL;
EFI_STATUS EFIAPI DummyFunc1() {
AsciiSPrint(myvarValue, 18, "DummyFunc1 called");
gRT->SetVariable(
myvarName,
&myvarGUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
myvarSize,
myvarValue);
return EFI_SUCCESS;
}
EFI_STATUS EFIAPI DummyFunc2() {
AsciiSPrint(myvarValue, 18, "DummyFunc2 called");
gRT->SetVariable(
myvarName,
&myvarGUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
myvarSize,
myvarValue);
return EFI_SUCCESS;
}
EFI_DUMMY_PROTOCOL mDummy = {
DummyFunc1,
DummyFunc2
};
EFI_STATUS EFIAPI MyDxeEntry(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
gBS->InstallMultipleProtocolInterfaces(&mDummyHandle, &gEfiDummyProtocolGuid, &mDummy, NULL);
EFI_TIME time;
gRT->GetTime(&time, NULL);
AsciiSPrint(myvarValue, 12, "%2d/%2d %2d:%2d", time.Month, time.Day, time.Hour, time.Minute);
gRT->SetVariable(
myvarName,
&myvarGUID,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
myvarSize,
myvarValue);
return EFI_SUCCESS;
}
MdeModulePkg.dec
다른 UEFI 모듈에서
gEfiDummyProtocolGuid
를 사용하려면 MdeModulePkg.dec에 gEfiDummyProtocolGuid
를 정의해야 합니다. MdeModulePkg.dec 내부에 아래와 같이 정의를 추가합니다.[Protocols]
...
## MyDxe/MyDxe2.h
gEfiDummyProtocolGuid = { 0xe9811f61, 0x14bd, 0x4637, { 0x8d, 0x17, 0xae, 0xc5, 0x40, 0xd8, 0xf5, 0x08 } }
MdeModulePkg.dsc
[Components]
MdeModulePkg/MyDxe/MyDxe2.inf
...
빌드
ACTIVE_PLATFORM = MdeModulePkg/MdeModulePkg.dsc
에 Conf/target.txt
가 있는지 확인하고 빌드해 보겠습니다. 그런 다음 에서 설명한 것처럼 FFS 파일을 구성하고 BIOS 이미지에 FFS 파일을 추가하고 해당 이미지로 SPI 플래시 칩을 플래시합니다.DummyProtocol 사용
다음으로 이 프로토콜을 사용하는 모듈을 작성해 봅시다. 출력을 쉽게 화면에 출력할 수 있도록 BDS 단계에서 USB 메모리에서 실행되는 UEFI 모듈을 작성할 것입니다.
AppPkg/
아래에 edk2/
라는 폴더를 만들고 이러한 파일을 만듭니다.AppPkg/
├── AppPkg.dec
├── AppPkg.dsc
└── Applications/
└── UseDummyProtocol/
├── UseDummyProtocol.c
└── UseDummyProtocol.inf
AppPkg.dec
FirstPkg
는 아무 이름이나 될 수 있습니다.[Defines]
DEC_SPECIFICATION = 0x00010005
PACKAGE_NAME = FirstPkg
PACKAGE_GUID = 75281f80-8657-4cf2-837f-04d73179c590
PACKAGE_VERSION = 0.1
AppPkg.dsc
[Defines]
PLATFORM_NAME = FirstPkg
PLATFORM_GUID = 7b86cb02-9fbb-4f77-8d93-35c8c90f2488
PLATFORM_VERSION = 0.1
DSC_SPECIFICATION = 0x00010005
OUTPUT_DIRECTORY = Build/FirstPkg$(ARCH)
SUPPORTED_ARCHITECTURES = IA32|X64
BUILD_TARGETS = DEBUG|RELEASE|NOOPT
DEFINE DEBUG_ENABLE_OUTPUT = TRUE
[LibraryClasses]
# Entry point
UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf
# Common Libraries
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
!if $(DEBUG_ENABLE_OUTPUT)
DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
!else ## DEBUG_ENABLE_OUTPUT
DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
!endif ## DEBUG_ENABLE_OUTPUT
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
[Components]
AppPkg/Applications/UseDummyProtocol/UseDummyProtocol.inf
UseDummyProtocol.inf
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = UseDummyProtocol
FILE_GUID = 5765e8dd-c97a-4ce2-891e-9e24b94d654b
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = UefiMain
[Sources]
UseDummyProtocol.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiLib
ShellCEntryLib
UefiBootServicesTableLib
UefiRuntimeServicesTableLib
[Protocols]
gEfiDummyProtocolGuid ## CONSUME
UseDummyProtocol.c
이것은
MyDxeStatus
(DummyProtocol의 함수)를 호출하기 전과 후에 GetVariable
에 의해 UEFI 변수DummyFunc1
를 확인하고 있습니다. DummyFunc1
는 MyDxeStatus
의 값을 원래 이 DXE 드라이버가 실행될 때 설정된 현재 시간인 DummyFunc1 called
로 변경합니다.#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <MyDxe/MyDxe2.h>
#include <Library/BaseMemoryLib.h>
EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
EFI_DUMMY_PROTOCOL *DummyProtocol;
gBS->LocateProtocol(&gEfiDummyProtocolGuid, NULL, (VOID**)&DummyProtocol);
CHAR8 myvarValue[30];
UINT64 myvarSize = 30;
UINT32 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
EFI_GUID myvarGUID = { 0xeefbd379, 0x9f5c, 0x4a92, { 0xa1, 0x57, 0xae, 0x40, 0x79, 0xeb, 0x14, 0x48 }};
Print(L"[Before Calling Protocol] MyDxeStatus:\r\n");
gRT->GetVariable(
L"MyDxeStatus",
&myvarGUID,
&Attributes,
&myvarSize,
myvarValue);
AsciiPrint("%a\n\n", myvarValue);
DummyProtocol->DummyFunc1();
Print(L"[After Calling Protocol] MyDxeStatus:\r\n");
gRT->GetVariable(
L"MyDxeStatus",
&myvarGUID,
&Attributes,
&myvarSize,
myvarValue);
AsciiPrint("%a\n", myvarValue);
while(1);
return 0;
}
빌드 및 실행
빌드하기 전에
ACTIVE_PLATFORM = AppPkg/AppPkg.dsc
에서 Conf/target.txt
로 변경합니다. 그런 다음 빌드하십시오.이번에는 생성된 UseDummyProtocol.efi를 USB 메모리에 저장하겠습니다. USB 메모리에 디렉토리
EFI/BOOT/
를 만들고 UseDummyProtocol.efi를 bootx64.efi로 이름을 바꾸고 폴더에 넣습니다.이전에 BIOS를 플래시한 PC에 USB를 연결하고 해당 컴퓨터를 부팅합니다. 아래 출력이 보이면 성공한 것입니다.
(문자열 길이를 지정하지 못했습니다 ...)
Reference
이 문제에 관하여(맞춤형 UEFI 프로토콜을 만드는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/machinehunter/how-to-make-custom-uefi-protocol-3ikp텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)