Newer
Older
AMI-Aptio-BIOS-Reversed / HttpBootDxe / HttpBootDxe.c
@Ajax Dong Ajax Dong 2 days ago 13 KB Init
/** @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
};