Newer
Older
AMI-Aptio-BIOS-Reversed / MnpDxe / ModuleEntry.c
@Ajax Dong Ajax Dong 2 days ago 16 KB Init
/**
 * @file ModuleEntry.c
 *
 * @brief MNP DXE Driver Entry Point
 *
 * This file implements the DXE driver entry point for the MNP driver.
 * It initializes global service table pointers, locates the DPC protocol,
 * reads the "NetworkStackVar" configuration variable, and installs the
 * Driver Binding Protocol and Component Name protocols.
 *
 * Source: AmiNetworkPkg/UefiNetworkStack/Common/MnpDxe/
 * UEFI Phase: DXE
 */

#include "MnpDxe.h"

//
// =====================================================================
// GLOBAL POINTERS
// =====================================================================
//

EFI_HANDLE               gImageHandle   = NULL;
EFI_SYSTEM_TABLE        *gSystemTable   = NULL;
EFI_BOOT_SERVICES       *gBootServices  = NULL;
EFI_RUNTIME_SERVICES    *gRuntimeServices = NULL;
VOID                    *gDpcProtocol   = NULL;

//
// Saved image handle copies for driver binding usage
//
EFI_HANDLE               gImageHandle_0  = NULL;   /* a.k.a. ImageHandle_0 at 0xA8D0 */
EFI_HANDLE               gImageHandle_1  = NULL;   /* a.k.a. ImageHandle_1 at 0xA8D8 */

//
// =====================================================================
// GUID DEFINITIONS
// =====================================================================
//

EFI_GUID gEfiDriverBindingProtocolGuid =
  { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 } };

EFI_GUID gEfiManagedNetworkServiceBindingProtocolGuid =
  { 0xF36FF770, 0xA7E1, 0x42CF, { 0x9E, 0xD2, 0x56, 0xF0, 0xF2, 0x71, 0xF4, 0x4C } };

EFI_GUID gEfiComponentName2ProtocolGuid =
  { 0x6A7A5CFF, 0xE870, 0x4FBA, { 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14, 0x68 } };

EFI_GUID gEfiLoadedImageProtocolGuid =
  { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } };

EFI_GUID gEfiDpcProtocolGuid =
  { 0x480F8AE9, 0x0C46, 0x4AA9, { 0xBC, 0x89, 0xDB, 0x9F, 0xBA, 0x61, 0x98, 0x06 } };

EFI_GUID gNetworkStackVarGuid =
  { 0x9E2368D7, 0xD2F4, 0x4366, { 0x9F, 0xC3, 0x89, 0xB2, 0x4E, 0x4C, 0x5E, 0x69 } };

EFI_GUID gVlanConfigProtocolGuid =
  { 0x9E23D768, 0xD2F3, 0x4366, { 0x9F, 0xC3, 0x3A, 0x7A, 0xBA, 0x86, 0x43, 0x74 } };

//
// The MNP protocol GUID (107A772C-D5E1-11D4-9A46-0090273FC14D)
// Used by the driver binding Start/Stop to install on children.
//
EFI_GUID gEfiManagedNetworkProtocolGuid =
  { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } };

//
// Hardcoded template MAC address for VLAN child handles (src_3 at 0xA9B0)
//
UINT8 gMnpVlanTemplateMac[6] = { 0x03, 0x14, 0x06, 0x00, 0x00, 0x00 };

//
// =====================================================================
// DRIVER BINDING PROTOCOL INSTANCE
// =====================================================================
//

EFI_DRIVER_BINDING_PROTOCOL gMnpDriverBinding = {
  MnpDriverBindingSupported,
  MnpDriverBindingStart,
  MnpDriverBindingStop,
  0x0A,                     /* Version = 10 */
  NULL,                     /* ImageHandle (set by entry point) */
  NULL                      /* DriverBindingHandle (set by entry point) */
};

//
// =====================================================================
// COMPONENT NAME 2 PROTOCOL INSTANCE
// =====================================================================
//

EFI_COMPONENT_NAME2_PROTOCOL gMnpComponentName2 = {
  MnpComponentNameGetDriverName,
  MnpComponentNameGetControllerName,
  L"eng"                    /* Supported Languages */
};

//
// =====================================================================
// COMPONENT NAME PROTOCOL INSTANCE (for backward compatibility)
// =====================================================================
//

EFI_COMPONENT_NAME_PROTOCOL gMnpComponentName = {
  MnpComponentNameGetDriverName,
  MnpComponentNameGetControllerName,
  L"eng;en"                 /* Supported Languages */
};

//
// =====================================================================
// INTERNAL FUNCTION PROTOTYPES
// =====================================================================
//

/**
 * Initialize global service table pointers and locate the DPC protocol.
 *
 * This is called early in the entry point to set up:
 *   gImageHandle         - The driver's image handle
 *   gSystemTable / gBS   - System table and boot services
 *   gRuntimeServices     - Runtime services table
 *   gDpcProtocol         - The DPC (Deferred Procedure Call) protocol interface
 *
 * @param[in] ImageHandle  The image handle for this driver.
 * @param[in] SystemTable  Pointer to the UEFI system table.
 */
VOID
MnpInitializeGlobals (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE    *SystemTable
  );

/**
 * Install all required protocols onto the driver's image handle:
 *   - EFI Driver Binding Protocol
 *   - EFI Component Name 2 Protocol
 *   - EFI Component Name Protocol
 *
 * Also reads the NetworkStackVar variable to determine initial VLAN config.
 *
 * @param[in] ImageHandle  The driver's image handle.
 *
 * @retval EFI_SUCCESS           Protocols installed successfully.
 * @retval EFI_OUT_OF_RESOURCES  Memory allocation failure.
 * @retval other                 Error from InstallMultipleProtocolInterfaces.
 */
EFI_STATUS
MnpInstallDriverProtocols (
  IN EFI_HANDLE  ImageHandle
  );

/**
 * DPC callback registered with the DPC protocol.
 *
 * When the DPC is queued, this function walks all handles in the system,
 * finds those with EFI_DRIVER_BINDING_PROTOCOL that match our image handle,
 * and performs cleanup (closes protocols, releases resources).
 *
 * @param[in] ImageHandle  The driver's image handle (passed as context).
 *
 * @retval EFI_SUCCESS  Cleanup completed.
 */
EFI_STATUS
EFIAPI
MnpDpcCallback (
  IN EFI_HANDLE  ImageHandle
  );

/**
 * Build a device path protocol instance containing a MAC address node
 * with the VLAN TCI appended.  Used to create distinguishable child
 * handles for each VLAN.
 *
 * @param[in] VlanConfig  VLAN_CONFIG_PROTOCOL instance (unused here).
 * @param[in] MacAddr     MAC address buffer (6 bytes).
 *
 * @return A newly allocated device path, or NULL on failure.
 */
EFI_DEVICE_PATH_PROTOCOL *
MnpCreateDevicePathWithMac (
  IN VLAN_CONFIG_PROTOCOL  *VlanConfig,
  IN UINT8                 *MacAddr
  );

/* ====================================================================== */
/*  _ModuleEntryPoint                                                      */
/* ====================================================================== */

/**
 * DXE driver entry point.
 *
 * 1. Initializes global service table pointers via MnpInitializeGlobals().
 * 2. Locates the Loaded Image Protocol for this image.
 * 3. Registers MnpDpcCallback as the DPC handler.
 * 4. Installs the Driver Binding and Component Name protocols via
 *    MnpInstallDriverProtocols().
 *
 * @param[in] ImageHandle  The image handle for this driver.
 * @param[in] SystemTable  Pointer to the UEFI system table.
 *
 * @retval EFI_SUCCESS           Driver initialized successfully.
 * @retval EFI_LOAD_ERROR        Could not locate required protocols.
 */
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE    *SystemTable
  )
{
  EFI_LOADED_IMAGE_PROTOCOL  *LoadedImage;
  EFI_STATUS                  Status;

  //
  // Step 1: Initialize global pointers.
  //
  MnpInitializeGlobals (ImageHandle, SystemTable);

  //
  // Step 2: Locate the Loaded Image Protocol for this image handle.
  //
  Status = gBootServices->OpenProtocol (
                            ImageHandle,
                            &gEfiLoadedImageProtocolGuid,
                            (VOID **)&LoadedImage,
                            ImageHandle,
                            NULL,
                            EFI_OPEN_PROTOCOL_GET_PROTOCOL
                            );

  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "MnpEntry: Failed to locate LoadedImageProtocol\n"));
    return EFI_LOAD_ERROR;
  }

  //
  // Step 3: Register the DPC handler.
  // The DPC protocol's callback is stored in LoadedImage->DeviceHandle
  // (offset +0x58 in the protocol structure) for later use by MnpReceive
  // and MnpCancel to queue deferred processing.
  //
  LoadedImage->DeviceHandle = (EFI_HANDLE)MnpDpcCallback;

  //
  // Step 4: Install driver binding and component name protocols.
  //
  Status = MnpInstallDriverProtocols (ImageHandle);

  return Status;
}

/* ====================================================================== */
/*  MnpInitializeGlobals                                                    */
/* ====================================================================== */

/**
 * Initialize global pointers used throughout the driver.
 *
 * @param[in] ImageHandle  The driver's image handle.
 * @param[in] SystemTable  Pointer to the UEFI system table.
 */
VOID
MnpInitializeGlobals (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE    *SystemTable
  )
{
  //
  // 1. Save image handle and system table.
  //
  gImageHandle  = ImageHandle;
  gSystemTable  = SystemTable;

  //
  // 2. Save copies of ImageHandle for various subsystems.
  //
  gImageHandle_0 = ImageHandle;
  gImageHandle_1 = ImageHandle;

  //
  // 3. Resolve Boot Services and Runtime Services.
  //
  gBootServices      = SystemTable->BootServices;
  gRuntimeServices   = SystemTable->RuntimeServices;

  //
  // 4. Validate pointers.
  //
  ASSERT (gImageHandle != NULL);
  ASSERT (gSystemTable != NULL);
  ASSERT (gBootServices != NULL);
  ASSERT (gRuntimeServices != NULL);

  //
  // 5. Locate the DPC protocol interface.
  //
  Status = gBootServices->LocateProtocol (
                            &gEfiDpcProtocolGuid,
                            NULL,
                            &gDpcProtocol
                            );

  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "MnpEntry: Failed to locate DPC protocol\n"));
    //
    // Non-fatal: MNP will still function but without DPC queuing.
    //
    gDpcProtocol = NULL;
  }
}

/* ====================================================================== */
/*  MnpInstallDriverProtocols                                               */
/* ====================================================================== */

/**
 * Install the Driver Binding Protocol, Component Name 2 Protocol,
 * and Component Name Protocol on the image handle.
 *
 * Before installation, reads the "NetworkStackVar" variable (optional)
 * to check whether the network stack is enabled.
 *
 * @param[in] ImageHandle  The driver's image handle.
 *
 * @retval EFI_SUCCESS           Protocols installed.
 * @retval EFI_UNSUPPORTED       Network stack disabled via variable.
 * @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
 */
EFI_STATUS
MnpInstallDriverProtocols (
  IN EFI_HANDLE  ImageHandle
  )
{
  EFI_STATUS  Status;
  UINT64      VariableSize;
  UINT8       VariableData[24];

  //
  // 1. Update the driver binding protocol with the image handle.
  //
  gMnpDriverBinding.ImageHandle          = ImageHandle;
  gMnpDriverBinding.DriverBindingHandle  = ImageHandle;

  //
  // 2. Read the NetworkStackVar variable (optional).
  //    This variable stores VLAN configuration.  If it does not exist,
  //    the network stack is still started (default VLAN ID 0).
  //
  VariableSize = sizeof (VariableData);
  Status = gRuntimeServices->GetVariable (
                               L"NetworkStackVar",
                               &gNetworkStackVarGuid,
                               NULL,
                               &VariableSize,
                               VariableData
                               );

  if (EFI_ERROR (Status)) {
    if (Status != EFI_NOT_FOUND) {
      //
      // Variable exists but could not be read; continue anyway.
      //
    }
  } else {
    //
    // Variable present; VLAN configurations will be processed later
    // by MnpDriverBindingStart when it reads the variable again.
    //
  }

  //
  // 3. Install Driver Binding, Component Name 2, and Component Name protocols.
  //
  Status = gBootServices->InstallMultipleProtocolInterfaces (
                            &ImageHandle,
                            &gEfiDriverBindingProtocolGuid,
                            &gMnpDriverBinding,
                            &gEfiComponentName2ProtocolGuid,
                            &gMnpComponentName2,
                            &gEfiComponentNameProtocolGuid,
                            &gMnpComponentName,
                            NULL
                            );

  return Status;
}

/* ====================================================================== */
/*  MnpDpcCallback                                                          */
/* ====================================================================== */

/**
 * DPC callback: Walk all handles, find those managed by this driver,
 * and disconnect/clean up protocols.
 *
 * This is invoked when the DPC protocol's QueueDpc is called (after
 * MnpReceive or MnpCancel operations complete).  It performs batch
 * cleanup by:
 *   1. Locating all handles in the system.
 *   2. Finding handles that have EFI_DRIVER_BINDING_PROTOCOL installed
 *      by this driver (ImageHandle match).
 *   3. Closing all managed protocols (SNP, MNP, ComponentName) on
 *      those handles.
 *
 * @param[in] Context  The driver's ImageHandle (passed from DPC queue).
 *
 * @retval EFI_SUCCESS  Walk completed successfully.
 */
EFI_STATUS
EFIAPI
MnpDpcCallback (
  IN VOID  *Context
  )
{
  EFI_HANDLE                *HandleBuffer;
  UINTN                      HandleCount;
  UINTN                      Index;
  UINTN                      SubIndex;
  EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
  VOID                       *ProtocolInterface;
  EFI_STATUS                  Status;

  //
  // 1. Get a buffer of all handles in the system.
  //
  HandleBuffer = NULL;
  HandleCount  = 0;
  Status = gBootServices->LocateHandleBuffer (
                            ByProtocol,
                            NULL,
                            NULL,
                            &HandleCount,
                            &HandleBuffer
                            );

  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // 2. For each handle, check if the Driver Binding Protocol is installed
  //    and if its ImageHandle matches the context.
  //
  for (Index = 0; Index < HandleCount; Index++) {
    Status = gBootServices->OpenProtocol (
                              HandleBuffer[Index],
                              &gEfiDriverBindingProtocolGuid,
                              (VOID **)&DriverBinding,
                              gImageHandle,
                              NULL,
                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
                              );

    if (EFI_ERROR (Status)) {
      continue;
    }

    if ((VOID *)DriverBinding->ImageHandle != Context) {
      continue;
    }

    //
    // 3. Close the SNP protocol (DriverBinding->DriverBindingHandle)
    //    on all handles.
    //
    for (SubIndex = 0; SubIndex < HandleCount; SubIndex++) {
      gBootServices->CloseProtocol (
                       HandleBuffer[SubIndex],
                       &gEfiSimpleNetworkProtocolGuid,
                       DriverBinding->DriverBindingHandle,
                       NULL
                       );
    }

    //
    // 4. Close the MNP protocol on the driver binding handle.
    //
    Status = gBootServices->OpenProtocol (
                              HandleBuffer[Index],
                              &gEfiManagedNetworkProtocolGuid,
                              &ProtocolInterface,
                              gImageHandle,
                              NULL,
                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
                              );

    if (!EFI_ERROR (Status)) {
      gBootServices->CloseProtocol (
                       HandleBuffer[Index],
                       &gEfiManagedNetworkProtocolGuid,
                       DriverBinding->DriverBindingHandle,
                       NULL
                       );
    }

    //
    // 5. Close the Component Name 2 protocol on the driver binding handle.
    //
    Status = gBootServices->OpenProtocol (
                              HandleBuffer[Index],
                              &gEfiComponentName2ProtocolGuid,
                              &ProtocolInterface,
                              gImageHandle,
                              NULL,
                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
                              );

    if (!EFI_ERROR (Status)) {
      gBootServices->CloseProtocol (
                       HandleBuffer[Index],
                       &gEfiComponentName2ProtocolGuid,
                       DriverBinding->DriverBindingHandle,
                       NULL
                       );
    }
  }

  //
  // 6. Free the handle buffer.
  //
  if (HandleBuffer != NULL) {
    gBootServices->FreePool (HandleBuffer);
  }

  return EFI_SUCCESS;
}