Home | History | Annotate | Download | only in UndiRuntimeDxe
      1 /** @file
      2   Initialization functions for EFI UNDI32 driver.
      3 
      4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Undi32.h"
     16 //
     17 // Global Variables
     18 //
     19 
     20 PXE_SW_UNDI             *pxe_31 = NULL;  // 3.1 entry
     21 UNDI32_DEV              *UNDI32DeviceList[MAX_NIC_INTERFACES];
     22 UNDI_CONFIG_TABLE       *UndiDataPointer = NULL;
     23 
     24 //
     25 // UNDI Class Driver Global Variables
     26 //
     27 EFI_DRIVER_BINDING_PROTOCOL  gUndiDriverBinding = {
     28   UndiDriverSupported,
     29   UndiDriverStart,
     30   UndiDriverStop,
     31   0xa,
     32   NULL,
     33   NULL
     34 };
     35 
     36 
     37 /**
     38   When address mapping changes to virtual this should make the appropriate
     39   address conversions.
     40 
     41   (Standard Event handler)
     42 
     43   @return None
     44 
     45 **/
     46 VOID
     47 EFIAPI
     48 UndiNotifyVirtual (
     49   EFI_EVENT Event,
     50   VOID      *Context
     51   )
     52 {
     53   UINT16  Index;
     54   VOID    *Pxe31Pointer;
     55 
     56   if (pxe_31 != NULL) {
     57     Pxe31Pointer = (VOID *) pxe_31;
     58 
     59     EfiConvertPointer (
     60       EFI_OPTIONAL_PTR,
     61       (VOID **) &Pxe31Pointer
     62       );
     63 
     64     //
     65     // UNDI32DeviceList is an array of pointers
     66     //
     67     for (Index = 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Index++) {
     68       UNDI32DeviceList[Index]->NIIProtocol_31.Id = (UINT64) (UINTN) Pxe31Pointer;
     69       EfiConvertPointer (
     70         EFI_OPTIONAL_PTR,
     71         (VOID **) &(UNDI32DeviceList[Index])
     72         );
     73     }
     74 
     75     EfiConvertPointer (
     76       EFI_OPTIONAL_PTR,
     77       (VOID **) &(pxe_31->EntryPoint)
     78       );
     79     pxe_31 = Pxe31Pointer;
     80   }
     81 
     82   for (Index = 0; Index <= PXE_OPCODE_LAST_VALID; Index++) {
     83     EfiConvertPointer (
     84       EFI_OPTIONAL_PTR,
     85       (VOID **) &api_table[Index].api_ptr
     86       );
     87   }
     88 }
     89 
     90 
     91 /**
     92   When EFI is shuting down the boot services, we need to install a
     93   configuration table for UNDI to work at runtime!
     94 
     95   (Standard Event handler)
     96 
     97   @return None
     98 
     99 **/
    100 VOID
    101 EFIAPI
    102 UndiNotifyReadyToBoot (
    103   EFI_EVENT Event,
    104   VOID      *Context
    105   )
    106 {
    107   InstallConfigTable ();
    108 }
    109 
    110 
    111 /**
    112   Test to see if this driver supports ControllerHandle. Any ControllerHandle
    113   than contains a  DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086,
    114   and DeviceId of (D100_DEVICE_ID || D102_DEVICE_ID || ICH3_DEVICE_ID_1 ||
    115   ICH3_DEVICE_ID_2 || ICH3_DEVICE_ID_3 || ICH3_DEVICE_ID_4 || ICH3_DEVICE_ID_5 ||
    116   ICH3_DEVICE_ID_6 || ICH3_DEVICE_ID_7 || ICH3_DEVICE_ID_8) can be supported.
    117 
    118   @param  This                 Protocol instance pointer.
    119   @param  Controller           Handle of device to test.
    120   @param  RemainingDevicePath  Not used.
    121 
    122   @retval EFI_SUCCESS          This driver supports this device.
    123   @retval other                This driver does not support this device.
    124 
    125 **/
    126 EFI_STATUS
    127 EFIAPI
    128 UndiDriverSupported (
    129   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    130   IN EFI_HANDLE                     Controller,
    131   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    132   )
    133 {
    134   EFI_STATUS          Status;
    135   EFI_PCI_IO_PROTOCOL *PciIo;
    136   PCI_TYPE00          Pci;
    137 
    138   Status = gBS->OpenProtocol (
    139                   Controller,
    140                   &gEfiDevicePathProtocolGuid,
    141                   NULL,
    142                   This->DriverBindingHandle,
    143                   Controller,
    144                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    145                   );
    146   if (EFI_ERROR (Status)) {
    147     return Status;
    148   }
    149 
    150   Status = gBS->OpenProtocol (
    151                   Controller,
    152                   &gEfiPciIoProtocolGuid,
    153                   (VOID **) &PciIo,
    154                   This->DriverBindingHandle,
    155                   Controller,
    156                   EFI_OPEN_PROTOCOL_BY_DRIVER
    157                   );
    158   if (EFI_ERROR (Status)) {
    159     return Status;
    160   }
    161 
    162   Status = PciIo->Pci.Read (
    163                         PciIo,
    164                         EfiPciIoWidthUint8,
    165                         0,
    166                         sizeof (PCI_CONFIG_HEADER),
    167                         &Pci
    168                         );
    169 
    170   if (!EFI_ERROR (Status)) {
    171     Status = EFI_UNSUPPORTED;
    172 
    173     if (Pci.Hdr.ClassCode[2] == 0x02 && Pci.Hdr.VendorId == PCI_VENDOR_ID_INTEL) {
    174       switch (Pci.Hdr.DeviceId) {
    175       case D100_DEVICE_ID:
    176       case D102_DEVICE_ID:
    177       case ICH3_DEVICE_ID_1:
    178       case ICH3_DEVICE_ID_2:
    179       case ICH3_DEVICE_ID_3:
    180       case ICH3_DEVICE_ID_4:
    181       case ICH3_DEVICE_ID_5:
    182       case ICH3_DEVICE_ID_6:
    183       case ICH3_DEVICE_ID_7:
    184       case ICH3_DEVICE_ID_8:
    185       case 0x1039:
    186       case 0x103A:
    187       case 0x103B:
    188       case 0x103C:
    189       case 0x103D:
    190       case 0x103E:
    191       case 0x1050:
    192       case 0x1051:
    193       case 0x1052:
    194       case 0x1053:
    195       case 0x1054:
    196       case 0x1055:
    197       case 0x1056:
    198       case 0x1057:
    199       case 0x1059:
    200       case 0x1064:
    201         Status = EFI_SUCCESS;
    202       }
    203     }
    204   }
    205 
    206   gBS->CloseProtocol (
    207         Controller,
    208         &gEfiPciIoProtocolGuid,
    209         This->DriverBindingHandle,
    210         Controller
    211         );
    212 
    213   return Status;
    214 }
    215 
    216 
    217 /**
    218   Start this driver on Controller by opening PciIo and DevicePath protocol.
    219   Initialize PXE structures, create a copy of the Controller Device Path with the
    220   NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol
    221   on the newly created Device Path.
    222 
    223   @param  This                 Protocol instance pointer.
    224   @param  Controller           Handle of device to work with.
    225   @param  RemainingDevicePath  Not used, always produce all possible children.
    226 
    227   @retval EFI_SUCCESS          This driver is added to Controller.
    228   @retval other                This driver does not support this device.
    229 
    230 **/
    231 EFI_STATUS
    232 EFIAPI
    233 UndiDriverStart (
    234   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    235   IN EFI_HANDLE                     Controller,
    236   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    237   )
    238 {
    239   EFI_STATUS                Status;
    240   EFI_DEVICE_PATH_PROTOCOL  *UndiDevicePath;
    241   PCI_CONFIG_HEADER         *CfgHdr;
    242   UNDI32_DEV                *UNDI32Device;
    243   UINT16                    NewCommand;
    244   UINT8                     *TmpPxePointer;
    245   EFI_PCI_IO_PROTOCOL       *PciIoFncs;
    246   UINTN                     Len;
    247   UINT64                    Supports;
    248   BOOLEAN                   PciAttributesSaved;
    249 
    250   Status = gBS->OpenProtocol (
    251                   Controller,
    252                   &gEfiPciIoProtocolGuid,
    253                   (VOID **) &PciIoFncs,
    254                   This->DriverBindingHandle,
    255                   Controller,
    256                   EFI_OPEN_PROTOCOL_BY_DRIVER
    257                   );
    258 
    259   if (EFI_ERROR (Status)) {
    260     return Status;
    261   }
    262 
    263   Status = gBS->OpenProtocol (
    264                   Controller,
    265                   &gEfiDevicePathProtocolGuid,
    266                   (VOID **) &UndiDevicePath,
    267                   This->DriverBindingHandle,
    268                   Controller,
    269                   EFI_OPEN_PROTOCOL_BY_DRIVER
    270                   );
    271 
    272   if (EFI_ERROR (Status)) {
    273     gBS->CloseProtocol (
    274           Controller,
    275           &gEfiPciIoProtocolGuid,
    276           This->DriverBindingHandle,
    277           Controller
    278           );
    279 
    280     return Status;
    281   }
    282 
    283   PciAttributesSaved = FALSE;
    284 
    285   Status = gBS->AllocatePool (
    286                   EfiRuntimeServicesData,
    287                   sizeof (UNDI32_DEV),
    288                   (VOID **) &UNDI32Device
    289                   );
    290 
    291   if (EFI_ERROR (Status)) {
    292     goto UndiError;
    293   }
    294 
    295   ZeroMem ((CHAR8 *) UNDI32Device, sizeof (UNDI32_DEV));
    296 
    297   //
    298   // Get original PCI attributes
    299   //
    300   Status = PciIoFncs->Attributes (
    301                     PciIoFncs,
    302                     EfiPciIoAttributeOperationGet,
    303                     0,
    304                     &UNDI32Device->NicInfo.OriginalPciAttributes
    305                     );
    306 
    307   if (EFI_ERROR (Status)) {
    308     goto UndiErrorDeleteDevice;
    309   }
    310   PciAttributesSaved = TRUE;
    311 
    312   //
    313   // allocate and initialize both (old and new) the !pxe structures here,
    314   // there should only be one copy of each of these structure for any number
    315   // of NICs this undi supports. Also, these structures need to be on a
    316   // paragraph boundary as per the spec. so, while allocating space for these,
    317   // make sure that there is space for 2 !pxe structures (old and new) and a
    318   // 32 bytes padding for alignment adjustment (in case)
    319   //
    320   TmpPxePointer = NULL;
    321   if (pxe_31 == NULL) {
    322     Status = gBS->AllocatePool (
    323                     EfiRuntimeServicesData,
    324                     (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32),
    325                     (VOID **) &TmpPxePointer
    326                     );
    327 
    328     if (EFI_ERROR (Status)) {
    329       goto UndiErrorDeleteDevice;
    330     }
    331 
    332     ZeroMem (
    333       TmpPxePointer,
    334       sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32
    335       );
    336     //
    337     // check for paragraph alignment here, assuming that the pointer is
    338     // already 8 byte aligned.
    339     //
    340     if (((UINTN) TmpPxePointer & 0x0F) != 0) {
    341       pxe_31 = (PXE_SW_UNDI *) ((UINTN) (TmpPxePointer + 8));
    342     } else {
    343       pxe_31 = (PXE_SW_UNDI *) TmpPxePointer;
    344     }
    345 
    346     PxeStructInit (pxe_31);
    347   }
    348 
    349   UNDI32Device->NIIProtocol_31.Id = (UINT64) (UINTN) (pxe_31);
    350 
    351   Status = PciIoFncs->Attributes (
    352                         PciIoFncs,
    353                         EfiPciIoAttributeOperationSupported,
    354                         0,
    355                         &Supports
    356                         );
    357   if (!EFI_ERROR (Status)) {
    358     Supports &= EFI_PCI_DEVICE_ENABLE;
    359     Status = PciIoFncs->Attributes (
    360                           PciIoFncs,
    361                           EfiPciIoAttributeOperationEnable,
    362                           Supports,
    363                           NULL
    364                           );
    365   }
    366   //
    367   // Read all the registers from device's PCI Configuration space
    368   //
    369   Status = PciIoFncs->Pci.Read (
    370                             PciIoFncs,
    371                             EfiPciIoWidthUint32,
    372                             0,
    373                             MAX_PCI_CONFIG_LEN,
    374                             &UNDI32Device->NicInfo.Config
    375                             );
    376 
    377   CfgHdr = (PCI_CONFIG_HEADER *) &(UNDI32Device->NicInfo.Config[0]);
    378 
    379   //
    380   // make sure that this device is a PCI bus master
    381   //
    382 
    383   NewCommand = (UINT16) (CfgHdr->Command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
    384   if (CfgHdr->Command != NewCommand) {
    385     PciIoFncs->Pci.Write (
    386                     PciIoFncs,
    387                     EfiPciIoWidthUint16,
    388                     PCI_COMMAND,
    389                     1,
    390                     &NewCommand
    391                     );
    392     CfgHdr->Command = NewCommand;
    393   }
    394 
    395   //
    396   // make sure that the latency timer is at least 32
    397   //
    398   if (CfgHdr->LatencyTimer < 32) {
    399     CfgHdr->LatencyTimer = 32;
    400     PciIoFncs->Pci.Write (
    401                     PciIoFncs,
    402                     EfiPciIoWidthUint8,
    403                     PCI_LATENCY_TIMER,
    404                     1,
    405                     &CfgHdr->LatencyTimer
    406                     );
    407   }
    408   //
    409   // the IfNum index for the current interface will be the total number
    410   // of interfaces initialized so far
    411   //
    412   UNDI32Device->NIIProtocol_31.IfNum  = pxe_31->IFcnt | pxe_31->IFcntExt << 8;
    413 
    414   PxeUpdate (&UNDI32Device->NicInfo, pxe_31);
    415 
    416   UNDI32Device->NicInfo.Io_Function                    = PciIoFncs;
    417   UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = UNDI32Device;
    418   UNDI32Device->Undi32BaseDevPath                      = UndiDevicePath;
    419 
    420   Status = AppendMac2DevPath (
    421             &UNDI32Device->Undi32DevPath,
    422             UNDI32Device->Undi32BaseDevPath,
    423             &UNDI32Device->NicInfo
    424             );
    425 
    426   if (Status != 0) {
    427     goto UndiErrorDeletePxe;
    428   }
    429 
    430   UNDI32Device->Signature                     = UNDI_DEV_SIGNATURE;
    431 
    432   UNDI32Device->NIIProtocol_31.Revision       = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31;
    433   UNDI32Device->NIIProtocol_31.Type           = EfiNetworkInterfaceUndi;
    434   UNDI32Device->NIIProtocol_31.MajorVer       = PXE_ROMID_MAJORVER;
    435   UNDI32Device->NIIProtocol_31.MinorVer       = PXE_ROMID_MINORVER_31;
    436   UNDI32Device->NIIProtocol_31.ImageSize      = 0;
    437   UNDI32Device->NIIProtocol_31.ImageAddr      = 0;
    438   UNDI32Device->NIIProtocol_31.Ipv6Supported  = TRUE;
    439 
    440   UNDI32Device->NIIProtocol_31.StringId[0]    = 'U';
    441   UNDI32Device->NIIProtocol_31.StringId[1]    = 'N';
    442   UNDI32Device->NIIProtocol_31.StringId[2]    = 'D';
    443   UNDI32Device->NIIProtocol_31.StringId[3]    = 'I';
    444 
    445   UNDI32Device->DeviceHandle                  = NULL;
    446 
    447   UNDI32Device->Aip.GetInformation            = UndiAipGetInfo;
    448   UNDI32Device->Aip.SetInformation            = UndiAipSetInfo;
    449   UNDI32Device->Aip.GetSupportedTypes         = UndiAipGetSupportedTypes;
    450 
    451   //
    452   // install both the 3.0 and 3.1 NII protocols.
    453   //
    454   Status = gBS->InstallMultipleProtocolInterfaces (
    455                   &UNDI32Device->DeviceHandle,
    456                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
    457                   &UNDI32Device->NIIProtocol_31,
    458                   &gEfiDevicePathProtocolGuid,
    459                   UNDI32Device->Undi32DevPath,
    460                   &gEfiAdapterInformationProtocolGuid,
    461                   &UNDI32Device->Aip,
    462                   NULL
    463                   );
    464 
    465   if (EFI_ERROR (Status)) {
    466     goto UndiErrorDeleteDevicePath;
    467   }
    468 
    469   //
    470   // if the table exists, free it and alloc again, or alloc it directly
    471   //
    472   if (UndiDataPointer != NULL) {
    473     Status = gBS->FreePool(UndiDataPointer);
    474   }
    475   if (EFI_ERROR (Status)) {
    476     goto UndiErrorDeleteDevicePath;
    477   }
    478 
    479   Len = ((pxe_31->IFcnt|pxe_31->IFcntExt << 8)* sizeof (UndiDataPointer->NII_entry)) + sizeof (UndiDataPointer);
    480   Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UndiDataPointer);
    481 
    482   if (EFI_ERROR (Status)) {
    483     goto UndiErrorAllocDataPointer;
    484   }
    485 
    486   //
    487   // Open For Child Device
    488   //
    489   Status = gBS->OpenProtocol (
    490                   Controller,
    491                   &gEfiPciIoProtocolGuid,
    492                   (VOID **) &PciIoFncs,
    493                   This->DriverBindingHandle,
    494                   UNDI32Device->DeviceHandle,
    495                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    496                   );
    497 
    498   return EFI_SUCCESS;
    499 UndiErrorAllocDataPointer:
    500   gBS->UninstallMultipleProtocolInterfaces (
    501                   &UNDI32Device->DeviceHandle,
    502                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
    503                   &UNDI32Device->NIIProtocol_31,
    504                   &gEfiDevicePathProtocolGuid,
    505                   UNDI32Device->Undi32DevPath,
    506                   &gEfiAdapterInformationProtocolGuid,
    507                   &UNDI32Device->Aip,
    508                   NULL
    509                   );
    510 
    511 UndiErrorDeleteDevicePath:
    512   UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = NULL;
    513   gBS->FreePool (UNDI32Device->Undi32DevPath);
    514 
    515 UndiErrorDeletePxe:
    516   PxeUpdate (NULL, pxe_31);
    517   if (TmpPxePointer != NULL) {
    518     gBS->FreePool (TmpPxePointer);
    519 
    520   }
    521 
    522 UndiErrorDeleteDevice:
    523   if (PciAttributesSaved) {
    524     //
    525     // Restore original PCI attributes
    526     //
    527     PciIoFncs->Attributes (
    528                     PciIoFncs,
    529                     EfiPciIoAttributeOperationSet,
    530                     UNDI32Device->NicInfo.OriginalPciAttributes,
    531                     NULL
    532                     );
    533   }
    534 
    535   gBS->FreePool (UNDI32Device);
    536 
    537 UndiError:
    538   gBS->CloseProtocol (
    539         Controller,
    540         &gEfiDevicePathProtocolGuid,
    541         This->DriverBindingHandle,
    542         Controller
    543         );
    544 
    545   gBS->CloseProtocol (
    546         Controller,
    547         &gEfiPciIoProtocolGuid,
    548         This->DriverBindingHandle,
    549         Controller
    550         );
    551 
    552   return Status;
    553 }
    554 
    555 
    556 /**
    557   Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
    558   closing the DevicePath and PciIo protocols on Controller.
    559 
    560   @param  This                 Protocol instance pointer.
    561   @param  Controller           Handle of device to stop driver on.
    562   @param  NumberOfChildren     How many children need to be stopped.
    563   @param  ChildHandleBuffer    Not used.
    564 
    565   @retval EFI_SUCCESS          This driver is removed Controller.
    566   @retval other                This driver was not removed from this device.
    567 
    568 **/
    569 // TODO:    EFI_DEVICE_ERROR - add return value to function comment
    570 EFI_STATUS
    571 EFIAPI
    572 UndiDriverStop (
    573   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
    574   IN  EFI_HANDLE                     Controller,
    575   IN  UINTN                          NumberOfChildren,
    576   IN  EFI_HANDLE                     *ChildHandleBuffer
    577   )
    578 {
    579   EFI_STATUS                                Status;
    580   BOOLEAN                                   AllChildrenStopped;
    581   UINTN                                     Index;
    582   UNDI32_DEV                                *UNDI32Device;
    583   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;
    584 
    585   //
    586   // Complete all outstanding transactions to Controller.
    587   // Don't allow any new transaction to Controller to be started.
    588   //
    589   if (NumberOfChildren == 0) {
    590 
    591     //
    592     // Close the bus driver
    593     //
    594     Status = gBS->CloseProtocol (
    595                     Controller,
    596                     &gEfiDevicePathProtocolGuid,
    597                     This->DriverBindingHandle,
    598                     Controller
    599                     );
    600 
    601     Status = gBS->CloseProtocol (
    602                     Controller,
    603                     &gEfiPciIoProtocolGuid,
    604                     This->DriverBindingHandle,
    605                     Controller
    606                     );
    607 
    608     return Status;
    609   }
    610 
    611   AllChildrenStopped = TRUE;
    612 
    613   for (Index = 0; Index < NumberOfChildren; Index++) {
    614 
    615     Status = gBS->OpenProtocol (
    616                     ChildHandleBuffer[Index],
    617                     &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
    618                     (VOID **) &NIIProtocol,
    619                     This->DriverBindingHandle,
    620                     Controller,
    621                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    622                     );
    623     if (!EFI_ERROR (Status)) {
    624 
    625       UNDI32Device = UNDI_DEV_FROM_THIS (NIIProtocol);
    626 
    627       Status = gBS->CloseProtocol (
    628                       Controller,
    629                       &gEfiPciIoProtocolGuid,
    630                       This->DriverBindingHandle,
    631                       ChildHandleBuffer[Index]
    632                       );
    633       if (!EFI_ERROR (Status)) {
    634         Status = gBS->UninstallMultipleProtocolInterfaces (
    635                         ChildHandleBuffer[Index],
    636                         &gEfiDevicePathProtocolGuid,
    637                         UNDI32Device->Undi32DevPath,
    638                         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
    639                         &UNDI32Device->NIIProtocol_31,
    640                         NULL
    641                         );
    642         if (!EFI_ERROR (Status)) {
    643           //
    644           // Restore original PCI attributes
    645           //
    646           Status = UNDI32Device->NicInfo.Io_Function->Attributes (
    647                                                         UNDI32Device->NicInfo.Io_Function,
    648                                                         EfiPciIoAttributeOperationSet,
    649                                                         UNDI32Device->NicInfo.OriginalPciAttributes,
    650                                                         NULL
    651                                                         );
    652 
    653           ASSERT_EFI_ERROR (Status);
    654 
    655           gBS->FreePool (UNDI32Device->Undi32DevPath);
    656           gBS->FreePool (UNDI32Device);
    657 
    658         }
    659       }
    660     }
    661 
    662     if (EFI_ERROR (Status)) {
    663       AllChildrenStopped = FALSE;
    664     }
    665   }
    666 
    667   if (!AllChildrenStopped) {
    668     return EFI_DEVICE_ERROR;
    669   }
    670 
    671   return EFI_SUCCESS;
    672 
    673 }
    674 
    675 
    676 /**
    677   Use the EFI boot services to produce a pause. This is also the routine which
    678   gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can
    679   do it's own pause.
    680 
    681   @param  UnqId                Runtime O/S routine might use this, this temp
    682                                routine does not use it
    683   @param  MicroSeconds         Determines the length of pause.
    684 
    685   @return none
    686 
    687 **/
    688 VOID
    689 TmpDelay (
    690   IN UINT64 UnqId,
    691   IN UINTN  MicroSeconds
    692   )
    693 {
    694   gBS->Stall ((UINT32) MicroSeconds);
    695 }
    696 
    697 
    698 /**
    699   Use the PCI IO abstraction to issue memory or I/O reads and writes.  This is also the routine which
    700   gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can do it's own I/O abstractions.
    701 
    702   @param  UnqId                Runtime O/S routine may use this field, this temp
    703                                routine does not.
    704   @param  ReadWrite            Determine if it is an I/O or Memory Read/Write
    705                                Operation.
    706   @param  Len                  Determines the width of the data operation.
    707   @param  Port                 What port to Read/Write from.
    708   @param  BuffAddr             Address to read to or write from.
    709 
    710   @return none
    711 
    712 **/
    713 VOID
    714 TmpMemIo (
    715   IN UINT64 UnqId,
    716   IN UINT8  ReadWrite,
    717   IN UINT8  Len,
    718   IN UINT64 Port,
    719   IN UINT64 BuffAddr
    720   )
    721 {
    722   EFI_PCI_IO_PROTOCOL_WIDTH Width;
    723   NIC_DATA_INSTANCE         *AdapterInfo;
    724 
    725   Width       = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
    726   AdapterInfo = (NIC_DATA_INSTANCE *) (UINTN) UnqId;
    727   switch (Len) {
    728   case 2:
    729     Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
    730     break;
    731 
    732   case 4:
    733     Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
    734     break;
    735 
    736   case 8:
    737     Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
    738     break;
    739   }
    740 
    741   switch (ReadWrite) {
    742   case PXE_IO_READ:
    743     AdapterInfo->Io_Function->Io.Read (
    744                                   AdapterInfo->Io_Function,
    745                                   Width,
    746                                   1,
    747                                   Port,
    748                                   1,
    749                                   (VOID *) (UINTN) (BuffAddr)
    750                                   );
    751     break;
    752 
    753   case PXE_IO_WRITE:
    754     AdapterInfo->Io_Function->Io.Write (
    755                                   AdapterInfo->Io_Function,
    756                                   Width,
    757                                   1,
    758                                   Port,
    759                                   1,
    760                                   (VOID *) (UINTN) (BuffAddr)
    761                                   );
    762     break;
    763 
    764   case PXE_MEM_READ:
    765     AdapterInfo->Io_Function->Mem.Read (
    766                                     AdapterInfo->Io_Function,
    767                                     Width,
    768                                     0,
    769                                     Port,
    770                                     1,
    771                                     (VOID *) (UINTN) (BuffAddr)
    772                                     );
    773     break;
    774 
    775   case PXE_MEM_WRITE:
    776     AdapterInfo->Io_Function->Mem.Write (
    777                                     AdapterInfo->Io_Function,
    778                                     Width,
    779                                     0,
    780                                     Port,
    781                                     1,
    782                                     (VOID *) (UINTN) (BuffAddr)
    783                                     );
    784     break;
    785   }
    786 
    787   return ;
    788 }
    789 
    790 
    791 /**
    792   Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space
    793   for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr)
    794   and an added MAC node.
    795 
    796   @param  DevPtr               Pointer which will point to the newly created device
    797                                path with the MAC node attached.
    798   @param  BaseDevPtr           Pointer to the device path which the UNDI device
    799                                driver is latching on to.
    800   @param  AdapterInfo          Pointer to the NIC data structure information which
    801                                the UNDI driver is layering on..
    802 
    803   @retval EFI_SUCCESS          A MAC address was successfully appended to the Base
    804                                Device Path.
    805   @retval other                Not enough resources available to create new Device
    806                                Path node.
    807 
    808 **/
    809 EFI_STATUS
    810 AppendMac2DevPath (
    811   IN OUT  EFI_DEVICE_PATH_PROTOCOL **DevPtr,
    812   IN      EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
    813   IN      NIC_DATA_INSTANCE        *AdapterInfo
    814   )
    815 {
    816   EFI_MAC_ADDRESS           MACAddress;
    817   PCI_CONFIG_HEADER         *CfgHdr;
    818   INT32                     Val;
    819   INT32                     Index;
    820   INT32                     Index2;
    821   UINT8                     AddrLen;
    822   MAC_ADDR_DEVICE_PATH      MacAddrNode;
    823   EFI_DEVICE_PATH_PROTOCOL  *EndNode;
    824   UINT8                     *DevicePtr;
    825   UINT16                    TotalPathLen;
    826   UINT16                    BasePathLen;
    827   EFI_STATUS                Status;
    828 
    829   //
    830   // set the environment ready (similar to UNDI_Start call) so that we can
    831   // execute the other UNDI_ calls to get the mac address
    832   // we are using undi 3.1 style
    833   //
    834   AdapterInfo->Delay      = TmpDelay;
    835   AdapterInfo->Virt2Phys  = (VOID *) 0;
    836   AdapterInfo->Block      = (VOID *) 0;
    837   AdapterInfo->Map_Mem    = (VOID *) 0;
    838   AdapterInfo->UnMap_Mem  = (VOID *) 0;
    839   AdapterInfo->Sync_Mem   = (VOID *) 0;
    840   AdapterInfo->Mem_Io     = TmpMemIo;
    841   //
    842   // these tmp call-backs follow 3.1 undi style
    843   // i.e. they have the unique_id parameter.
    844   //
    845   AdapterInfo->VersionFlag  = 0x31;
    846   AdapterInfo->Unique_ID    = (UINT64) (UINTN) AdapterInfo;
    847 
    848   //
    849   // undi init portion
    850   //
    851   CfgHdr              = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);
    852   AdapterInfo->ioaddr = 0;
    853   AdapterInfo->RevID  = CfgHdr->RevID;
    854 
    855   AddrLen             = E100bGetEepromAddrLen (AdapterInfo);
    856 
    857   for (Index = 0, Index2 = 0; Index < 3; Index++) {
    858     Val                       = E100bReadEeprom (AdapterInfo, Index, AddrLen);
    859     MACAddress.Addr[Index2++] = (UINT8) Val;
    860     MACAddress.Addr[Index2++] = (UINT8) (Val >> 8);
    861   }
    862 
    863   SetMem (MACAddress.Addr + Index2, sizeof (EFI_MAC_ADDRESS) - Index2, 0);
    864   //for (; Index2 < sizeof (EFI_MAC_ADDRESS); Index2++) {
    865   //  MACAddress.Addr[Index2] = 0;
    866   //}
    867   //
    868   // stop undi
    869   //
    870   AdapterInfo->Delay  = (VOID *) 0;
    871   AdapterInfo->Mem_Io = (VOID *) 0;
    872 
    873   //
    874   // fill the mac address node first
    875   //
    876   ZeroMem ((CHAR8 *) &MacAddrNode, sizeof MacAddrNode);
    877   CopyMem (
    878     (CHAR8 *) &MacAddrNode.MacAddress,
    879     (CHAR8 *) &MACAddress,
    880     sizeof (EFI_MAC_ADDRESS)
    881     );
    882 
    883   MacAddrNode.Header.Type       = MESSAGING_DEVICE_PATH;
    884   MacAddrNode.Header.SubType    = MSG_MAC_ADDR_DP;
    885   MacAddrNode.Header.Length[0]  = (UINT8) sizeof (MacAddrNode);
    886   MacAddrNode.Header.Length[1]  = 0;
    887 
    888   //
    889   // find the size of the base dev path.
    890   //
    891   EndNode = BaseDevPtr;
    892 
    893   while (!IsDevicePathEnd (EndNode)) {
    894     EndNode = NextDevicePathNode (EndNode);
    895   }
    896 
    897   BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr));
    898 
    899   //
    900   // create space for full dev path
    901   //
    902   TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
    903 
    904   Status = gBS->AllocatePool (
    905                   EfiRuntimeServicesData,
    906                   TotalPathLen,
    907                   (VOID **) &DevicePtr
    908                   );
    909 
    910   if (Status != EFI_SUCCESS) {
    911     return Status;
    912   }
    913   //
    914   // copy the base path, mac addr and end_dev_path nodes
    915   //
    916   *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr;
    917   CopyMem (DevicePtr, (CHAR8 *) BaseDevPtr, BasePathLen);
    918   DevicePtr += BasePathLen;
    919   CopyMem (DevicePtr, (CHAR8 *) &MacAddrNode, sizeof (MacAddrNode));
    920   DevicePtr += sizeof (MacAddrNode);
    921   CopyMem (DevicePtr, (CHAR8 *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
    922 
    923   return EFI_SUCCESS;
    924 }
    925 
    926 
    927 /**
    928   Install a GUID/Pointer pair into the system's configuration table.
    929 
    930   none
    931 
    932   @retval EFI_SUCCESS          Install a GUID/Pointer pair into the system's
    933                                configuration table.
    934   @retval other                Did not successfully install the GUID/Pointer pair
    935                                into the configuration table.
    936 
    937 **/
    938 // TODO:    VOID - add argument and description to function comment
    939 EFI_STATUS
    940 InstallConfigTable (
    941   IN VOID
    942   )
    943 {
    944   EFI_STATUS              Status;
    945   EFI_CONFIGURATION_TABLE *CfgPtr;
    946   UNDI_CONFIG_TABLE       *TmpData;
    947   UINT16                  Index;
    948   UNDI_CONFIG_TABLE       *UndiData;
    949 
    950   if (pxe_31 == NULL) {
    951     return EFI_SUCCESS;
    952   }
    953 
    954   if(UndiDataPointer == NULL) {
    955     return EFI_SUCCESS;
    956   }
    957 
    958   UndiData = (UNDI_CONFIG_TABLE *)UndiDataPointer;
    959 
    960   UndiData->NumberOfInterfaces  = (pxe_31->IFcnt | pxe_31->IFcntExt << 8);
    961   UndiData->nextlink            = NULL;
    962 
    963   for (Index = 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Index++) {
    964     UndiData->NII_entry[Index].NII_InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31;
    965     UndiData->NII_entry[Index].DevicePathPointer    = UNDI32DeviceList[Index]->Undi32DevPath;
    966   }
    967 
    968   //
    969   // see if there is an entry in the config table already
    970   //
    971   CfgPtr = gST->ConfigurationTable;
    972 
    973   for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
    974     Status = CompareGuid (
    975               &CfgPtr->VendorGuid,
    976               &gEfiNetworkInterfaceIdentifierProtocolGuid_31
    977               );
    978     if (Status != EFI_SUCCESS) {
    979       break;
    980     }
    981 
    982     CfgPtr++;
    983   }
    984 
    985   if (Index < gST->NumberOfTableEntries) {
    986     TmpData = (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable;
    987 
    988     //
    989     // go to the last link
    990     //
    991     while (TmpData->nextlink != NULL) {
    992       TmpData = TmpData->nextlink;
    993     }
    994 
    995     TmpData->nextlink = UndiData;
    996 
    997     //
    998     // 1st one in chain
    999     //
   1000     UndiData = (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable;
   1001   }
   1002 
   1003   //
   1004   // create an entry in the configuration table for our GUID
   1005   //
   1006   Status = gBS->InstallConfigurationTable (
   1007                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
   1008                   UndiData
   1009                   );
   1010   return Status;
   1011 }
   1012 
   1013 /**
   1014 
   1015 **/
   1016 EFI_STATUS
   1017 EFIAPI
   1018 InitializeUndi(
   1019   IN EFI_HANDLE           ImageHandle,
   1020   IN EFI_SYSTEM_TABLE     *SystemTable
   1021   )
   1022 {
   1023   EFI_EVENT     Event;
   1024   EFI_STATUS    Status;
   1025 
   1026   Status = EfiLibInstallDriverBindingComponentName2 (
   1027              ImageHandle,
   1028              SystemTable,
   1029              &gUndiDriverBinding,
   1030              ImageHandle,
   1031              &gUndiComponentName,
   1032              &gUndiComponentName2
   1033              );
   1034   ASSERT_EFI_ERROR (Status);
   1035 
   1036   Status = gBS->CreateEventEx (
   1037                   EVT_NOTIFY_SIGNAL,
   1038                   TPL_NOTIFY,
   1039                   UndiNotifyReadyToBoot,
   1040                   NULL,
   1041                   &gEfiEventReadyToBootGuid,
   1042                   &Event
   1043                   );
   1044   ASSERT_EFI_ERROR (Status);
   1045 
   1046   Status = gBS->CreateEventEx (
   1047                   EVT_NOTIFY_SIGNAL,
   1048                   TPL_NOTIFY,
   1049                   UndiNotifyVirtual,
   1050                   NULL,
   1051                   &gEfiEventVirtualAddressChangeGuid,
   1052                   &Event
   1053                   );
   1054   ASSERT_EFI_ERROR (Status);
   1055 
   1056   return Status;
   1057 }
   1058