From 6064c1e48b622f53538f4df9bdd402c607a87d51 Mon Sep 17 00:00:00 2001 From: Konstantin Aladyshev Date: Sat, 10 Jul 2021 00:04:40 +0300 Subject: Move lessons to separate folder Signed-off-by: Konstantin Aladyshev --- Lessons/Lesson_09/Conf/target.txt | 7 + Lessons/Lesson_09/README.md | 148 +++++++++++++++++++++ .../UefiLessonsPkg/HelloWorld/HelloWorld.c | 15 +++ .../UefiLessonsPkg/HelloWorld/HelloWorld.inf | 18 +++ .../UefiLessonsPkg/ImageHandle/ImageHandle.c | 102 ++++++++++++++ .../UefiLessonsPkg/ImageHandle/ImageHandle.inf | 18 +++ .../Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.c | 44 ++++++ .../UefiLessonsPkg/ImageInfo/ImageInfo.inf | 22 +++ .../UefiLessonsPkg/SimplestApp/SimplestApp.c | 10 ++ .../UefiLessonsPkg/SimplestApp/SimplestApp.inf | 16 +++ .../Lesson_09/UefiLessonsPkg/UefiLessonsPkg.dsc | 32 +++++ 11 files changed, 432 insertions(+) create mode 100644 Lessons/Lesson_09/Conf/target.txt create mode 100644 Lessons/Lesson_09/README.md create mode 100644 Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.c create mode 100644 Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.inf create mode 100644 Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.c create mode 100644 Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.inf create mode 100644 Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.c create mode 100644 Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.inf create mode 100644 Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.c create mode 100644 Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.inf create mode 100644 Lessons/Lesson_09/UefiLessonsPkg/UefiLessonsPkg.dsc (limited to 'Lessons/Lesson_09') diff --git a/Lessons/Lesson_09/Conf/target.txt b/Lessons/Lesson_09/Conf/target.txt new file mode 100644 index 0000000..c109dcf --- /dev/null +++ b/Lessons/Lesson_09/Conf/target.txt @@ -0,0 +1,7 @@ +ACTIVE_PLATFORM = UefiLessonsPkg/UefiLessonsPkg.dsc +TARGET = RELEASE +TARGET_ARCH = X64 +TOOL_CHAIN_CONF = Conf/tools_def.txt +TOOL_CHAIN_TAG = GCC5 +BUILD_RULE_CONF = Conf/build_rule.txt + diff --git a/Lessons/Lesson_09/README.md b/Lessons/Lesson_09/README.md new file mode 100644 index 0000000..3b838d8 --- /dev/null +++ b/Lessons/Lesson_09/README.md @@ -0,0 +1,148 @@ +The methods that we've used to discover protocols for our image handle were purely educational. + +Let's try UEFI API functions to get the same result. + +To do this we will need to understand `ProtocolsPerHandle` function: +``` +EFI_BOOT_SERVICES.ProtocolsPerHandle() + +Summary: +Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated from pool. + +Prototype: +typedef +EFI_STATUS +(EFIAPI *EFI_PROTOCOLS_PER_HANDLE) ( + IN EFI_HANDLE Handle, + OUT EFI_GUID ***ProtocolBuffer, + OUT UINTN *ProtocolBufferCount + ); + +Parameters: +Handle The handle from which to retrieve the list of protocol interface GUIDs. +ProtocolBuffer A pointer to the list of protocol interface GUID pointers that are installed on Handle. This buffer is allocated with a call to the Boot Service EFI_BOOT_SERVICES.AllocatePool(). It is the caller's responsibility to call the Boot Service EFI_BOOT_SERVICES.FreePool() when the caller no longer requires the contents of ProtocolBuffer. +ProtocolBufferCountA pointer to the number of GUID pointers present in ProtocolBuffer. + +Description: +The ProtocolsPerHandle() function retrieves the list of protocol interface GUIDs that are installed on Handle. The list is returned in ProtocolBuffer, and the number of GUID pointers in ProtocolBuffer is returned in ProtocolBufferCount. +If Handle is NULL or Handle is NULL, then EFI_INVALID_PARAMETER is returned. +If ProtocolBuffer is NULL, then EFI_INVALID_PAREMETER is returned. +If ProtocolBufferCount is NULL, then EFI_INVALID_PARAMETER is returned. +If there are not enough resources available to allocate ProtocolBuffer, then EFI_OUT_OF_RESOURCES is +returned. + +Status Codes Returned: +EFI_SUCCESS The list of protocol interface GUIDs installed on Handle was returned in + ProtocolBuffer. The number of protocol interface GUIDs was + returned in ProtocolBufferCount. +EFI_INVALID_PARAMETER Handle is NULL. +EFI_INVALID_PARAMETER ProtocolBuffer is NULL. +EFI_INVALID_PARAMETER ProtocolBufferCount is NULL. +EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results. +``` + +This description mentions that we need manually deallocate received ProtocolBuffer, so lel's also look to the suggessted `FreePool` function: + +``` +EFI_BOOT_SERVICES.FreePool() + +Summary: +Returns pool memory to the system. + +Prototype: +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_POOL) ( + IN VOID *Buffer +); + +Parameters: +Buffer Pointer to the buffer to free. + +Description: +The FreePool() function returns the memory specified by Buffer to the system. On return, the +memory’s type is EfiConventionalMemory. The Buffer that is freed must have been allocated by +AllocatePool(). + +Status Codes Returned: +EFI_SUCCESS The memory was returned to the system. +EFI_INVALID_PARAMETER Buffer was invalid +``` + +Now when we know how to use API, let's add this code at the end of our `ImageHandle` app: +``` +Print(L"________\n"); +EFI_GUID **ProtocolGuidArray; +UINTN ArrayCount; +EFI_STATUS Status = gBS->ProtocolsPerHandle(ImageHandle, + &ProtocolGuidArray, + &ArrayCount); + +if (Status == EFI_SUCCESS) { + for (int i=0; i +``` + +Some may have noticed, that we've used `FreePool`, but not a `gBS->FreePool`. It is legit because `FreePool` is defined in the https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiMemoryAllocationLib/MemoryAllocationLib.c file: +``` +/** + Frees a buffer that was previously allocated with one of the pool allocation functions in the + Memory Allocation Library. + + Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the + pool allocation services of the Memory Allocation Library. If it is not possible to free pool + resources, then this function will perform no actions. + + If Buffer was not allocated with a pool allocation function in the Memory Allocation Library, + then ASSERT(). + + @param Buffer The pointer to the buffer to free. + +**/ +VOID +EFIAPI +FreePool ( + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + + Status = gBS->FreePool (Buffer); + ASSERT_EFI_ERROR (Status); +} +``` +This is shortcut is neccessary as `FreePool` have different library implementations: +``` +MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c +MdePkg/Library/SmmMemoryAllocationLib/MemoryAllocationLib.c +MdePkg/Library/UefiMemoryAllocationLib/MemoryAllocationLib.c +``` +This is the example of LibraryClass that can have several possible instances. In our case we use `UefiMemoryAllocationLib` instance. + +UefiLessonsPkg/UefiLessonsPkg.dsc: +``` +[LibraryClasses] + ... + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + ... +``` + +Now if we build and execute our app under OVMF this code will give us: +``` +752F3136-4E16-4FDC-A22A-E5F46812F4CA +BC62157E-3E33-4FEC-9920-2D3B36D750DF +5B1B31A1-9562-11D2-8E3F-00A0C969723B +``` +Which are the same GUIDs we've discovered through hardcore raw walkthrough through the handle/protocol databases. + + + diff --git a/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.c new file mode 100644 index 0000000..1f05899 --- /dev/null +++ b/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.c @@ -0,0 +1,15 @@ +#include +#include + +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n"); + gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n"); + Print(L"Bye!\n"); + return EFI_SUCCESS; +} diff --git a/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.inf new file mode 100644 index 0000000..d65ca2e --- /dev/null +++ b/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.inf @@ -0,0 +1,18 @@ +[Defines] + INF_VERSION = 1.25 + BASE_NAME = HelloWorld + FILE_GUID = 2e55fa38-f148-42d3-af90-1be247323e30 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +[Sources] + HelloWorld.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + diff --git a/Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.c new file mode 100644 index 0000000..6117243 --- /dev/null +++ b/Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.c @@ -0,0 +1,102 @@ +#include +#include +#include + +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; + +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; + +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; + + +#define offsetof(a,b) ((INTN)(&(((a*)(0))->b))) + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +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); + + Print(L"Back Protocol Interface Link: %p\n", MyHandle->Protocols.BackLink); + Print(L"Forward Protocol Interface Link: %p\n", MyHandle->Protocols.ForwardLink); + + LIST_ENTRY *FirstLink = MyHandle->Protocols.ForwardLink; + LIST_ENTRY *CurrentLink = FirstLink; + do { + PROTOCOL_INTERFACE* MyProtocolInterface = container_of(CurrentLink, PROTOCOL_INTERFACE, Link); + + Print(L"\n"); + Print(L"Current Link: %p\n", CurrentLink); + Print(L"Signature: %x %x %x %x\n", (MyProtocolInterface->Signature >> 0) & 0xff, + (MyProtocolInterface->Signature >> 8) & 0xff, + (MyProtocolInterface->Signature >> 16) & 0xff, + (MyProtocolInterface->Signature >> 24) & 0xff); + + Print(L"Back Link: %p\n", MyProtocolInterface->Link.BackLink); + Print(L"Forward Link: %p\n", MyProtocolInterface->Link.ForwardLink); + Print(L"GUID=%g\n", MyProtocolInterface->Protocol->ProtocolID); + CurrentLink = MyProtocolInterface->Link.ForwardLink; + } while (CurrentLink != FirstLink); + + Print(L"________\n"); + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + EFI_STATUS Status = gBS->ProtocolsPerHandle(ImageHandle, + &ProtocolGuidArray, + &ArrayCount); + + if (Status == EFI_SUCCESS) { + for (int i=0; i +#include + +#include +#include + +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL* LoadedImage; + + Status = gBS->HandleProtocol( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &LoadedImage + ); + + if (Status == EFI_SUCCESS) { + EFI_DEVICE_PATH_PROTOCOL* DevicePath; + + Status = gBS->HandleProtocol( + ImageHandle, + &gEfiLoadedImageDevicePathProtocolGuid, + (VOID**) &DevicePath + ); + + if (Status == EFI_SUCCESS) { + Print(L"Image device: %s\n", ConvertDevicePathToText(DevicePath, FALSE, TRUE)); + Print(L"Image file: %s\n", ConvertDevicePathToText(LoadedImage->FilePath, FALSE, TRUE)); // EFI_DEVICE_PATH_PROTOCOL *FilePath + Print(L"Image Base: %X\n", LoadedImage->ImageBase); + Print(L"Image Size: %X\n", LoadedImage->ImageSize); + } else { + Print(L"Can't get EFI_LOADED_IMAGE_PROTOCOL, Status=%r\n", Status); + } + } else { + Print(L"Can't get EFI_DEVICE_PATH_PROTOCOL, Status=%r\n", Status); + } + return EFI_SUCCESS; +} diff --git a/Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.inf new file mode 100644 index 0000000..0ce54a6 --- /dev/null +++ b/Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.inf @@ -0,0 +1,22 @@ +[Defines] + INF_VERSION = 1.25 + BASE_NAME = ImageInfo + FILE_GUID = b68d3472-70c7-4928-841b-6566032e0a23 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +[Sources] + ImageInfo.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + +[Protocols] + gEfiLoadedImageProtocolGuid + gEfiLoadedImageDevicePathProtocolGuid + diff --git a/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.c new file mode 100644 index 0000000..8bdf500 --- /dev/null +++ b/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.c @@ -0,0 +1,10 @@ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} + diff --git a/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.inf new file mode 100644 index 0000000..7d4bae2 --- /dev/null +++ b/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.inf @@ -0,0 +1,16 @@ +[Defines] + INF_VERSION = 1.25 + BASE_NAME = SimplestApp + FILE_GUID = 4a298956-fbe0-47fb-ae3a-2d5a0a959a26 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +[Sources] + SimplestApp.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint diff --git a/Lessons/Lesson_09/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_09/UefiLessonsPkg/UefiLessonsPkg.dsc new file mode 100644 index 0000000..ff2edf6 --- /dev/null +++ b/Lessons/Lesson_09/UefiLessonsPkg/UefiLessonsPkg.dsc @@ -0,0 +1,32 @@ +[Defines] + DSC_SPECIFICATION = 0x0001001C + PLATFORM_GUID = 3db7270f-ffac-4139-90a4-0ae68f3f8167 + PLATFORM_VERSION = 0.01 + PLATFORM_NAME = UefiLessonsPkg + SKUID_IDENTIFIER = DEFAULT + SUPPORTED_ARCHITECTURES = X64 + BUILD_TARGETS = RELEASE + + +[LibraryClasses] + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + +[Components] + UefiLessonsPkg/SimplestApp/SimplestApp.inf + UefiLessonsPkg/HelloWorld/HelloWorld.inf + UefiLessonsPkg/ImageHandle/ImageHandle.inf + UefiLessonsPkg/ImageInfo/ImageInfo.inf + + -- cgit v1.2.3-18-g5258