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
UndiNotifyVirtual(EFI_EVENT Event,VOID * Context)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
UndiNotifyReadyToBoot(EFI_EVENT Event,VOID * Context)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
UndiDriverSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
UndiDriverStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
UndiDriverStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
TmpDelay(IN UINT64 UnqId,IN UINTN MicroSeconds)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
TmpMemIo(IN UINT64 UnqId,IN UINT8 ReadWrite,IN UINT8 Len,IN UINT64 Port,IN UINT64 BuffAddr)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
AppendMac2DevPath(IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevPtr,IN EFI_DEVICE_PATH_PROTOCOL * BaseDevPtr,IN NIC_DATA_INSTANCE * AdapterInfo)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
InstallConfigTable(IN VOID)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
InitializeUndi(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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