1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
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.
|