Brief introduction
Under UEFI, a number of network boot methods are implemented, such as HTTP boot and PXE boot. The corresponding default is as follows:
!if $(PXE_ENABLE) == TRUE
NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf
!endif
!if $(HTTP_BOOT_ENABLE) == TRUE
NetworkPkg/DnsDxe/DnsDxe.inf
NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf
NetworkPkg/HttpDxe/HttpDxe.inf
NetworkPkg/HttpBootDxe/HttpBootDxe.inf
!endif
From their macro definitions, you can see which codes correspond to specific HTTP startup and PXE startup. The two network startup methods are introduced below.
PXE boot
PXE network startup is an older network startup method. The specific usage method is introduced in the PXE introduction and usage instructions , and here is mainly about its realization. First look at the NetworkPkg\UefiPxeBcDxe\UefiPxeBcDxe.inf file, from here you can see that it actually implements two Protocols for packaging the entire PXE action:
[Protocols]
## TO_START
## SOMETIMES_CONSUMES
gEfiDevicePathProtocolGuid
gEfiNetworkInterfaceIdentifierProtocolGuid_31 ## SOMETIMES_CONSUMES
gEfiArpServiceBindingProtocolGuid ## TO_START
gEfiArpProtocolGuid ## TO_START
gEfiIp4ServiceBindingProtocolGuid ## TO_START
gEfiIp4ProtocolGuid ## TO_START
gEfiIp4Config2ProtocolGuid ## TO_START
gEfiIp6ServiceBindingProtocolGuid ## TO_START
gEfiIp6ProtocolGuid ## TO_START
gEfiIp6ConfigProtocolGuid ## TO_START
gEfiUdp4ServiceBindingProtocolGuid ## TO_START
gEfiUdp4ProtocolGuid ## TO_START
gEfiMtftp4ServiceBindingProtocolGuid ## TO_START
gEfiMtftp4ProtocolGuid ## TO_START
gEfiDhcp4ServiceBindingProtocolGuid ## TO_START
gEfiDhcp4ProtocolGuid ## TO_START
gEfiUdp6ServiceBindingProtocolGuid ## TO_START
gEfiUdp6ProtocolGuid ## TO_START
gEfiMtftp6ServiceBindingProtocolGuid ## TO_START
gEfiMtftp6ProtocolGuid ## TO_START
gEfiDhcp6ServiceBindingProtocolGuid ## TO_START
gEfiDhcp6ProtocolGuid ## TO_START
gEfiDns6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
gEfiDns6ProtocolGuid ## SOMETIMES_CONSUMES
gEfiPxeBaseCodeCallbackProtocolGuid ## SOMETIMES_PRODUCES
gEfiPxeBaseCodeProtocolGuid ## BY_START
gEfiLoadFileProtocolGuid ## BY_START
gEfiAdapterInformationProtocolGuid ## SOMETIMES_CONSUMES
BY_START here means to generate a protocol, you can find their installation code directly in NetworkPkg\UefiPxeBcDxe\PxeBcDriver.c:
//
// Create a new handle for IPv4 virtual nic,
// and install PxeBaseCode, LoadFile and DevicePath protocols.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&Private->Ip4Nic->Controller,
&gEfiDevicePathProtocolGuid,
Private->Ip4Nic->DevicePath,
&gEfiLoadFileProtocolGuid,
&Private->Ip4Nic->LoadFile,
&gEfiPxeBaseCodeProtocolGuid,
&Private->PxeBc,
NULL
);
In fact, it will be installed twice, corresponding to IPv4 and IPv6. We still take IPv4 as an example. You can see that in addition to the two Protocols mentioned above, Device Path Protocol is also installed. It is installed as a general requirement. Here No special instructions.
///
/// The EFI_LOAD_FILE_PROTOCOL is a simple protocol used to obtain files from arbitrary devices.
///
struct _EFI_LOAD_FILE_PROTOCOL {
EFI_LOAD_FILE LoadFile;
};
It is an interface for obtaining files. In fact, PXE is only a process of obtaining BootLoader through the network, so the interface here is also very consistent. Also need to explain, in fact, HTTP startup also implements this interface, because it only obtains the BootLoader through the network.
The implementation of LoadFile is as follows (NetworkPkg\UefiPxeBcDxe\PxeBcImpl.c):
EFI_LOAD_FILE_PROTOCOL gLoadFileProtocolTemplate = { EfiPxeLoadFile };
Its concrete realization is from PxeBc .
The protocol corresponding to gEfiPxeBaseCodeProtocolGuid is slightly more complicated (MdePkg\Include\Protocol\PxeBaseCode.h):
///
/// The EFI_PXE_BASE_CODE_PROTOCOL is used to control PXE-compatible devices.
/// An EFI_PXE_BASE_CODE_PROTOCOL will be layered on top of an
/// EFI_MANAGED_NETWORK_PROTOCOL protocol in order to perform packet level transactions.
/// The EFI_PXE_BASE_CODE_PROTOCOL handle also supports the
/// EFI_LOAD_FILE_PROTOCOL protocol. This provides a clean way to obtain control from the
/// boot manager if the boot path is from the remote device.
///
struct _EFI_PXE_BASE_CODE_PROTOCOL {
///
/// The revision of the EFI_PXE_BASE_CODE_PROTOCOL. All future revisions must
/// be backwards compatible. If a future version is not backwards compatible
/// it is not the same GUID.
///
UINT64 Revision;
EFI_PXE_BASE_CODE_START Start;
EFI_PXE_BASE_CODE_STOP Stop;
EFI_PXE_BASE_CODE_DHCP Dhcp;
EFI_PXE_BASE_CODE_DISCOVER Discover;
EFI_PXE_BASE_CODE_MTFTP Mtftp;
EFI_PXE_BASE_CODE_UDP_WRITE UdpWrite;
EFI_PXE_BASE_CODE_UDP_READ UdpRead;
EFI_PXE_BASE_CODE_SET_IP_FILTER SetIpFilter;
EFI_PXE_BASE_CODE_ARP Arp;
EFI_PXE_BASE_CODE_SET_PARAMETERS SetParameters;
EFI_PXE_BASE_CODE_SET_STATION_IP SetStationIp;
EFI_PXE_BASE_CODE_SET_PACKETS SetPackets;
///
/// The pointer to the EFI_PXE_BASE_CODE_MODE data for this device.
///
EFI_PXE_BASE_CODE_MODE *Mode;
};
It actually needs to complete network communication-related actions, such as DHCP/TFPT. The implementation of PxeBc is as follows (NetworkPkg\UefiPxeBcDxe\PxeBcImpl.c):
EFI_PXE_BASE_CODE_PROTOCOL gPxeBcProtocolTemplate = {
EFI_PXE_BASE_CODE_PROTOCOL_REVISION,
EfiPxeBcStart,
EfiPxeBcStop,
EfiPxeBcDhcp,
EfiPxeBcDiscover,
EfiPxeBcMtftp,
EfiPxeBcUdpWrite,
EfiPxeBcUdpRead,
EfiPxeBcSetIpFilter,
EfiPxeBcArp,
EfiPxeBcSetParameters,
EfiPxeBcSetStationIP,
EfiPxeBcSetPackets,
NULL
};
And PxeBc and LoadFile relationship between the structure are connected by the following together (NetworkPkg \ UefiPxeBcDxe \ PxeBcImpl.h):
struct _PXEBC_VIRTUAL_NIC {
UINT32 Signature;
EFI_HANDLE Controller;
EFI_LOAD_FILE_PROTOCOL LoadFile;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
PXEBC_PRIVATE_DATA *Private;
};
HTTP start
Although HTTP itself is not new, it is still newer than PXE when used for network boot. Compared with PXE using TFTP to download Boot Loader, HTTP startup is of course using HTTP to download Boot Loader. Although there is no essential difference between the two, HTTP has wider applicability. The following is the environment diagram of HTTP startup:
BootLoader is located on the HTTP server, not on the TFTP server started by PXE. And HTTP uses URI to access server equipment, while PXE uses IP to access server equipment.
The implementation of HTTP startup is slightly more complicated than PXE startup, involving content such as DNS/DHCP/URL. But the key is the NetworkPkg\HttpBootDxe\HttpBootDxe.inf module, which implements EFI_LOAD_FILE_PROTOCOL (NetworkPkg\HttpBootDxe\HttpBootDxe.c):
//
// Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.
//
CopyMem (&Private->Ip4Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (EFI_LOAD_FILE_PROTOCOL));
Status = gBS->InstallMultipleProtocolInterfaces (
&Private->Ip4Nic->Controller,
&gEfiLoadFileProtocolGuid,
&Private->Ip4Nic->LoadFile,
&gEfiDevicePathProtocolGuid,
Private->Ip4Nic->DevicePath,
NULL
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
It is also divided into two types, IPv4 and IPv6. The corresponding LoadFile implementation (NetworkPkg\HttpBootDxe\HttpBootImpl.c):
///
/// Load File Protocol instance
///
GLOBAL_REMOVE_IF_UNREFERENCED
EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile = {
HttpBootDxeLoadFile
};
There are also some protocols used to handle HTTP communication, such as:
///
/// EFI_HTTP_UTILITIES_PROTOCOL
/// designed to be used by EFI drivers and applications to parse HTTP
/// headers from a byte stream. This driver is neither dependent on
/// network connectivity, nor the existence of an underlying network
/// infrastructure.
///
struct _EFI_HTTP_UTILITIES_PROTOCOL {
EFI_HTTP_UTILS_BUILD Build;
EFI_HTTP_UTILS_PARSE Parse;
};
///
/// The EFI_DNS4_Protocol provides the function to get the host name and address
/// mapping, also provides pass through interface to retrieve arbitrary information
/// from DNS.
///
struct _EFI_DNS4_PROTOCOL {
EFI_DNS4_GET_MODE_DATA GetModeData;
EFI_DNS4_CONFIGURE Configure;
EFI_DNS4_HOST_NAME_TO_IP HostNameToIp;
EFI_DNS4_IP_TO_HOST_NAME IpToHostName;
EFI_DNS4_GENERAL_LOOKUP GeneralLookUp;
EFI_DNS4_UPDATE_DNS_CACHE UpdateDnsCache;
EFI_DNS4_POLL Poll;
EFI_DNS4_CANCEL Cancel;
};
For HTTP boot, you can also refer to: https://github.com/tianocore/tianocore.github.io/wiki/HTTP-Boot .
Network startup items
After a brief introduction to HTTP startup and PXE startup, the follow-up need to pay attention to how to use these startup implementations. In fact, as mentioned earlier, this is mainly done through EFI_LOAD_FILE_PROTOCOL . For network startup, the approximate code is as follows:
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);
if (EFI_ERROR (Status)) {
HandleCount = 0;
Handles = NULL;
}
NextFullPath = NULL;
GetNext = (BOOLEAN)(FullPath == NULL);
for (Index = 0; Index < HandleCount; Index++) {
NextFullPath = BmExpandLoadFile (Handles[Index], FilePath);
Here get all the implemented EFI_LOAD_FILE_PROTOCOL , and for each protocol, call its LoadFile to get the file. However, it should be noted that because the addresses used for HTTP startup and PXE startup are different, the corresponding Device Path is also different:
/**
Causes the driver to load a specified file.
@param This Protocol instance pointer.
@param FilePath The device specific path of the file to load.
@param BootPolicy If TRUE, indicates that the request originates from the
boot manager is attempting to load FilePath as a boot
selection. If FALSE, then FilePath must match as exact file
to be loaded.
@param BufferSize On input the size of Buffer in bytes. On output with a return
code of EFI_SUCCESS, the amount of data transferred to
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
the size of Buffer required to retrieve the requested file.
@param Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
then the size of the requested file is returned in
BufferSize.
@retval EFI_SUCCESS The file was loaded.
@retval EFI_UNSUPPORTED The device does not support the provided BootPolicy
@retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
BufferSize is NULL.
@retval EFI_NO_MEDIA No medium was present to load the file.
@retval EFI_DEVICE_ERROR The file was not loaded due to a device error.
@retval EFI_NO_RESPONSE The remote system did not respond.
@retval EFI_NOT_FOUND The file was not found.
@retval EFI_ABORTED The file load process was manually cancelled.
@retval EFI_WARN_FILE_SYSTEM The resulting Buffer contains UEFI-compliant file system.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_LOAD_FILE)(
IN EFI_LOAD_FILE_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN BOOLEAN BootPolicy,
IN OUT UINTN *BufferSize,
IN VOID *Buffer OPTIONAL
);
That is, the FilePath here has different values. Device Path structure corresponding to HTTP:
///
/// Uniform Resource Identifiers (URI) Device Path SubType
///
#define MSG_URI_DP 0x18
typedef struct {
EFI_DEVICE_PATH_PROTOCOL Header;
///
/// Instance of the URI pursuant to RFC 3986.
///
CHAR8 Uri[];
} URI_DEVICE_PATH;
Device Path will be used in the implementation of HttpBootDxeLoadFile :
EFI_STATUS
EFIAPI
HttpBootDxeLoadFile (
IN EFI_LOAD_FILE_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN BOOLEAN BootPolicy,
IN OUT UINTN *BufferSize,
IN VOID *Buffer OPTIONAL
)
{
HTTP_BOOT_PRIVATE_DATA *Private;
HTTP_BOOT_VIRTUAL_NIC *VirtualNic;
BOOLEAN MediaPresent;
BOOLEAN UsingIpv6;
EFI_STATUS Status;
HTTP_BOOT_IMAGE_TYPE ImageType;
if (This == NULL || BufferSize == NULL || FilePath == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Only support BootPolicy
//
if (!BootPolicy) {
return EFI_UNSUPPORTED;
}
VirtualNic = HTTP_BOOT_VIRTUAL_NIC_FROM_LOADFILE (This);
Private = VirtualNic->Private;
//
// Check media status before HTTP boot start
//
MediaPresent = TRUE;
NetLibDetectMedia (Private->Controller, &MediaPresent);
if (!MediaPresent) {
return EFI_NO_MEDIA;
}
//
// Check whether the virtual nic is using IPv6 or not.
//
UsingIpv6 = FALSE;
if (VirtualNic == Private->Ip6Nic) {
UsingIpv6 = TRUE;
}
//
// Initialize HTTP boot.
//
Status = HttpBootStart (Private, UsingIpv6, FilePath);
if (Status != EFI_SUCCESS && Status != EFI_ALREADY_STARTED) {
return Status;
}
And PXE boot does not need a special Device Path:
EFI_STATUS
EFIAPI
EfiPxeLoadFile (
IN EFI_LOAD_FILE_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN BOOLEAN BootPolicy,
IN OUT UINTN *BufferSize,
IN VOID *Buffer OPTIONAL
)
{
PXEBC_PRIVATE_DATA *Private;
PXEBC_VIRTUAL_NIC *VirtualNic;
EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
BOOLEAN UsingIpv6;
EFI_STATUS Status;
BOOLEAN MediaPresent;
if (FilePath == NULL || !IsDevicePathEnd (FilePath)) {
return EFI_INVALID_PARAMETER;
}
Only judgment is made here, but it is not really used. Except for Device Path, there is no big difference between the two calling LoadFile .