Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Let's print GUID for all the protocols that are exist in our IMAGE_HANDLE.

First understand what EFI_GUID internally means in the edk2 codebase:

https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiBaseType.h

///
/// 128-bit buffer containing a unique identifier value.
///
typedef GUID                      EFI_GUID;

GUID structure is defined in https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Base.h :

///
/// 128 bit buffer containing a unique identifier value.
/// Unless otherwise specified, aligned on a 64 bit boundary.
///
typedef struct {
  UINT32  Data1;
  UINT16  Data2;
  UINT16  Data3;
  UINT8   Data4[8];
} GUID;

Fortunately we don't have to manually print all these fields by hand. Print function has a format option %g to print GUIDs, so we could simply print GUIDs with a code like this:

Print("GUID=%g\n", myGUID);

More information about Print formating options can be found at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PrintLib.h

We want to print EFI_GUID field from the PROTOCOL_ENTRY structure which are referred from the PROTOCOL_INTERFACE structures. So we need to define both of these structures in our file for the same reason we've defined IHANDLE earlier.

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;

PROTOCOL_INTERFACE structures that are connected to any HANDLE are interlinked with each other with a help of a LIST_ENTRY Link field that connects them to a double linked list.

As you may remember LIST_ENTRY is defined like this:

///
/// LIST_ENTRY structure definition.
///
typedef struct _LIST_ENTRY LIST_ENTRY;

///
/// _LIST_ENTRY structure definition.
///
struct _LIST_ENTRY {
  LIST_ENTRY  *ForwardLink;
  LIST_ENTRY  *BackLink;
};

Each of these fields inside these structure points to another LIST_ENTRY structure that is placed in another PROTOCOL_INTERFACE.

So this connection looks like this:

typedef struct {                                         typedef struct {
  UINTN                       Signature;                   UINTN                       Signature;
  struct LIST_ENTRY {                          |---------> struct LIST_ENTRY {
    LIST_ENTRY  *ForwardLink; -----------------|             LIST_ENTRY  *ForwardLink;
    LIST_ENTRY  *BackLink;                                   LIST_ENTRY  *BackLink;
  } Link;                                                  } Link;
  IHANDLE                     *Handle;                     IHANDLE                     *Handle;
  LIST_ENTRY                  ByProtocol;                  LIST_ENTRY                  ByProtocol;
  PROTOCOL_ENTRY              *Protocol;                   PROTOCOL_ENTRY              *Protocol;
  VOID                        *Interface;                  VOID                        *Interface;
  LIST_ENTRY                  OpenList;                    LIST_ENTRY                  OpenList;
  UINTN                       OpenListCount;               UINTN                       OpenListCount;
} PROTOCOL_INTERFACE;                                    } PROTOCOL_INTERFACE;

But in reality we want a pointer not to Link field of another PROTOCOL_INTERFACE structure, we want a pointer to another PROTCOL_INTERFACE structure inself.

Therefore one more thing that we would need is a couple of macros:

#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) );})

These macros can be familiar to you if you've investigated linux kernel programming. This is where I got them from anyway.

contianer_of macro helps to get a pointer to a structure if you have a pointer to one of its fields.

If you want to understand how it works internally in C language I suggest you to look at the https://stackoverflow.com/questions/15832301/understanding-container-of-macro-in-the-linux-kernel

With all of this information final code for our UefiMain function would look like this:

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: %c %c %c %c\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);

  return EFI_SUCCESS;
}

If we compile and run our app in OVMF (I hope at this time I don't need to repeat how to do it):

FS0:\> ImageHandle.efi
h n d l
Back Protocol Interface Link: 68D4320
Forward Protocol Interface Link: 6891520

Current Link: 6891520
p i f c
Back Link: 6891430
Forward Link: 6891B20
GUID=752F3136-4E16-4FDC-A22A-E5F46812F4CA

Current Link: 6891B20
p i f c
Back Link: 6891520
Forward Link: 68D4320
GUID=BC62157E-3E33-4FEC-9920-2D3B36D750DF

Current Link: 68D4320
p i f c
Back Link: 6891B20
Forward Link: 6891430
GUID=5B1B31A1-9562-11D2-8E3F-00A0C969723B

Current Link: 6891430
  ? ? ?
Back Link: 68D4320
Forward Link: 6891520
GUID=00000000-0000-0000-0000-000000000000

Let's find first GUID by executing grep on the edk2 source:

$ grep -i 752F3136 -r ./ --exclude-dir=Build
./MdePkg/Include/Protocol/ShellParameters.h:  0x752f3136, 0x4e16, 0x4fdc, { 0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca } \
./MdePkg/MdePkg.dec:  gEfiShellParametersProtocolGuid      = { 0x752f3136, 0x4e16, 0x4fdc, {0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca }}

https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/ShellParameters.h

#define EFI_SHELL_PARAMETERS_PROTOCOL_GUID \
  { \
  0x752f3136, 0x4e16, 0x4fdc, { 0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca } \
  }

You can also see in in a https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec file:

  ## Include/Protocol/ShellParameters.h
  gEfiShellParametersProtocolGuid      = { 0x752f3136, 0x4e16, 0x4fdc, {0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca }}

The next two GUIDs you can find in UEFI the specification.

EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL - When installed, the Loaded Image Device Path Protocol specifies the device path that was used when a PE/COFF image was loaded through the EFI Boot Service LoadImage().

#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \
{0xbc62157e,0x3e33,0x4fec,\
 {0x99,0x20,0x2d,0x3b,0x36,0xd7,0x50,0xdf}}

EFI_LOADED_IMAGE_PROTOCOL - Can be used on any image handle to obtain information about the loaded image.

#define EFI_LOADED_IMAGE_PROTOCOL_GUID\
 {0x5B1B31A1,0x9562,0x11d2,\
 {0x8E,0x3F,0x00,0xA0,0xC9,0x69,0x72,0x3B}}

The last PROTOCOL_INTERFACE structure doesn't have a valid "p i f c" signature (in my case it is 0x20 0x0E 0xED 0x06), so we don't need to look at its GUID.