diff options
Diffstat (limited to 'Lessons')
-rw-r--r-- | Lessons/Lesson_38/README.md | 287 |
1 files changed, 280 insertions, 7 deletions
diff --git a/Lessons/Lesson_38/README.md b/Lessons/Lesson_38/README.md index 946c8fd..d79d1ce 100644 --- a/Lessons/Lesson_38/README.md +++ b/Lessons/Lesson_38/README.md @@ -42,11 +42,11 @@ SIMPLE_CLASS_PROTOCOL mSimpleClass = { SimpleClassProtocolSetNumber }; ``` -In C syntax there is no such keyword as a `class`, but still it is possible to create something similar. We use `struct` keyword and class methods would be just fields with pointers to functions. +In C syntax there is no such keyword as a `class`, but still it is possible to create something similar. We use `struct` keyword and class methods would be just fields with pointers to functions. Now we need to create a header file that would contain the `SIMPLE_CLASS_PROTOCOL` type definition. -Usually package contain headers for protocols in a folder: +Usually packages contain headers for protocols in a folder: ``` <pkg>/Include/Protocol/ ``` @@ -82,7 +82,7 @@ struct _SIMPLE_CLASS_PROTOCOL { #endif ``` -Include this file in our *.c file, so it would itself also know that is the `SIMPLE_CLASS_PROTOCOL` type: +Include this file in our *.c file, so it would itself also know what is the `SIMPLE_CLASS_PROTOCOL` type: ``` #include <Protocol/SimpleClass.h> ``` @@ -217,11 +217,11 @@ Finally it is time to write INF file: # SimpleClassUser -Now it time to write an app that would use our protocol. As this protocol is not installed to the app image handle, we first need to find all handles with such protocol with a help of `LocateHandleBuffer` API, and then call `OpenProtocol` on every one of this handles. +Now it time to write an app that would use our protocol. As this protocol is not installed to the app image handle, we first need to find all handles with such protocol with a help of `LocateHandleBuffer` API, and then call `OpenProtocol` on every one of these handles. -This is no different as it was some other protocol from the other edk2 packages. +This is no different as it was for some other protocols from the other edk2 packages. -UefiLessonsPkg/SimpleClassUser/SimpleClassUser.c +UefiLessonsPkg/SimpleClassUser/SimpleClassUser.c: ``` #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiLib.h> @@ -337,9 +337,282 @@ Add both `SimpleClassProtocol` and `SimpleClassUser` to the `[Components]` secti Now build, copy results to QEMU shared folder and run OVMF. -If we execute our +If we execute our `SimpleClassUser` first, we would get an error: ``` FS0:\> SimpleClassUser.efi Error! Can't find any handle with gSimpleClassProtocolGuid: Not Found ``` +It is understandable, our protocol is not yet installed in the system. Let's install it and use our app. +``` +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 +``` + +We can see handles for our driver and its protocol with `dh`: +``` +FS0:\> dh +... +C6: ImageDevicePath(..C1)/\SimpleClassProtocol.efi) LoadedImage(\SimpleClassProtocol.efi) +C7: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67 +``` + +If we execute `SimpleClassUser.efi` again, the number would increase from 5 to 10. It means that the `number` value is really stored outside `SimpleClassUser.efi`. As you can guess, it is stored in a protocol with a handle `C7`. +``` +FS0:\> SimpleClassUser.efi +Handle = 6695318 +Number before=5 +Number after=10 +``` + +We can load another copy of our `SimpleClassProtocol.efi` driver: +``` +FS0:\> load SimpleClassProtocol.efi +Hello from SimpleClassProtocol driver, handle=6635498 +Image 'FS0:\SimpleClassProtocol.efi' loaded at 6631000 - Success +``` +Now there would be two protocol handles in the system C7 and 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 +``` + +If we execute our `SimpleClassUser.efi` application again, we'll see, that 2 separate version of `number` exist in the system: +``` +FS0:\> SimpleClassUser.efi +Handle = 6695318 +Number before=10 +Number after=15 +Handle = 6635498 +Number before=0 +Number after=5 +``` + +We didn't implement unload function in our driver yet, so it is not possible to unload them. + +# IMAGE_UNLOAD + +Let's implemet unload function in our protocol driver (UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.inf): +``` +[Defines] + ... + UNLOAD_IMAGE = SimpleClassProtocolDriverUnload +``` + +For now write it like this (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; +} +``` + +Let's test again. Load driver and execute our app once: +``` +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 +``` + +It is not possible to perform unload for the protocol handler (C7), but as we've implemented unload function for our driver let's to try unload it: +``` +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. +``` + +But there is a problem - C7 is still in the system: +``` +FS0:\> dh +... +C7: B5510EEA-6F11-4E4B-AD0F-35CE17BD7A67 +``` + +Now if we try to execute our app we would get an exception. `OpenProtocol` call would give the same address for the protocol, but now this memory is freed, and a call to protocol functions like `SimpleClass->GetNumber` would crash the system: +``` +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 +``` + +To fix this we need to uninstall our protocol from the system on the driver unload. + +# Uninstall protocol interface + +Like with the protocol interface install there are two functions in UEFI API for the protocol uninstallation. The obsolete one `UninstallProtocolInterface` and a new one `UninstallMultipleProtocolInterfaces`: +``` +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 +``` + +Let's call `UninstallMultipleProtocolInterfaces` on the driver unload: +``` +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; +} +``` + +Now build and perform our experiments again. + +Load driver and execute our app once: +``` +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 +``` +Load another copy of the driver and execute our app again: +``` +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 +``` +Now there are two protocols/drivers in the system. Let's try to unload the first one. +``` +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 +``` +If we execute our app again, we would see, that that now there is only one handle in the system with the `SimpleClass` protocol, it's valid, and it was completely undisturbed by another protocol uninstall process: +``` +FS0:\> SimpleClassUser.efi +Handle = 6636898 +Number before=5 +Number after=10 +``` + |