/**
* @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;
}