이제 코드를 검증해보자. 드라이버 언로드의 경우 Shell의 unload 명령을 사용할 수 있다.
FS0:\> unload -?
Unloads a driver image that was already loaded.
UNLOAD [-n] [-v|-verbose] Handle
-n - Skips all prompts during unloading, so that it can be used
in a script file.
-v, -verbose - Dumps verbose status information before the image is unloaded.
Handle - Specifies the handle of driver to unload, always taken as hexadecimal number.
NOTES:
1. The '-n' option can be used to skip all prompts during unloading.
2. If the '-v' option is specified, verbose image information will be
displayed before the image is unloaded.
3. Only drivers that support unloading can be successfully unloaded.
4. Use the 'LOAD' command to load a driver.
EXAMPLES:
* To find the handle for the UEFI driver image to unload:
Shell> dh -b
* To unload the UEFI driver image with handle 27:
Shell> unload 27
도움말 메시지에서 볼 수 있듯이 언로드하려면 드라이버 핸들을 찾아야 한다. 이를 위해 dh 명령을 사용할 수 있다. 드라이버 로드 후에 실행하면 출력 끝에 다음과 같은 내용이 표시된다.
이것은 실수가 아니다. HII 하위 시스템이 올바르게 작동하려면 폼과 함께 Device Path를 제공해야 한다.
이것이 checkbox 폼이 올바르게 작동하기 위해 해야할 마지막 일이다.
기억하겠지만 DevicePath 노드에는 다음과 같은 몇 가지 가능한 type이 있다.
typedefstruct { UINT8 Type; ///< 0x01 Hardware Device Path. ///< 0x02 ACPI Device Path. ///< 0x03 Messaging Device Path. ///< 0x04 Media Device Path. ///< 0x05 BIOS Boot Specification Device Path. ///< 0x7F End of Hardware Device Path. UINT8 SubType; ///< Varies by Type UINT8 Length[2];} EFI_DEVICE_PATH_PROTOCOL;
그리고 모든 type에는 여러 하위 type이 있다. type + 하위 type의 조합은 뒤에 오는 실제 데이터의 구조를 정의한다. 모든 데이터 형식은 UEFI 스펙에 의해 엄격하게 정의된다. 그러나 일부 유형은 공급업체가 장치 경로에서 자체 사용자 지정 구조를 제공할 수 있는 가능성을 남긴다. 물론 EDKII lib는 특수 경로를 출력할 수 없지만 최소한 실패하지는 않을 것이다. 라이브러리는 EFI_DEVICE_PATH_PROTOCOL.Length 필드를 사용하여 알 수 없는 DeviceNode를 건너뛸 수 있기 때문이다.
이 모든 것은 다음과 같은 특별한 하위 type으로 인해 가능해진다.
#define HW_VENDOR_DP 0x04 // vendor subtype for the Hardware Device Path type
#define MSG_VENDOR_DP 0x0a // vendor subtype for the Messaging Device Path type
#define MEDIA_VENDOR_DP 0x03 // vendor subtype for the Media Device Path type
////// The Vendor Device Path allows the creation of vendor-defined Device Paths. A vendor must/// allocate a Vendor GUID for a Device Path. The Vendor GUID can then be used to define the/// contents on the n bytes that follow in the Vendor Device Path node.///typedefstruct { EFI_DEVICE_PATH_PROTOCOL Header; /// /// Vendor-assigned GUID that defines the data that follows. /// EFI_GUID Guid; /// /// Vendor-defined variable size data. ///} VENDOR_DEVICE_PATH;
EDKII 코드베이스의 폼에 대한 장치 경로는 이 방법으로 표시된다. 일반적으로 HARDWARE_DEVICE_PATH 및 HW_VENDOR_DP는 해당 벤더 노드의 Type 및 SubType으로 사용된다.
이를 염두에 두고 우리의 고유한 Device Path를 만들어보자. 우리의 특수 Device Node에는 Guid = FORMSET_GUID가 있다. 이것은 필수 사항이 아니며 경로에 자체 GUID가 있을 수 있으므로 나는 불필요한 GUID를 생성하고 싶지 않다.
우리의 특별한 GUID는 중요한 데이터가 없는 장치 경로 노드를 정의하므로 다음과 같이 전체 Device Path 구조를 정적으로 정의할 수 있다.
이제 드라이버에 EFI_DEVICE_PATH_PROTOCOL을 설치해야 한다. 기억하겠지만 InstallProtocolInterface는 이제 사용되지 않는 것으로 간주되므로 InstallMultipleProtocolInterfaces를 사용하자.
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.
따라서 드라이버에 대해 EFI_HANDLE mDriverHandle을 선언하고 Device Path를 설치해보자.
EFI_HANDLE mDriverHandle =NULL;EFI_STATUSEFIAPIHIIFormCheckboxEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ){ EFI_STATUS Status; Status =gBS->InstallMultipleProtocolInterfaces(&mDriverHandle,&gEfiDevicePathProtocolGuid,&mHiiVendorDevicePath,NULL);if (EFI_ERROR (Status)) {return Status; } ...}
드라이버 언로드에서 프로토콜을 제거하는 것을 잊지 말자.
EFI_STATUSEFIAPIHIIFormCheckboxUnload ( EFI_HANDLE ImageHandle ){ ... Status =gBS->UninstallMultipleProtocolInterfaces( mDriverHandle,&gEfiDevicePathProtocolGuid,&mHiiVendorDevicePath,NULL);return Status;}
모든 것이 올바르게 작동하는지 확인해보자. dh 명령으로 이제 드라이버가 DevicePath 프로토콜이 설치된 다른 핸들을 생성하는 것을 볼 수 있다.
이제 실제로 Device Path 패키지를 HII 데이터베이스에 추가해야 한다. HII 데이터베이스의 패키지 및 패키지 목록을 기억하고 있겠지만,
typedefstruct _EFI_HII_DEVICE_PATH_PACKAGE { EFI_HII_PACKAGE_HEADER Header;//EFI_DEVICE_PATH_PROTOCOL DevicePath[];} EFI_HII_DEVICE_PATH_PACKAGE;Header The standard package header, where Header.Type = EFI_HII_PACKAGE_DEVICE_PATH.DevicePath The Device Path description associated with the driver handle that provided the content sent to the HII database.
다행히 폼과 문자열을 등록하는 데 지속적으로 사용되었던 HiiLib의 HiiAddPackages를 Device Path 설치에도 쉽게 사용할 수 있다.
우리가 해야 할 일은 EFI_DEVICE_PATH_PROTOCOL이 설치된 EFI_HANDLE(우리가 이미 생성한 것)을 제공하는 것 뿐이다.
/** Registers a list of packages in the HII Database and returns the HII Handle associated with that registration. If an HII Handle has already been registered with the same PackageListGuid and DeviceHandle, then NULL is returned. If there are not enough resources to perform the registration, then NULL is returned. If an empty list of packages is passed in, then NULL is returned. If the size of the list of package is 0, then NULL is returned. The variable arguments are pointers that point to package headers defined by UEFI VFR compiler and StringGather tool. #pragma pack (push, 1) typedef struct { UINT32 BinaryLength; EFI_HII_PACKAGE_HEADER PackageHeader; } EDKII_AUTOGEN_PACKAGES_HEADER; #pragma pack (pop)@param[in] PackageListGuid The GUID of the package list.@param[in] DeviceHandle If not NULL, the Device Handle on which <--------- !! an instance of DEVICE_PATH_PROTOCOL is installed. This Device Handle uniquely defines the device that the added packages are associated with.@param[in] ... The variable argument list that contains pointers to packages terminated by a NULL.@retval NULL An HII Handle has already been registered in the HII Database with the same PackageListGuid and DeviceHandle.@retval NULL The HII Handle could not be created.@retval NULL An empty list of packages was passed in.@retval NULL All packages are empty.@retval Other The HII Handle associated with the newly registered package list.**/EFI_HII_HANDLEEFIAPIHiiAddPackages ( IN CONST EFI_GUID *PackageListGuid, IN EFI_HANDLE DeviceHandle OPTIONAL, ... );
그 전에는 항상 DeviceHandle 인수 대신 NULL을 사용했었다. 그래서 우리가 해야 할 일은 이것을 바꾸는 것이다.