/** @file Initialization functions for EFI UNDI32 driver. Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Undi32.h" // // Global Variables // PXE_SW_UNDI *pxe_31 = NULL; // 3.1 entry UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES]; UNDI_CONFIG_TABLE *UndiDataPointer = NULL; // // UNDI Class Driver Global Variables // EFI_DRIVER_BINDING_PROTOCOL gUndiDriverBinding = { UndiDriverSupported, UndiDriverStart, UndiDriverStop, 0xa, NULL, NULL }; /** When address mapping changes to virtual this should make the appropriate address conversions. (Standard Event handler) @return None **/ VOID EFIAPI UndiNotifyVirtual ( EFI_EVENT Event, VOID *Context ) { UINT16 Index; VOID *Pxe31Pointer; if (pxe_31 != NULL) { Pxe31Pointer = (VOID *) pxe_31; EfiConvertPointer ( EFI_OPTIONAL_PTR, (VOID **) &Pxe31Pointer ); // // UNDI32DeviceList is an array of pointers // for (Index = 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Index++) { UNDI32DeviceList[Index]->NIIProtocol_31.Id = (UINT64) (UINTN) Pxe31Pointer; EfiConvertPointer ( EFI_OPTIONAL_PTR, (VOID **) &(UNDI32DeviceList[Index]) ); } EfiConvertPointer ( EFI_OPTIONAL_PTR, (VOID **) &(pxe_31->EntryPoint) ); pxe_31 = Pxe31Pointer; } for (Index = 0; Index <= PXE_OPCODE_LAST_VALID; Index++) { EfiConvertPointer ( EFI_OPTIONAL_PTR, (VOID **) &api_table[Index].api_ptr ); } } /** When EFI is shuting down the boot services, we need to install a configuration table for UNDI to work at runtime! (Standard Event handler) @return None **/ VOID EFIAPI UndiNotifyReadyToBoot ( EFI_EVENT Event, VOID *Context ) { InstallConfigTable (); } /** Test to see if this driver supports ControllerHandle. Any ControllerHandle than contains a DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086, and DeviceId of (D100_DEVICE_ID || D102_DEVICE_ID || ICH3_DEVICE_ID_1 || ICH3_DEVICE_ID_2 || ICH3_DEVICE_ID_3 || ICH3_DEVICE_ID_4 || ICH3_DEVICE_ID_5 || ICH3_DEVICE_ID_6 || ICH3_DEVICE_ID_7 || ICH3_DEVICE_ID_8) can be supported. @param This Protocol instance pointer. @param Controller Handle of device to test. @param RemainingDevicePath Not used. @retval EFI_SUCCESS This driver supports this device. @retval other This driver does not support this device. **/ EFI_STATUS EFIAPI UndiDriverSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; EFI_PCI_IO_PROTOCOL *PciIo; PCI_TYPE00 Pci; Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, NULL, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_TEST_PROTOCOL ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &PciIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { return Status; } Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint8, 0, sizeof (PCI_CONFIG_HEADER), &Pci ); if (!EFI_ERROR (Status)) { Status = EFI_UNSUPPORTED; if (Pci.Hdr.ClassCode[2] == 0x02 && Pci.Hdr.VendorId == PCI_VENDOR_ID_INTEL) { switch (Pci.Hdr.DeviceId) { case D100_DEVICE_ID: case D102_DEVICE_ID: case ICH3_DEVICE_ID_1: case ICH3_DEVICE_ID_2: case ICH3_DEVICE_ID_3: case ICH3_DEVICE_ID_4: case ICH3_DEVICE_ID_5: case ICH3_DEVICE_ID_6: case ICH3_DEVICE_ID_7: case ICH3_DEVICE_ID_8: case 0x1039: case 0x103A: case 0x103B: case 0x103C: case 0x103D: case 0x103E: case 0x1050: case 0x1051: case 0x1052: case 0x1053: case 0x1054: case 0x1055: case 0x1056: case 0x1057: case 0x1059: case 0x1064: Status = EFI_SUCCESS; } } } gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Controller ); return Status; } /** Start this driver on Controller by opening PciIo and DevicePath protocol. Initialize PXE structures, create a copy of the Controller Device Path with the NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol on the newly created Device Path. @param This Protocol instance pointer. @param Controller Handle of device to work with. @param RemainingDevicePath Not used, always produce all possible children. @retval EFI_SUCCESS This driver is added to Controller. @retval other This driver does not support this device. **/ EFI_STATUS EFIAPI UndiDriverStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath; PCI_CONFIG_HEADER *CfgHdr; UNDI32_DEV *UNDI32Device; UINT16 NewCommand; UINT8 *TmpPxePointer; EFI_PCI_IO_PROTOCOL *PciIoFncs; UINTN Len; UINT64 Supports; BOOLEAN PciAttributesSaved; Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &PciIoFncs, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, (VOID **) &UndiDevicePath, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Controller ); return Status; } PciAttributesSaved = FALSE; Status = gBS->AllocatePool ( EfiRuntimeServicesData, sizeof (UNDI32_DEV), (VOID **) &UNDI32Device ); if (EFI_ERROR (Status)) { goto UndiError; } ZeroMem ((CHAR8 *) UNDI32Device, sizeof (UNDI32_DEV)); // // Get original PCI attributes // Status = PciIoFncs->Attributes ( PciIoFncs, EfiPciIoAttributeOperationGet, 0, &UNDI32Device->NicInfo.OriginalPciAttributes ); if (EFI_ERROR (Status)) { goto UndiErrorDeleteDevice; } PciAttributesSaved = TRUE; // // allocate and initialize both (old and new) the !pxe structures here, // there should only be one copy of each of these structure for any number // of NICs this undi supports. Also, these structures need to be on a // paragraph boundary as per the spec. so, while allocating space for these, // make sure that there is space for 2 !pxe structures (old and new) and a // 32 bytes padding for alignment adjustment (in case) // TmpPxePointer = NULL; if (pxe_31 == NULL) { Status = gBS->AllocatePool ( EfiRuntimeServicesData, (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32), (VOID **) &TmpPxePointer ); if (EFI_ERROR (Status)) { goto UndiErrorDeleteDevice; } ZeroMem ( TmpPxePointer, sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32 ); // // check for paragraph alignment here, assuming that the pointer is // already 8 byte aligned. // if (((UINTN) TmpPxePointer & 0x0F) != 0) { pxe_31 = (PXE_SW_UNDI *) ((UINTN) (TmpPxePointer + 8)); } else { pxe_31 = (PXE_SW_UNDI *) TmpPxePointer; } PxeStructInit (pxe_31); } UNDI32Device->NIIProtocol_31.Id = (UINT64) (UINTN) (pxe_31); Status = PciIoFncs->Attributes ( PciIoFncs, EfiPciIoAttributeOperationSupported, 0, &Supports ); if (!EFI_ERROR (Status)) { Supports &= EFI_PCI_DEVICE_ENABLE; Status = PciIoFncs->Attributes ( PciIoFncs, EfiPciIoAttributeOperationEnable, Supports, NULL ); } // // Read all the registers from device's PCI Configuration space // Status = PciIoFncs->Pci.Read ( PciIoFncs, EfiPciIoWidthUint32, 0, MAX_PCI_CONFIG_LEN, &UNDI32Device->NicInfo.Config ); CfgHdr = (PCI_CONFIG_HEADER *) &(UNDI32Device->NicInfo.Config[0]); // // make sure that this device is a PCI bus master // NewCommand = (UINT16) (CfgHdr->Command | PCI_COMMAND_MASTER | PCI_COMMAND_IO); if (CfgHdr->Command != NewCommand) { PciIoFncs->Pci.Write ( PciIoFncs, EfiPciIoWidthUint16, PCI_COMMAND, 1, &NewCommand ); CfgHdr->Command = NewCommand; } // // make sure that the latency timer is at least 32 // if (CfgHdr->LatencyTimer < 32) { CfgHdr->LatencyTimer = 32; PciIoFncs->Pci.Write ( PciIoFncs, EfiPciIoWidthUint8, PCI_LATENCY_TIMER, 1, &CfgHdr->LatencyTimer ); } // // the IfNum index for the current interface will be the total number // of interfaces initialized so far // UNDI32Device->NIIProtocol_31.IfNum = pxe_31->IFcnt | pxe_31->IFcntExt << 8; PxeUpdate (&UNDI32Device->NicInfo, pxe_31); UNDI32Device->NicInfo.Io_Function = PciIoFncs; UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = UNDI32Device; UNDI32Device->Undi32BaseDevPath = UndiDevicePath; Status = AppendMac2DevPath ( &UNDI32Device->Undi32DevPath, UNDI32Device->Undi32BaseDevPath, &UNDI32Device->NicInfo ); if (Status != 0) { goto UndiErrorDeletePxe; } UNDI32Device->Signature = UNDI_DEV_SIGNATURE; UNDI32Device->NIIProtocol_31.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31; UNDI32Device->NIIProtocol_31.Type = EfiNetworkInterfaceUndi; UNDI32Device->NIIProtocol_31.MajorVer = PXE_ROMID_MAJORVER; UNDI32Device->NIIProtocol_31.MinorVer = PXE_ROMID_MINORVER_31; UNDI32Device->NIIProtocol_31.ImageSize = 0; UNDI32Device->NIIProtocol_31.ImageAddr = 0; UNDI32Device->NIIProtocol_31.Ipv6Supported = TRUE; UNDI32Device->NIIProtocol_31.StringId[0] = 'U'; UNDI32Device->NIIProtocol_31.StringId[1] = 'N'; UNDI32Device->NIIProtocol_31.StringId[2] = 'D'; UNDI32Device->NIIProtocol_31.StringId[3] = 'I'; UNDI32Device->DeviceHandle = NULL; UNDI32Device->Aip.GetInformation = UndiAipGetInfo; UNDI32Device->Aip.SetInformation = UndiAipSetInfo; UNDI32Device->Aip.GetSupportedTypes = UndiAipGetSupportedTypes; // // install both the 3.0 and 3.1 NII protocols. // Status = gBS->InstallMultipleProtocolInterfaces ( &UNDI32Device->DeviceHandle, &gEfiNetworkInterfaceIdentifierProtocolGuid_31, &UNDI32Device->NIIProtocol_31, &gEfiDevicePathProtocolGuid, UNDI32Device->Undi32DevPath, &gEfiAdapterInformationProtocolGuid, &UNDI32Device->Aip, NULL ); if (EFI_ERROR (Status)) { goto UndiErrorDeleteDevicePath; } // // if the table exists, free it and alloc again, or alloc it directly // if (UndiDataPointer != NULL) { Status = gBS->FreePool(UndiDataPointer); } if (EFI_ERROR (Status)) { goto UndiErrorDeleteDevicePath; } Len = ((pxe_31->IFcnt|pxe_31->IFcntExt << 8)* sizeof (UndiDataPointer->NII_entry)) + sizeof (UndiDataPointer); Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UndiDataPointer); if (EFI_ERROR (Status)) { goto UndiErrorAllocDataPointer; } // // Open For Child Device // Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &PciIoFncs, This->DriverBindingHandle, UNDI32Device->DeviceHandle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); return EFI_SUCCESS; UndiErrorAllocDataPointer: gBS->UninstallMultipleProtocolInterfaces ( &UNDI32Device->DeviceHandle, &gEfiNetworkInterfaceIdentifierProtocolGuid_31, &UNDI32Device->NIIProtocol_31, &gEfiDevicePathProtocolGuid, UNDI32Device->Undi32DevPath, &gEfiAdapterInformationProtocolGuid, &UNDI32Device->Aip, NULL ); UndiErrorDeleteDevicePath: UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = NULL; gBS->FreePool (UNDI32Device->Undi32DevPath); UndiErrorDeletePxe: PxeUpdate (NULL, pxe_31); if (TmpPxePointer != NULL) { gBS->FreePool (TmpPxePointer); } UndiErrorDeleteDevice: if (PciAttributesSaved) { // // Restore original PCI attributes // PciIoFncs->Attributes ( PciIoFncs, EfiPciIoAttributeOperationSet, UNDI32Device->NicInfo.OriginalPciAttributes, NULL ); } gBS->FreePool (UNDI32Device); UndiError: gBS->CloseProtocol ( Controller, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, Controller ); gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Controller ); return Status; } /** Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and closing the DevicePath and PciIo protocols on Controller. @param This Protocol instance pointer. @param Controller Handle of device to stop driver on. @param NumberOfChildren How many children need to be stopped. @param ChildHandleBuffer Not used. @retval EFI_SUCCESS This driver is removed Controller. @retval other This driver was not removed from this device. **/ // TODO: EFI_DEVICE_ERROR - add return value to function comment EFI_STATUS EFIAPI UndiDriverStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; BOOLEAN AllChildrenStopped; UINTN Index; UNDI32_DEV *UNDI32Device; EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol; // // Complete all outstanding transactions to Controller. // Don't allow any new transaction to Controller to be started. // if (NumberOfChildren == 0) { // // Close the bus driver // Status = gBS->CloseProtocol ( Controller, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, Controller ); Status = gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Controller ); return Status; } AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index++) { Status = gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiNetworkInterfaceIdentifierProtocolGuid_31, (VOID **) &NIIProtocol, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (!EFI_ERROR (Status)) { UNDI32Device = UNDI_DEV_FROM_THIS (NIIProtocol); Status = gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, ChildHandleBuffer[Index] ); if (!EFI_ERROR (Status)) { Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, UNDI32Device->Undi32DevPath, &gEfiNetworkInterfaceIdentifierProtocolGuid_31, &UNDI32Device->NIIProtocol_31, NULL ); if (!EFI_ERROR (Status)) { // // Restore original PCI attributes // Status = UNDI32Device->NicInfo.Io_Function->Attributes ( UNDI32Device->NicInfo.Io_Function, EfiPciIoAttributeOperationSet, UNDI32Device->NicInfo.OriginalPciAttributes, NULL ); ASSERT_EFI_ERROR (Status); gBS->FreePool (UNDI32Device->Undi32DevPath); gBS->FreePool (UNDI32Device); } } } if (EFI_ERROR (Status)) { AllChildrenStopped = FALSE; } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Use the EFI boot services to produce a pause. This is also the routine which gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can do it's own pause. @param UnqId Runtime O/S routine might use this, this temp routine does not use it @param MicroSeconds Determines the length of pause. @return none **/ VOID TmpDelay ( IN UINT64 UnqId, IN UINTN MicroSeconds ) { gBS->Stall ((UINT32) MicroSeconds); } /** Use the PCI IO abstraction to issue memory or I/O reads and writes. This is also the routine which gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can do it's own I/O abstractions. @param UnqId Runtime O/S routine may use this field, this temp routine does not. @param ReadWrite Determine if it is an I/O or Memory Read/Write Operation. @param Len Determines the width of the data operation. @param Port What port to Read/Write from. @param BuffAddr Address to read to or write from. @return none **/ VOID TmpMemIo ( IN UINT64 UnqId, IN UINT8 ReadWrite, IN UINT8 Len, IN UINT64 Port, IN UINT64 BuffAddr ) { EFI_PCI_IO_PROTOCOL_WIDTH Width; NIC_DATA_INSTANCE *AdapterInfo; Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0; AdapterInfo = (NIC_DATA_INSTANCE *) (UINTN) UnqId; switch (Len) { case 2: Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1; break; case 4: Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2; break; case 8: Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3; break; } switch (ReadWrite) { case PXE_IO_READ: AdapterInfo->Io_Function->Io.Read ( AdapterInfo->Io_Function, Width, 1, Port, 1, (VOID *) (UINTN) (BuffAddr) ); break; case PXE_IO_WRITE: AdapterInfo->Io_Function->Io.Write ( AdapterInfo->Io_Function, Width, 1, Port, 1, (VOID *) (UINTN) (BuffAddr) ); break; case PXE_MEM_READ: AdapterInfo->Io_Function->Mem.Read ( AdapterInfo->Io_Function, Width, 0, Port, 1, (VOID *) (UINTN) (BuffAddr) ); break; case PXE_MEM_WRITE: AdapterInfo->Io_Function->Mem.Write ( AdapterInfo->Io_Function, Width, 0, Port, 1, (VOID *) (UINTN) (BuffAddr) ); break; } return ; } /** Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr) and an added MAC node. @param DevPtr Pointer which will point to the newly created device path with the MAC node attached. @param BaseDevPtr Pointer to the device path which the UNDI device driver is latching on to. @param AdapterInfo Pointer to the NIC data structure information which the UNDI driver is layering on.. @retval EFI_SUCCESS A MAC address was successfully appended to the Base Device Path. @retval other Not enough resources available to create new Device Path node. **/ EFI_STATUS AppendMac2DevPath ( IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr, IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr, IN NIC_DATA_INSTANCE *AdapterInfo ) { EFI_MAC_ADDRESS MACAddress; PCI_CONFIG_HEADER *CfgHdr; INT32 Val; INT32 Index; INT32 Index2; UINT8 AddrLen; MAC_ADDR_DEVICE_PATH MacAddrNode; EFI_DEVICE_PATH_PROTOCOL *EndNode; UINT8 *DevicePtr; UINT16 TotalPathLen; UINT16 BasePathLen; EFI_STATUS Status; // // set the environment ready (similar to UNDI_Start call) so that we can // execute the other UNDI_ calls to get the mac address // we are using undi 3.1 style // AdapterInfo->Delay = TmpDelay; AdapterInfo->Virt2Phys = (VOID *) 0; AdapterInfo->Block = (VOID *) 0; AdapterInfo->Map_Mem = (VOID *) 0; AdapterInfo->UnMap_Mem = (VOID *) 0; AdapterInfo->Sync_Mem = (VOID *) 0; AdapterInfo->Mem_Io = TmpMemIo; // // these tmp call-backs follow 3.1 undi style // i.e. they have the unique_id parameter. // AdapterInfo->VersionFlag = 0x31; AdapterInfo->Unique_ID = (UINT64) (UINTN) AdapterInfo; // // undi init portion // CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]); AdapterInfo->ioaddr = 0; AdapterInfo->RevID = CfgHdr->RevID; AddrLen = E100bGetEepromAddrLen (AdapterInfo); for (Index = 0, Index2 = 0; Index < 3; Index++) { Val = E100bReadEeprom (AdapterInfo, Index, AddrLen); MACAddress.Addr[Index2++] = (UINT8) Val; MACAddress.Addr[Index2++] = (UINT8) (Val >> 8); } SetMem (MACAddress.Addr + Index2, sizeof (EFI_MAC_ADDRESS) - Index2, 0); //for (; Index2 < sizeof (EFI_MAC_ADDRESS); Index2++) { // MACAddress.Addr[Index2] = 0; //} // // stop undi // AdapterInfo->Delay = (VOID *) 0; AdapterInfo->Mem_Io = (VOID *) 0; // // fill the mac address node first // ZeroMem ((CHAR8 *) &MacAddrNode, sizeof MacAddrNode); CopyMem ( (CHAR8 *) &MacAddrNode.MacAddress, (CHAR8 *) &MACAddress, sizeof (EFI_MAC_ADDRESS) ); MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH; MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP; MacAddrNode.Header.Length[0] = (UINT8) sizeof (MacAddrNode); MacAddrNode.Header.Length[1] = 0; // // find the size of the base dev path. // EndNode = BaseDevPtr; while (!IsDevicePathEnd (EndNode)) { EndNode = NextDevicePathNode (EndNode); } BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr)); // // create space for full dev path // TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL)); Status = gBS->AllocatePool ( EfiRuntimeServicesData, TotalPathLen, (VOID **) &DevicePtr ); if (Status != EFI_SUCCESS) { return Status; } // // copy the base path, mac addr and end_dev_path nodes // *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr; CopyMem (DevicePtr, (CHAR8 *) BaseDevPtr, BasePathLen); DevicePtr += BasePathLen; CopyMem (DevicePtr, (CHAR8 *) &MacAddrNode, sizeof (MacAddrNode)); DevicePtr += sizeof (MacAddrNode); CopyMem (DevicePtr, (CHAR8 *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL)); return EFI_SUCCESS; } /** Install a GUID/Pointer pair into the system's configuration table. none @retval EFI_SUCCESS Install a GUID/Pointer pair into the system's configuration table. @retval other Did not successfully install the GUID/Pointer pair into the configuration table. **/ // TODO: VOID - add argument and description to function comment EFI_STATUS InstallConfigTable ( IN VOID ) { EFI_STATUS Status; EFI_CONFIGURATION_TABLE *CfgPtr; UNDI_CONFIG_TABLE *TmpData; UINT16 Index; UNDI_CONFIG_TABLE *UndiData; if (pxe_31 == NULL) { return EFI_SUCCESS; } if(UndiDataPointer == NULL) { return EFI_SUCCESS; } UndiData = (UNDI_CONFIG_TABLE *)UndiDataPointer; UndiData->NumberOfInterfaces = (pxe_31->IFcnt | pxe_31->IFcntExt << 8); UndiData->nextlink = NULL; for (Index = 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Index++) { UndiData->NII_entry[Index].NII_InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31; UndiData->NII_entry[Index].DevicePathPointer = UNDI32DeviceList[Index]->Undi32DevPath; } // // see if there is an entry in the config table already // CfgPtr = gST->ConfigurationTable; for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { Status = CompareGuid ( &CfgPtr->VendorGuid, &gEfiNetworkInterfaceIdentifierProtocolGuid_31 ); if (Status != EFI_SUCCESS) { break; } CfgPtr++; } if (Index < gST->NumberOfTableEntries) { TmpData = (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable; // // go to the last link // while (TmpData->nextlink != NULL) { TmpData = TmpData->nextlink; } TmpData->nextlink = UndiData; // // 1st one in chain // UndiData = (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable; } // // create an entry in the configuration table for our GUID // Status = gBS->InstallConfigurationTable ( &gEfiNetworkInterfaceIdentifierProtocolGuid_31, UndiData ); return Status; } /** **/ EFI_STATUS EFIAPI InitializeUndi( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_EVENT Event; EFI_STATUS Status; Status = EfiLibInstallDriverBindingComponentName2 ( ImageHandle, SystemTable, &gUndiDriverBinding, ImageHandle, &gUndiComponentName, &gUndiComponentName2 ); ASSERT_EFI_ERROR (Status); Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, UndiNotifyReadyToBoot, NULL, &gEfiEventReadyToBootGuid, &Event ); ASSERT_EFI_ERROR (Status); Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, UndiNotifyVirtual, NULL, &gEfiEventVirtualAddressChangeGuid, &Event ); ASSERT_EFI_ERROR (Status); return Status; }