8.4 Communication between DXE Drivers
This section introduces communication channels between DXE drivers, including protocol, variable, and PCD.

8.4.1 Protocol

This section will introduce how to produce and consume protocols. The UEFI Specification defines a group of boot services to handle protocols, including:
Services to install protocols
    InstallProtocolInterface()
    ReInstallProtocolInterface()
    InstallMultipleProtocolInterfaces()
Services to retrieve protocols
    LocateProtocol()
    OpenProtocol()
First, to make use of it, the module writer must declare the protocols for the module in the INF and then write code to use the protocols.
The following example demonstrates how a DXE driver produces a protocol:
1
//
2
// Handle for new protocol instance. Since it's NULL now, its value will
3
// be assigned by Boot Service InstallMultipleProtocolInterfaces()
4
//
5
EFI_HANDLE mNewHandle = NULL;
6
//
7
// The Sample Protocol instance produced by this driver
8
//
9
EFI_SAMPLE_PROTOCOL mSampleProtocol = {
10
SampleProtocolApi
11
//
12
// More APIs can be added here
13
//
14
};
15
//
16
// This is just a NULL function with no parameters. Necessary parameters
17
// and code can be added.
18
//
19
EFI_STATUS
20
EFIAPI
21
SampleProtocolApi (
22
VOID
23
)
24
{
25
return EFI_SUCCESS;
26
}
27
EFI_STATUS
28
EFIAPI
29
SampleDriverInitialize (
30
IN EFI_HANDLE ImageHandle,
31
IN EFI_SYSTEM_TABLE *SystemTable
32
)
33
{
34
EFI_STATUS Status;
35
//
36
// More initialization can be added here.
37
//
38
//
39
// Install the Sample Protocol onto a new handle
40
//
41
Status = gBS->InstallMultipleProtocolInterfaces (
42
&mNewHandle,
43
&gEfiSampleProtocolGuid,
44
&mSampleProtocol,
45
NULL
46
);
47
ASSERT_EFI_ERROR (Status);
48
return EFI_SUCCESS;
49
}
Copied!
The following example demonstrates how a DXE driver retrieves a protocol and invokes the API:
1
EFI_STATUS
2
SampleFunction (
3
VOID
4
)
5
{
6
EFI_STATUS Status;
7
EFI_SAMPLE_PROTOCOL *SampleProtocol;
8
//
9
// Locates the Sample Protocol from system.
10
//
11
Status = gBS->LocateProtocol (
12
&gEfiSampleProtocolGuid,
13
NULL,
14
(VOID **) &SampleProtocol
15
);
16
if (EFI_ERROR (Status)) {
17
return Status;
18
}
19
Status = SampleProtocol->SampleProtocolApi();
20
return Status;
21
}
Copied!

8.4.2 Variable

Variables are defined as key/value pairs that consist of identifying information plus attributes (the key) and arbitrary data (the value). Variables are intended for use as a means to store data that is passed between the EFI environment implemented in the platform and EFI OS loaders and other applications that run in the EFI environment.
A DXE driver can read and write variables via the UEFI Runtime Services GetVariable() and SetVariable().
Note: These services are not available at the beginning of the DXE phase . The PI Specification defines two architectural protocols to indicate the readiness of read/write access to variables: EFIVARIABLE_ARCH_PROTOCOL and EFI_VARIABLE_WRITE_ARCH_PROTOCOL._
DXE drivers that require read-only access or read/write access to volatile environment variables must have EFI_VARIABLE_ARCH_PROTOCOL in their dependency expressions.
DXE drivers that require write access to nonvolatile environment variables must have the EFI_VARIABLE_WRITE_ARCH_PROTOCOL in their dependency expressions.
The full complement of environment variable services is not available until both EFI_VARIABLE_ARCH_PROTOCOL and EFI_VARIABLE_WRITE_ARCH_PROTOCOL are installed.
Sample code to read and write variables is as follows:
1
EFI_STATUS
2
ReadAndWriteVariable (
3
IN CHAR16 *Name,
4
IN EFI_GUID *VendorGuid,
5
){
6
EFI_STATUS Status;
7
UINTN BufferSize;
8
VOID *Buffer;
9
Buffer = NULL;
10
//
11
// Pass in a zero-size buffer to find the required buffer size.
12
//
13
BufferSize = 0;
14
Status = gRT->GetVariable (
15
Name,
16
VendorGuid,
17
NULL,
18
&BufferSize,
19
Buffer
20
);
21
//
22
// If variable exists, the Status should be EFI_BUFFER_TOO_SMALL and
23
// BufferSize has been updated.
24
//
25
if (Status != EFI_BUFFER_TOO_SMALL) {
26
return Status;
27
}
28
//
29
// Allocate the buffer according to updated BufferSize.
30
//
31
Buffer = AllocateZeroPool (BufferSize);
32
ASSERT (Buffer != NULL);
33
//
34
// Read variable into the allocated buffer.
35
//
36
Status = gRT->GetVariable (
37
Name,
38
VendorGuid,
39
NULL,
40
&BufferSize,
41
Buffer
42
);
43
if (EFI_ERROR (Status)) {
44
BufferSize = 0;
45
}
46
//
47
// TODO: Process of retrieved variable can be added here.
48
//
49
//
50
// Now write back the processed variable.
51
//
52
Status = gRT->SetVariable (
53
Name,
54
VendorGuid,
55
EFI_VARIABLE_BOOTSERVICE_ACCESS |
56
EFI_VARIABLE_RUNTIME_ACCESS |
57
EFI_VARIABLE_NON_VOLATILE,
58
BufferSize,
59
Buffer
60
);
61
ASSERT_EFI_ERROR (Status);
62
return EFI_SUCCESS;
63
}
Copied!

8.4.3 Dynamic PCD

EDK II provides dynamic PCDs as a high-level mechanism for communication between modules. See Appendix A for details.
Last modified 1yr ago