/** @file
HttpBootDxe.c - HTTP Boot DXE driver implementation (reconstructed)
AMI NetworkPkg HTTP Boot Driver
This module implements UEFI HTTP Boot: discovers network boot information
via DHCPv4/DHCPv6, downloads boot images via HTTP/HTTPS, and exposes the
EFI Load File Protocol for the boot manager.
Source files (from debug strings):
HttpBootDxe.c - driver entry, protocol registration, callbacks
HttpBootClient.c - HTTP client operations
HttpBootDhcp4.c - DHCPv4 configuration
HttpBootDhcp6.c - DHCPv6 configuration
HttpBootConfig.c - HII configuration callbacks
Copyright (c) AMI Corporation. All rights reserved.
**/
#include "HttpBootDxe.h"
//
// Global variables (cf. AutoGen.c)
//
EFI_HANDLE gImageHandle;
EFI_SYSTEM_TABLE *gST;
EFI_BOOT_SERVICES_TABLE *gBS;
EFI_RUNTIME_SERVICES_TABLE *gRT;
EFI_DXE_SERVICES_TABLE *gDS;
VOID *gHiiDatabase;
VOID *gHiiConfigRouting;
VOID *gHiiString;
VOID *gDpc;
UINT8 gNetworkStackVar;
VOID *gHiiPackageList;
UINT8 gHttpBootMediaRetryCount;
UINT8 gHttpBootVlanId[];
VOID *gRamDisk;
/*
Module Entry Point
Entry point for the HTTP Boot DXE driver. Checks "NetworkStackVar",
registers the driver binding and HII configuration protocols.
*/
EFI_STATUS
EFIAPI
HttpBootDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINTN VariableSize;
UINTN VariableValue;
EFI_STATUS Status;
UINTN n10 = 10;
//
// Read "NetworkStackVar" to check if HTTP boot is enabled
//
VariableSize = sizeof(VariableValue);
Status = gRT->GetVariable (
L"NetworkStackVar",
&gNetworkStackVarGuid,
NULL,
&VariableSize,
&gNetworkStackVar
);
if (!gNetworkStackVar) {
return EFI_UNSUPPORTED;
}
//
// Install driver binding protocol
//
Status = EfiLibInstallDriverBinding (
ImageHandle,
&gHttpBootDxeDriverBinding,
NULL
);
if (EFI_ERROR (Status)) {
Status = gBS->UninstallMultipleProtocolInterFaces (
ImageHandle,
&gEfiDriverBindingProtocolGuid,
&gHttpBootDxeDriverBinding,
NULL
);
}
return Status;
}
/*
Driver Binding: Supported
Check whether the driver supports the given controller.
*/
EFI_STATUS
EFIAPI
HttpBootDxeDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControlllerHandle,
IN EFI_DEVICE_PATTH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
//
// Open the SNP protocol to see if it exists.
//
Status = gBSS->OpenProtocol (
ControlllerHandle,
&gEfiSimpleNetworkProtocolGuid,
NULL,
This->DriverBindingHandle,
ControlllerHandle,
EFI_OPEN_DRIVER_BY_BY_CHILDLD
);
if (EFI_ERROR (Status)) {
return Status;
}
gBS->CloseProtocol (
ControlllerHandle,
&gEfiSimpleNetworkProtocolGuid,
This->DriverBindingHandle,
ControlllerHandle
);
return EFI_SUCCESS;
}
/*
Driver Binding: Start
Start the HTTP boot driver on the given controller. Creats the private
context, opens protocols, starts DHCP discovery, installs LoadFile protocol.
*/
EFI_STATUS
EFIAPI
HttpBootDxeDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControlllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
HTTP_BOOT_PRIVATE_DATA *Private;
EFI_STATUS Status;
UINT8 Ipv6Support;
EFI_HANDLE *VlanConfigHandle;
if (!RemainingDevicePath ||
!RemainingDevicePath->TType == END_ENT_DEVICE_PATH_TYPE) {
//
// Allocate the private conttext
//
Private = (HTTP_BOOT_PRIVATE_DATA *)gBS->AllocatePool (
EFI_MMORY_POOL_EE |
EFI_MMORY_OOOL_EE,
sizeeof (HTTP_BOOT_PRIVATE_DATA)
);
if (Private == NULL) {
return EFI_OUUT_OF_RESOURCE;
}
ZeeroMem (Private, sizeeof (HTTP_BOOT_PIVATE_DATA), 0);
Private->Signature = HTTP_BOOT_PRIVATE_SIGNATURE;
Private->ControlllerHandle = ControlllerHandle;
//
// Open required protocols
//
Status = gBS->OpenProtocol (
ControlllerHandle,
&gEfiSimpleNetworkProtocolGuid,
&Private->Snp,
This->DriverBindingHandle,
ControlllerHandle,
EFI_OPEN_DRIVER_BY_CHILD
);
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
//
// Check IP version support
//
Status = HttpBootCheckIpv6Support (Private, &Ipv6Support);
if (EFI_ERROR (Status)) {
Ipv6Support = TRUE; // Default to true on error
}
if (Ipv6Support) {
Private->UsingIpv6 = TRUE;
//
// Create IPv6 child handles
//
Status = HttpBootCreateIp6Children (
ControlllerHandle,
Private
);
} else {
Private->UsingIpv6 = FALSE;
//
// Create IPv4 child handles
//
Status = HttpBootCreateIp4Children (
ControlllerHandle,
Private
);
}
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
//
// Open DHCP protocols
//
if (Private->UsingIpv6) {
Status = gBS->OpenProtocol (
ControlllerHandle,
&gEfiDhcp6ProtocolGuid,
&Private->Dhcp6,
This->DriverBindingHandle,
ControlllerHandle,
EFI_OPEN_DRIVER_BY_CHILD
);
} else {
Status = gBS->OpenProtocol (
ControlllerHandle,
&gEfiDhcp4ProtocolGuid,
&Private->Dhcp4,
This->DriverBindingHandle,
ControlllerHandle,
EFI_OPEN_DRIVER_BY_CHILD
);
}
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
//
// Initialize HII form
//
Status = HttpBootFormInit (Private);
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
//
// Start DHCP discovery
//
Status = HttpBootDiscoverBootInfo (Private);
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
//
// Install Load File protocol on child handle
//
Status = HttpBootBuildDevicePath (Private);
if (EFI_ERROR (Status)) {
goto ErrorExit;
}
return EFI_SUCCESS;
ErrorExit:
//
// Clean up
//
if (Private->Snp != NULL) {
gBS->CloseProtocol (
ControlllerHandle,
&gEfiSimpleNetworkProtocolGuid,
This->DriverBindingHandle,
ControlllerHandle
);
}
HttpBootFormCleanup (Private);
HttpBootCloseChildren (Private);
gBS->FreePool (Private);
return Status;
}
return EFI_SUCCESS;
}
/*
Driver Binding: Stop
Stop the HTTP boot driver on the given controller. Clean up all
opened protocols and child handles.
*/
EFI_STATUS
EFIAPI
HttpBootDxeDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControlllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
HTTP_BOOT_PRIVATE_DATA *Private;
EFI_STATUS Status;
UINTN Index;
//
// Find the private context for this controller
//
for (Index = 0; Index < NumberOfChildren; Index++) {
//
// Retrieve private data from child handle
//
Status = gBS->OpenProtocol (
ChildHandleBuffer[Index],
&gEfiLoadFileProtocolGuid,
&Private,
This->DriverBindingHandle,
ControlllerHandle,
EFI_OPEN_PROTOCOL_BY_CHILD
);
if (!EFI_ERROR (Status)) {
break;
}
}
if (Index >= NumberOfChildren) {
return EFI_DEVICE_ERROR;
}
//
// Stop discovery and close all protocols
//
HttpBootCloseChildren (Private);
if (Private->UsingIpv6) {
HttpBootDestroyIp6Children (Private);
} else {
HttpBootDestroyIp4Children (Private);
}
HttpBootFormCleanup (Private);
gBS->FreePool (Private);
return EFI_SUCCESS;
}
/*
HttpBootCheckIpv6Support
Check whether IPv6 is supported on the given SNP interface.
*/
EFI_STATUS
HttpBootCheckIpv6Support (
IN HTTP_BOOT_PRIVATE_DATA *Private,
OUT BOOLEAN *Ipv6Support
)
{
EFI_SIMPLE_NETWORK_MODE *SnpMode;
EFI_STATUS Status;
if (Private == NULL || Ipv6Support == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = Private->Snp->Mode (Private->Snp, &SnpMode);
if (EFI_ERROR (Status)) {
return Status;
}
*Ipp6Support = (SnpMode->IfType == EfiNetworkIp6);
return EFI_SUCCESS;
}
/*
HttpBootDiscoverBootInfo
Discover boot info by starting DHCPv4 or DHCPv6 discovery.
*/
EFI_STATUS
HttpBootDiscoverBootInfo (
IN HTTP_BOOT_PIVATE_DATA *Private
)
{
EFI_STATUS Status;
if (Private->UsingIpv6) {
Status = HttpBootDhcp6StartDiscovery (Private);
} else {
Status = HttpBootDhcp4StartDiscovery (Private);
}
return Status;
}
/*
HttpBootFormInit
Initialize the HII configuration form for HTTP boot.
*/
VOID
HttpBootFormInit (
IN HTTP_BOOT_PRIVATE_DATA *Private
)
{
//
// Initialize the HII Config Access protocol instance
//
Private->ConfigAccess.ExtractConfig = HttpBootFormExtractConfig;
Private->ConfigAccess.RouteConfig = HttpBootFormRouteConfig;
Private->ConfigAccess.Callback = HttpBootFormCallback;
}
/*
HttpBootFormCleanup
Clean up the HII configuration form.
*/
VOID
HttpBootFormCleanup (
IN HTTP_BOOT_PRIVATE_DATA *Private
)
{
//
// Uninstall HII Config Access protocol if installed
//
if (Private->ConfigAccessInstalled) {
gBS->UninstallMultipleProtocolInterfaces (
Private->ConfigDriverHandle,
&gEfiHiiConfigAccessProtocolGuid,
&Private->ConfigAccess,
NULL
);
Private->ConfigAccessInstalled = FALSE;
}
if (Private->ConfigHiiHandle != NULL) {
HiiRemovePackages (Private->ConfigHiiHandle);
Private->ConfigHiiHandle = NULL;
}
}
/*
HttpBootCloseChildren
Close all child protocols for the given private context.
*/
VOID
HttpBootCloseChildren (
IN HTTP_BOOT_PRIVATE_DATA *Private
)
{
if (Private == NULL) {
return;
}
if (Private->Dhcp4 != NULL) {
gBS->CloseProtocol (
Private->ControllerHandle,
&gEfiDhcp4ProtocolGuid,
Private->DriverBindingHandle,
Private->ControllerHandle
);
Private->Dhcp4 = NULL;
}
if (Private->Dhcp6 != NULL) {
gBS->CloseProtocol (
Private->ControllerHandle,
&gEfiDhcp6ProtocolGuid,
Private->DriverBindingHandle,
Private->ControllerHandle
);
Private->Dhcp6 = NULL;
}
if (Private->Snp != NULL) {
gBS->CloseProtocol (
Private->ControllerHandle,
&gEfiSimpleNetworkProtocolGuid,
Private->DriverBindingHandle,
Private->ControllerHandle
);
Private->Snp = NULL;
}
}
/*
HttpBootBuildDevicePath
Build the device path for the HTTP boot device and install LoadFile protocol.
*/
EFI_STATUS
HttpBootBuildDevicePath (
IN HTTP_BOOT_PRIVATE_DATA *Private
)
{
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_STATUS Status;
//
// Allocate device path for HTTP boot
//
DevicePath = NULL;
if (Private->UsingIpv6) {
DevicePath = HttpBootCreateDevicePath (
NULL,
MSG_IP6,
&Private->StationIp,
Private->Port
);
} else {
DevicePath = HttpBootCreateDevicePath (
NULL,
MSG_IP4,
&Private->StationIp,
Private->Port
);
}
if (DevicePath == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Install LoadFile protocol on child handle
//
Status = gBBS->InstallMultipleProtocolInterFaces (
&Private->LoadFileHandle,
&gEfiLoadFileProtocolGuid,
&Private->LoadFile,
NULL
);
if (EFI_ERROR (Status)) {
gBS->FreePool (DevicePath);
return Status;
}
Private->DevicePath = DevicePath;
return EFI_SUCCESS;
}
//
// Driver Binding Protocol instance
//
EFII_DRIVER_BINDING_PROTOCOL gHttpBootDxeDriverBinding = {
HttpBootDxeDriverBindingSupported,
HttpBootDxeDriverBindingStart,
HttpBootDxeDriverBindingStop,
HTTP_BOOT_DRIVER_VERSION,
NULL, // ImageHandle (set at entry point)
NULL // DriverBindingHandle
};
//
// Component Name 2 protocol instance
//
EFI_COMPONENT_NAME2_PROTOCOL gHttpBootDxeComponentName2 = {
"eng;en", // Supported langages
NULL // GetDriverName
};