1 /** @file
2 
3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
4 
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "LegacyBiosInterface.h"
10 #include <IndustryStandard/Pci30.h>
11 
12 #define PCI_START_ADDRESS(x)   (((x) + 0x7ff) & ~0x7ff)
13 
14 #define MAX_BRIDGE_INDEX  0x20
15 typedef struct {
16   UINTN PciSegment;
17   UINTN PciBus;
18   UINTN PciDevice;
19   UINTN PciFunction;
20   UINT8 PrimaryBus;
21   UINT8 SecondaryBus;
22   UINT8 SubordinateBus;
23 } BRIDGE_TABLE;
24 
25 #define ROM_MAX_ENTRIES 24
26 BRIDGE_TABLE                        Bridges[MAX_BRIDGE_INDEX];
27 UINTN                               SortedBridgeIndex[MAX_BRIDGE_INDEX];
28 UINTN                               NumberOfBridges;
29 LEGACY_PNP_EXPANSION_HEADER  *mBasePnpPtr;
30 UINT16                              mBbsRomSegment;
31 UINTN                               mHandleCount;
32 EFI_HANDLE                          mVgaHandle;
33 BOOLEAN                             mIgnoreBbsUpdateFlag;
34 BOOLEAN                             mVgaInstallationInProgress  = FALSE;
35 UINT32                              mRomCount                   = 0x00;
36 ROM_INSTANCE_ENTRY                  mRomEntry[ROM_MAX_ENTRIES];
37 EDKII_IOMMU_PROTOCOL                *mIoMmu;
38 
39 /**
40   Query shadowed legacy ROM parameters registered by RomShadow() previously.
41 
42   @param  PciHandle        PCI device whos ROM has been shadowed
43   @param  DiskStart        DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
44   @param  DiskEnd          DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
45   @param  RomShadowAddress Address where ROM was shadowed
46   @param  ShadowedSize     Runtime size of ROM
47 
48   @retval EFI_SUCCESS      Query Logging successful.
49   @retval EFI_NOT_FOUND    No logged data found about PciHandle.
50 
51 **/
52 EFI_STATUS
GetShadowedRomParameters(IN EFI_HANDLE PciHandle,OUT UINT8 * DiskStart,OPTIONAL OUT UINT8 * DiskEnd,OPTIONAL OUT VOID ** RomShadowAddress,OPTIONAL OUT UINTN * ShadowedSize OPTIONAL)53 GetShadowedRomParameters (
54   IN EFI_HANDLE                         PciHandle,
55   OUT UINT8                             *DiskStart,         OPTIONAL
56   OUT UINT8                             *DiskEnd,           OPTIONAL
57   OUT VOID                              **RomShadowAddress, OPTIONAL
58   OUT UINTN                             *ShadowedSize       OPTIONAL
59   )
60 {
61   EFI_STATUS          Status;
62   EFI_PCI_IO_PROTOCOL *PciIo;
63   UINTN               Index;
64   UINTN               PciSegment;
65   UINTN               PciBus;
66   UINTN               PciDevice;
67   UINTN               PciFunction;
68 
69   //
70   // Get the PCI I/O Protocol on PciHandle
71   //
72   Status = gBS->HandleProtocol (
73                   PciHandle,
74                   &gEfiPciIoProtocolGuid,
75                   (VOID **) &PciIo
76                   );
77   if (EFI_ERROR (Status)) {
78     return Status;
79   }
80 
81   //
82   // Get the location of the PCI device
83   //
84   PciIo->GetLocation (
85            PciIo,
86            &PciSegment,
87            &PciBus,
88            &PciDevice,
89            &PciFunction
90            );
91 
92   for(Index = 0; Index < mRomCount; Index++) {
93     if ((mRomEntry[Index].PciSegment == PciSegment) &&
94         (mRomEntry[Index].PciBus == PciBus)         &&
95         (mRomEntry[Index].PciDevice == PciDevice)   &&
96         (mRomEntry[Index].PciFunction == PciFunction)) {
97       break;
98     }
99   }
100 
101   if (Index == mRomCount) {
102     return EFI_NOT_FOUND;
103   }
104 
105   if (DiskStart != NULL) {
106     *DiskStart = mRomEntry[Index].DiskStart;
107   }
108 
109   if (DiskEnd != NULL) {
110     *DiskEnd = mRomEntry[Index].DiskEnd;
111   }
112 
113   if (RomShadowAddress != NULL) {
114     *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress;
115   }
116 
117   if (ShadowedSize != NULL) {
118     *ShadowedSize = mRomEntry[Index].ShadowedSize;
119   }
120 
121   return EFI_SUCCESS;
122 }
123 
124 /**
125   Every legacy ROM that is shadowed by the Legacy BIOS driver will be
126   registered into this API so that the policy code can know what has
127   happend
128 
129   @param  PciHandle              PCI device whos ROM is being shadowed
130   @param  ShadowAddress          Address that ROM was shadowed
131   @param  ShadowedSize           Runtime size of ROM
132   @param  DiskStart              DiskStart value from
133                                  EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
134   @param  DiskEnd                DiskEnd value from
135                                  EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
136 
137   @retval EFI_SUCCESS            Logging successful.
138   @retval EFI_OUT_OF_RESOURCES   No remaining room for registering another option
139                                  ROM.
140 
141 **/
142 EFI_STATUS
RomShadow(IN EFI_HANDLE PciHandle,IN UINT32 ShadowAddress,IN UINT32 ShadowedSize,IN UINT8 DiskStart,IN UINT8 DiskEnd)143 RomShadow (
144   IN  EFI_HANDLE                                  PciHandle,
145   IN  UINT32                                      ShadowAddress,
146   IN  UINT32                                      ShadowedSize,
147   IN  UINT8                                       DiskStart,
148   IN  UINT8                                       DiskEnd
149   )
150 {
151   EFI_STATUS          Status;
152   EFI_PCI_IO_PROTOCOL *PciIo;
153 
154   //
155   // See if there is room to register another option ROM
156   //
157   if (mRomCount >= ROM_MAX_ENTRIES) {
158     return EFI_OUT_OF_RESOURCES;
159   }
160   //
161   // Get the PCI I/O Protocol on PciHandle
162   //
163   Status = gBS->HandleProtocol (
164                   PciHandle,
165                   &gEfiPciIoProtocolGuid,
166                   (VOID **) &PciIo
167                   );
168   if (EFI_ERROR (Status)) {
169     return Status;
170   }
171   //
172   // Get the location of the PCI device
173   //
174   PciIo->GetLocation (
175            PciIo,
176            &mRomEntry[mRomCount].PciSegment,
177            &mRomEntry[mRomCount].PciBus,
178            &mRomEntry[mRomCount].PciDevice,
179            &mRomEntry[mRomCount].PciFunction
180            );
181   mRomEntry[mRomCount].ShadowAddress = ShadowAddress;
182   mRomEntry[mRomCount].ShadowedSize  = ShadowedSize;
183   mRomEntry[mRomCount].DiskStart     = DiskStart;
184   mRomEntry[mRomCount].DiskEnd       = DiskEnd;
185 
186   mRomCount++;
187 
188   return EFI_SUCCESS;
189 }
190 
191 
192 /**
193   Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This
194   information represents every call to RomShadow ()
195 
196   @param  PciHandle              PCI device to get status for
197 
198   @retval EFI_SUCCESS            Legacy ROM loaded for this device
199   @retval EFI_NOT_FOUND          No Legacy ROM loaded for this device
200 
201 **/
202 EFI_STATUS
IsLegacyRom(IN EFI_HANDLE PciHandle)203 IsLegacyRom (
204   IN  EFI_HANDLE                PciHandle
205   )
206 {
207   EFI_STATUS          Status;
208   EFI_PCI_IO_PROTOCOL *PciIo;
209   UINTN               Index;
210   UINTN               Segment;
211   UINTN               Bus;
212   UINTN               Device;
213   UINTN               Function;
214 
215   //
216   // Get the PCI I/O Protocol on PciHandle
217   //
218   Status = gBS->HandleProtocol (
219                   PciHandle,
220                   &gEfiPciIoProtocolGuid,
221                   (VOID **) &PciIo
222                   );
223   if (EFI_ERROR (Status)) {
224     return Status;
225   }
226   //
227   // Get the location of the PCI device
228   //
229   PciIo->GetLocation (
230            PciIo,
231            &Segment,
232            &Bus,
233            &Device,
234            &Function
235            );
236 
237   //
238   // See if the option ROM from PciHandle has been previously posted
239   //
240   for (Index = 0; Index < mRomCount; Index++) {
241     if (mRomEntry[Index].PciSegment == Segment &&
242         mRomEntry[Index].PciBus == Bus &&
243         mRomEntry[Index].PciDevice == Device &&
244         mRomEntry[Index].PciFunction == Function
245         ) {
246       return EFI_SUCCESS;
247     }
248   }
249 
250   return EFI_NOT_FOUND;
251 }
252 
253 /**
254   Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the
255   related information from the header.
256 
257   @param  Csm16Revision           The PCI interface version of underlying CSM16
258   @param  VendorId                Vendor ID of the PCI device
259   @param  DeviceId                Device ID of the PCI device
260   @param  Rom                     On input pointing to beginning of the raw PCI OpROM
261                                   On output pointing to the first legacy PCI OpROM
262   @param  ImageSize               On input is the size of Raw PCI Rom
263                                   On output is the size of the first legacy PCI ROM
264   @param  MaxRuntimeImageLength   The max runtime image length only valid if OpRomRevision >= 3
265   @param  OpRomRevision           Revision of the PCI Rom
266   @param  ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header
267 
268   @retval EFI_SUCCESS             Successfully find the legacy PCI ROM
269   @retval EFI_NOT_FOUND           Failed to find the legacy PCI ROM
270 
271 **/
272 EFI_STATUS
GetPciLegacyRom(IN UINT16 Csm16Revision,IN UINT16 VendorId,IN UINT16 DeviceId,IN OUT VOID ** Rom,IN OUT UINTN * ImageSize,OUT UINTN * MaxRuntimeImageLength,OPTIONAL OUT UINT8 * OpRomRevision,OPTIONAL OUT VOID ** ConfigUtilityCodeHeader OPTIONAL)273 GetPciLegacyRom (
274   IN     UINT16 Csm16Revision,
275   IN     UINT16 VendorId,
276   IN     UINT16 DeviceId,
277   IN OUT VOID   **Rom,
278   IN OUT UINTN  *ImageSize,
279   OUT    UINTN  *MaxRuntimeImageLength,   OPTIONAL
280   OUT    UINT8  *OpRomRevision,           OPTIONAL
281   OUT    VOID   **ConfigUtilityCodeHeader OPTIONAL
282   )
283 {
284   BOOLEAN                 Match;
285   UINT16                  *DeviceIdList;
286   EFI_PCI_ROM_HEADER      RomHeader;
287   PCI_3_0_DATA_STRUCTURE  *Pcir;
288   VOID                    *BackupImage;
289   VOID                    *BestImage;
290 
291 
292   if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) {
293     return EFI_NOT_FOUND;
294   }
295 
296   BestImage     = NULL;
297   BackupImage   = NULL;
298   RomHeader.Raw = *Rom;
299   while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
300     if (RomHeader.Generic->PcirOffset == 0 ||
301         (RomHeader.Generic->PcirOffset & 3) !=0 ||
302         *ImageSize < RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)) {
303       break;
304     }
305 
306     Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
307     //
308     // Check signature in the PCI Data Structure.
309     //
310     if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
311       break;
312     }
313 
314     if (((UINTN)RomHeader.Raw - (UINTN)*Rom) + Pcir->ImageLength * 512 > *ImageSize) {
315       break;
316     }
317 
318     if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
319       Match = FALSE;
320       if (Pcir->VendorId == VendorId) {
321         if (Pcir->DeviceId == DeviceId) {
322           Match = TRUE;
323         } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) {
324           DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset);
325           //
326           // Checking the device list
327           //
328           while (*DeviceIdList != 0) {
329             if (*DeviceIdList == DeviceId) {
330               Match = TRUE;
331               break;
332             }
333             DeviceIdList ++;
334           }
335         }
336       }
337 
338       if (Match) {
339         if (Csm16Revision >= 0x0300) {
340           //
341           // Case 1: CSM16 3.0
342           //
343           if (Pcir->Revision >= 3) {
344             //
345             // case 1.1: meets OpRom 3.0
346             //           Perfect!!!
347             //
348             BestImage  = RomHeader.Raw;
349             break;
350           } else {
351             //
352             // case 1.2: meets OpRom 2.x
353             //           Store it and try to find the OpRom 3.0
354             //
355             BackupImage = RomHeader.Raw;
356           }
357         } else {
358           //
359           // Case 2: CSM16 2.x
360           //
361           if (Pcir->Revision >= 3) {
362             //
363             // case 2.1: meets OpRom 3.0
364             //           Store it and try to find the OpRom 2.x
365             //
366             BackupImage = RomHeader.Raw;
367           } else {
368             //
369             // case 2.2: meets OpRom 2.x
370             //           Perfect!!!
371             //
372             BestImage   = RomHeader.Raw;
373             break;
374           }
375         }
376       } else {
377         DEBUG ((DEBUG_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId));
378       }
379     }
380 
381     if ((Pcir->Indicator & 0x80) == 0x80) {
382       break;
383     } else {
384       RomHeader.Raw += 512 * Pcir->ImageLength;
385     }
386   }
387 
388   if (BestImage == NULL) {
389     if (BackupImage == NULL) {
390       return EFI_NOT_FOUND;
391     }
392     //
393     // The versions of CSM16 and OpRom don't match exactly
394     //
395     BestImage = BackupImage;
396   }
397   RomHeader.Raw = BestImage;
398   Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
399   *Rom       = BestImage;
400   *ImageSize = Pcir->ImageLength * 512;
401 
402   if (MaxRuntimeImageLength != NULL) {
403     if (Pcir->Revision < 3) {
404       *MaxRuntimeImageLength = 0;
405     } else {
406       *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
407     }
408   }
409 
410   if (OpRomRevision != NULL) {
411     //
412     // Optional return PCI Data Structure revision
413     //
414     if (Pcir->Length >= 0x1C) {
415       *OpRomRevision = Pcir->Revision;
416     } else {
417       *OpRomRevision = 0;
418     }
419   }
420 
421   if (ConfigUtilityCodeHeader != NULL) {
422     //
423     // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM
424     //
425     if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) {
426       *ConfigUtilityCodeHeader = NULL;
427     } else {
428       *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset;
429     }
430   }
431 
432   return EFI_SUCCESS;
433 }
434 
435 /**
436   Build a table of bridge info for PIRQ translation.
437 
438   @param  RoutingTable         RoutingTable obtained from Platform.
439   @param  RoutingTableEntries  Number of RoutingTable entries.
440 
441   @retval EFI_SUCCESS          New Subordinate bus.
442   @retval EFI_NOT_FOUND        No more Subordinate busses.
443 
444 **/
445 EFI_STATUS
CreateBridgeTable(IN EFI_LEGACY_IRQ_ROUTING_ENTRY * RoutingTable,IN UINTN RoutingTableEntries)446 CreateBridgeTable (
447   IN EFI_LEGACY_IRQ_ROUTING_ENTRY         *RoutingTable,
448   IN UINTN                                RoutingTableEntries
449   )
450 {
451   EFI_STATUS          Status;
452   UINTN               HandleCount;
453   EFI_HANDLE          *HandleBuffer;
454   UINTN               BridgeIndex;
455   UINTN               Index;
456   UINTN               Index1;
457   EFI_PCI_IO_PROTOCOL *PciIo;
458   PCI_TYPE01          PciConfigHeader;
459   BRIDGE_TABLE        SlotBridges[MAX_BRIDGE_INDEX];
460   UINTN               SlotBridgeIndex;
461 
462   BridgeIndex = 0x00;
463   SlotBridgeIndex = 0x00;
464 
465   //
466   // Assumption is table is built from low bus to high bus numbers.
467   //
468   Status = gBS->LocateHandleBuffer (
469                   ByProtocol,
470                   &gEfiPciIoProtocolGuid,
471                   NULL,
472                   &HandleCount,
473                   &HandleBuffer
474                   );
475   if (EFI_ERROR (Status)) {
476     return EFI_NOT_FOUND;
477   }
478   for (Index = 0; Index < HandleCount; Index++) {
479     Status = gBS->HandleProtocol (
480                     HandleBuffer[Index],
481                     &gEfiPciIoProtocolGuid,
482                     (VOID **) &PciIo
483                     );
484     if (EFI_ERROR (Status)) {
485       continue;
486     }
487 
488     PciIo->Pci.Read (
489                  PciIo,
490                  EfiPciIoWidthUint32,
491                  0,
492                  sizeof (PciConfigHeader) / sizeof (UINT32),
493                  &PciConfigHeader
494                  );
495 
496     if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) {
497       PciIo->GetLocation (
498                PciIo,
499                &Bridges[BridgeIndex].PciSegment,
500                &Bridges[BridgeIndex].PciBus,
501                &Bridges[BridgeIndex].PciDevice,
502                &Bridges[BridgeIndex].PciFunction
503                );
504 
505       Bridges[BridgeIndex].PrimaryBus     = PciConfigHeader.Bridge.PrimaryBus;
506 
507       Bridges[BridgeIndex].SecondaryBus   = PciConfigHeader.Bridge.SecondaryBus;
508 
509       Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus;
510 
511       for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){
512         //
513         // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board
514         // Once we find one, store it in the SlotBridges[]
515         //
516         if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus)
517            && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) {
518           CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE));
519           SlotBridgeIndex++;
520 
521           break;
522         }
523       }
524 
525       ++BridgeIndex;
526     }
527   }
528 
529   //
530   // Pack up Bridges by removing those useless ones
531   //
532   for (Index = 0; Index < BridgeIndex;){
533     for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) {
534       if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) ||
535         ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) {
536         //
537         // We have found one that meets our criteria
538         //
539         Index++;
540         break;
541       }
542     }
543 
544     //
545     // This one doesn't meet criteria, pack it
546     //
547     if (Index1 >= SlotBridgeIndex) {
548       for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) {
549         CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE));
550       }
551 
552       BridgeIndex--;
553     }
554   }
555 
556   NumberOfBridges = BridgeIndex;
557 
558   //
559   // Sort bridges low to high by Secondary bus followed by subordinate bus
560   //
561   if (NumberOfBridges > 1) {
562     Index = 0;
563     do {
564       SortedBridgeIndex[Index] = Index;
565       ++Index;
566     } while (Index < NumberOfBridges);
567 
568     for (Index = 0; Index < NumberOfBridges - 1; Index++) {
569       for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) {
570         if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) {
571           SortedBridgeIndex[Index]  = Index1;
572           SortedBridgeIndex[Index1] = Index;
573         }
574 
575         if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) &&
576             (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus)
577             ) {
578           SortedBridgeIndex[Index]  = Index1;
579           SortedBridgeIndex[Index1] = Index;
580         }
581       }
582     }
583   }
584   FreePool (HandleBuffer);
585   return EFI_SUCCESS;
586 }
587 
588 
589 /**
590   Find base Bridge for device.
591 
592   @param  Private                Legacy  BIOS Instance data
593   @param  PciBus                 Input = Bus of device.
594   @param  PciDevice              Input = Device.
595   @param  RoutingTable           The platform specific routing table
596   @param  RoutingTableEntries    Number of entries in table
597 
598   @retval EFI_SUCCESS            At base bus.
599   @retval EFI_NOT_FOUND          Behind a bridge.
600 
601 **/
602 EFI_STATUS
GetBaseBus(IN LEGACY_BIOS_INSTANCE * Private,IN UINTN PciBus,IN UINTN PciDevice,IN EFI_LEGACY_IRQ_ROUTING_ENTRY * RoutingTable,IN UINTN RoutingTableEntries)603 GetBaseBus (
604   IN  LEGACY_BIOS_INSTANCE        *Private,
605   IN UINTN                        PciBus,
606   IN UINTN                        PciDevice,
607   IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
608   IN UINTN                        RoutingTableEntries
609   )
610 {
611   UINTN Index;
612   for (Index = 0; Index < RoutingTableEntries; Index++) {
613     if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) {
614       return EFI_SUCCESS;
615     }
616   }
617 
618   return EFI_NOT_FOUND;
619 }
620 
621 /**
622   Translate PIRQ through busses
623 
624   @param  Private              Legacy  BIOS Instance data
625   @param  PciBus               Input = Bus of device. Output = Translated Bus
626   @param  PciDevice            Input = Device. Output = Translated Device
627   @param  PciFunction          Input = Function. Output = Translated Function
628   @param  PirqIndex            Input = Original PIRQ index. If single function
629                                   device then 0, otherwise 0-3.
630                                Output = Translated Index
631 
632   @retval EFI_SUCCESS          Pirq successfully translated.
633   @retval EFI_NOT_FOUND        The device is not behind any known bridge.
634 
635 **/
636 EFI_STATUS
TranslateBusPirq(IN LEGACY_BIOS_INSTANCE * Private,IN OUT UINTN * PciBus,IN OUT UINTN * PciDevice,IN OUT UINTN * PciFunction,IN OUT UINT8 * PirqIndex)637 TranslateBusPirq (
638   IN  LEGACY_BIOS_INSTANCE            *Private,
639   IN OUT UINTN                        *PciBus,
640   IN OUT UINTN                        *PciDevice,
641   IN OUT UINTN                        *PciFunction,
642   IN OUT UINT8                        *PirqIndex
643   )
644 {
645   /*
646   This routine traverses the PCI busses from base slot
647   and translates the PIRQ register to the appropriate one.
648 
649   Example:
650 
651   Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.
652     Primary bus# = 0
653     Secondary bus # = 1
654     Subordinate bus # is highest bus # behind this bus
655        Bus 1, Device 0 is Slot 0 and is not a bridge.
656        Bus 1, Device 1 is Slot 1 and is a bridge.
657          Slot PIRQ routing is A,B,C,D.
658          Primary bus # = 1
659          Secondary bus # = 2
660          Subordinate bus # = 5
661             Bus 2, Device 6 is a bridge. It has no bridges behind it.
662               Primary bus # = 2
663               Secondary bus # = 3
664               Subordinate bus # = 3
665               Bridge PIRQ routing is C,D,A,B
666             Bus 2, Device 7 is a bridge. It has 1 bridge behind it.
667               Primary bus # = 2
668               Secondary bus = 4   Device 6 takes bus 2.
669               Subordinate bus = 5.
670               Bridge PIRQ routing is D,A,B,C
671                  Bus 4, Device 2 is a bridge. It has no bridges behind it.
672                    Primary bus # = 4
673                    Secondary bus # = 5
674                    Subordinate bus = 5
675                    Bridge PIRQ routing is B,C,D,A
676                       Bus 5, Device 1 is to be programmed.
677                          Device PIRQ routing is C,D,A,B
678 
679 
680 Search busses starting from slot bus for final bus >= Secondary bus and
681 final bus <= Subordinate bus. Assumption is bus entries increase in bus
682 number.
683 Starting PIRQ is A,B,C,D.
684 Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device
685   7 modulo 4 giving (D,A,B,C).
686 Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving
687   (B,C,D,A).
688 No other busses match criteria. Device to be programmed is Bus 5, Device 1.
689 Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.
690 
691 */
692   UINTN LocalBus;
693   UINTN LocalDevice;
694   UINTN BaseBus;
695   UINTN BaseDevice;
696   UINTN BaseFunction;
697   UINT8 LocalPirqIndex;
698   BOOLEAN BaseIndexFlag;
699   UINTN BridgeIndex;
700   UINTN SBridgeIndex;
701   BaseIndexFlag   = FALSE;
702   BridgeIndex     = 0x00;
703 
704   LocalPirqIndex  = *PirqIndex;
705   LocalBus        = *PciBus;
706   LocalDevice     = *PciDevice;
707   BaseBus         = *PciBus;
708   BaseDevice      = *PciDevice;
709   BaseFunction    = *PciFunction;
710 
711   //
712   // LocalPirqIndex list PIRQs in rotated fashion
713   // = 0  A,B,C,D
714   // = 1  B,C,D,A
715   // = 2  C,D,A,B
716   // = 3  D,A,B,C
717   //
718 
719   for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) {
720     SBridgeIndex = SortedBridgeIndex[BridgeIndex];
721     //
722     // Check if device behind this bridge
723     //
724     if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) {
725       //
726       // If BaseIndexFlag = FALSE then have found base bridge, i.e
727       // bridge in slot. Save info for use by IRQ routing table.
728       //
729       if (!BaseIndexFlag) {
730         BaseBus       = Bridges[SBridgeIndex].PciBus;
731         BaseDevice    = Bridges[SBridgeIndex].PciDevice;
732         BaseFunction  = Bridges[SBridgeIndex].PciFunction;
733         BaseIndexFlag = TRUE;
734       } else {
735         LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4);
736       }
737 
738       //
739       // Check if at device. If not get new PCI location & PIRQ
740       //
741       if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) {
742         //
743         // Translate PIRQ
744         //
745         LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4);
746         break;
747       }
748     }
749   }
750 
751   //
752   // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user
753   //
754   if(BridgeIndex >= NumberOfBridges){
755     DEBUG ((DEBUG_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction));
756   }
757 
758   *PirqIndex    = LocalPirqIndex;
759   *PciBus       = BaseBus;
760   *PciDevice    = BaseDevice;
761   *PciFunction  = BaseFunction;
762 
763   return EFI_SUCCESS;
764 }
765 
766 
767 /**
768   Copy the $PIR table as required.
769 
770   @param  Private                Legacy  BIOS Instance data
771   @param  RoutingTable           Pointer to IRQ routing table
772   @param  RoutingTableEntries    IRQ routing table entries
773   @param  PirqTable              Pointer to $PIR table
774   @param  PirqTableSize          Length of table
775 
776 **/
777 VOID
CopyPirqTable(IN LEGACY_BIOS_INSTANCE * Private,IN EFI_LEGACY_IRQ_ROUTING_ENTRY * RoutingTable,IN UINTN RoutingTableEntries,IN EFI_LEGACY_PIRQ_TABLE_HEADER * PirqTable,IN UINTN PirqTableSize)778 CopyPirqTable (
779   IN  LEGACY_BIOS_INSTANCE                *Private,
780   IN EFI_LEGACY_IRQ_ROUTING_ENTRY         *RoutingTable,
781   IN UINTN                                RoutingTableEntries,
782   IN EFI_LEGACY_PIRQ_TABLE_HEADER         *PirqTable,
783   IN UINTN                                PirqTableSize
784   )
785 {
786   EFI_IA32_REGISTER_SET Regs;
787   UINT32                Granularity;
788 
789   //
790   // Copy $PIR table, if it exists.
791   //
792   if (PirqTable != NULL) {
793     Private->LegacyRegion->UnLock (
794                             Private->LegacyRegion,
795                             0xE0000,
796                             0x20000,
797                             &Granularity
798                             );
799 
800     Private->InternalIrqRoutingTable  = RoutingTable;
801     Private->NumberIrqRoutingEntries  = (UINT16) (RoutingTableEntries);
802     ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
803 
804     Regs.X.AX = Legacy16GetTableAddress;
805     Regs.X.CX = (UINT16) PirqTableSize;
806     //
807     // Allocate at F segment according to PCI IRQ Routing Table Specification
808     //
809     Regs.X.BX = (UINT16) 0x1;
810     //
811     // 16-byte boundary alignment requirement according to
812     // PCI IRQ Routing Table Specification
813     //
814     Regs.X.DX = 0x10;
815     Private->LegacyBios.FarCall86 (
816       &Private->LegacyBios,
817       Private->Legacy16CallSegment,
818       Private->Legacy16CallOffset,
819       &Regs,
820       NULL,
821       0
822       );
823 
824     Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
825     if (Regs.X.AX != 0) {
826       DEBUG ((DEBUG_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize));
827     } else {
828       DEBUG ((DEBUG_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer));
829       Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize;
830       CopyMem (
831         (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer,
832         PirqTable,
833         PirqTableSize
834         );
835     }
836 
837     Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
838     Private->LegacyRegion->Lock (
839                              Private->LegacyRegion,
840                              0xE0000,
841                              0x20000,
842                              &Granularity
843                              );
844   }
845 
846   Private->PciInterruptLine = TRUE;
847   mHandleCount              = 0;
848 }
849 
850 /**
851   Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.
852 
853   @param  PciHandle               The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
854 
855 **/
856 VOID
DumpPciHandle(IN EFI_LEGACY_INSTALL_PCI_HANDLER * PciHandle)857 DumpPciHandle (
858   IN EFI_LEGACY_INSTALL_PCI_HANDLER  *PciHandle
859   )
860 {
861   DEBUG ((DEBUG_INFO, "PciBus             - %02x\n", (UINTN)PciHandle->PciBus));
862   DEBUG ((DEBUG_INFO, "PciDeviceFun       - %02x\n", (UINTN)PciHandle->PciDeviceFun));
863   DEBUG ((DEBUG_INFO, "PciSegment         - %02x\n", (UINTN)PciHandle->PciSegment));
864   DEBUG ((DEBUG_INFO, "PciClass           - %02x\n", (UINTN)PciHandle->PciClass));
865   DEBUG ((DEBUG_INFO, "PciSubclass        - %02x\n", (UINTN)PciHandle->PciSubclass));
866   DEBUG ((DEBUG_INFO, "PciInterface       - %02x\n", (UINTN)PciHandle->PciInterface));
867 
868   DEBUG ((DEBUG_INFO, "PrimaryIrq         - %02x\n", (UINTN)PciHandle->PrimaryIrq));
869   DEBUG ((DEBUG_INFO, "PrimaryReserved    - %02x\n", (UINTN)PciHandle->PrimaryReserved));
870   DEBUG ((DEBUG_INFO, "PrimaryControl     - %04x\n", (UINTN)PciHandle->PrimaryControl));
871   DEBUG ((DEBUG_INFO, "PrimaryBase        - %04x\n", (UINTN)PciHandle->PrimaryBase));
872   DEBUG ((DEBUG_INFO, "PrimaryBusMaster   - %04x\n", (UINTN)PciHandle->PrimaryBusMaster));
873 
874   DEBUG ((DEBUG_INFO, "SecondaryIrq       - %02x\n", (UINTN)PciHandle->SecondaryIrq));
875   DEBUG ((DEBUG_INFO, "SecondaryReserved  - %02x\n", (UINTN)PciHandle->SecondaryReserved));
876   DEBUG ((DEBUG_INFO, "SecondaryControl   - %04x\n", (UINTN)PciHandle->SecondaryControl));
877   DEBUG ((DEBUG_INFO, "SecondaryBase      - %04x\n", (UINTN)PciHandle->SecondaryBase));
878   DEBUG ((DEBUG_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster));
879   return;
880 }
881 
882 /**
883   Copy the $PIR table as required.
884 
885   @param  Private                Legacy  BIOS Instance data
886   @param  PciIo                  Pointer to PCI_IO protocol
887   @param  PciIrq                 Pci IRQ number
888   @param  PciConfigHeader        Type00 Pci configuration header
889 
890 **/
891 VOID
InstallLegacyIrqHandler(IN LEGACY_BIOS_INSTANCE * Private,IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 PciIrq,IN PCI_TYPE00 * PciConfigHeader)892 InstallLegacyIrqHandler (
893   IN LEGACY_BIOS_INSTANCE       *Private,
894   IN EFI_PCI_IO_PROTOCOL        *PciIo,
895   IN UINT8                      PciIrq,
896   IN PCI_TYPE00                 *PciConfigHeader
897   )
898 {
899   EFI_IA32_REGISTER_SET     Regs;
900   UINT16                    LegMask;
901   UINTN                     PciSegment;
902   UINTN                     PciBus;
903   UINTN                     PciDevice;
904   UINTN                     PciFunction;
905   EFI_LEGACY_8259_PROTOCOL  *Legacy8259;
906   UINT16                    PrimaryMaster;
907   UINT16                    SecondaryMaster;
908   UINTN                     TempData;
909   UINTN                     RegisterAddress;
910   UINT32                    Granularity;
911 
912   PrimaryMaster   = 0;
913   SecondaryMaster = 0;
914   Legacy8259      = Private->Legacy8259;
915   //
916   // Disable interrupt in PIC, in case shared, to prevent an
917   // interrupt from occurring.
918   //
919   Legacy8259->GetMask (
920                 Legacy8259,
921                 &LegMask,
922                 NULL,
923                 NULL,
924                 NULL
925                 );
926 
927   LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq));
928 
929   Legacy8259->SetMask (
930                 Legacy8259,
931                 &LegMask,
932                 NULL,
933                 NULL,
934                 NULL
935                 );
936 
937   PciIo->GetLocation (
938           PciIo,
939           &PciSegment,
940           &PciBus,
941           &PciDevice,
942           &PciFunction
943           );
944   Private->IntThunk->PciHandler.PciBus              = (UINT8) PciBus;
945   Private->IntThunk->PciHandler.PciDeviceFun        = (UINT8) ((PciDevice << 3) + PciFunction);
946   Private->IntThunk->PciHandler.PciSegment          = (UINT8) PciSegment;
947   Private->IntThunk->PciHandler.PciClass            = PciConfigHeader->Hdr.ClassCode[2];
948   Private->IntThunk->PciHandler.PciSubclass         = PciConfigHeader->Hdr.ClassCode[1];
949   Private->IntThunk->PciHandler.PciInterface        = PciConfigHeader->Hdr.ClassCode[0];
950 
951   //
952   // Use native mode base address registers in two cases:
953   // 1. Programming Interface (PI) register indicates Primary Controller is
954   // in native mode OR
955   // 2. PCI device Sub Class Code is not IDE
956   //
957   Private->IntThunk->PciHandler.PrimaryBusMaster  = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc);
958   if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
959     Private->IntThunk->PciHandler.PrimaryIrq      = PciIrq;
960     Private->IntThunk->PciHandler.PrimaryBase     = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc);
961     Private->IntThunk->PciHandler.PrimaryControl  = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2);
962   } else {
963     Private->IntThunk->PciHandler.PrimaryIrq      = 14;
964     Private->IntThunk->PciHandler.PrimaryBase     = 0x1f0;
965     Private->IntThunk->PciHandler.PrimaryControl  = 0x3f6;
966   }
967   //
968   // Secondary controller data
969   //
970   if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) {
971     Private->IntThunk->PciHandler.SecondaryBusMaster  = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8);
972     PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2);
973     SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2);
974 
975     //
976     // Clear pending interrupts in Bus Master registers
977     //
978     IoWrite16 (PrimaryMaster, 0x04);
979     IoWrite16 (SecondaryMaster, 0x04);
980 
981   }
982 
983   //
984   // Use native mode base address registers in two cases:
985   // 1. Programming Interface (PI) register indicates Secondary Controller is
986   // in native mode OR
987   // 2. PCI device Sub Class Code is not IDE
988   //
989   if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
990     Private->IntThunk->PciHandler.SecondaryIrq      = PciIrq;
991     Private->IntThunk->PciHandler.SecondaryBase     = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc);
992     Private->IntThunk->PciHandler.SecondaryControl  = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2);
993   } else {
994 
995     Private->IntThunk->PciHandler.SecondaryIrq      = 15;
996     Private->IntThunk->PciHandler.SecondaryBase     = 0x170;
997     Private->IntThunk->PciHandler.SecondaryControl  = 0x376;
998   }
999 
1000   //
1001   // Clear pending interrupts in IDE Command Block Status reg before we
1002   // Thunk to CSM16 below.  Don't want a pending Interrupt before we
1003   // install the handlers as wierd corruption would occur and hang system.
1004   //
1005   //
1006   // Read IDE CMD blk status reg to clear out any pending interrupts.
1007   // Do here for Primary and Secondary IDE channels
1008   //
1009   RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07;
1010   IoRead8 (RegisterAddress);
1011   RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07;
1012   IoRead8 (RegisterAddress);
1013 
1014   Private->IntThunk->PciHandler.PrimaryReserved   = 0;
1015   Private->IntThunk->PciHandler.SecondaryReserved = 0;
1016   Private->LegacyRegion->UnLock (
1017                            Private->LegacyRegion,
1018                            0xE0000,
1019                            0x20000,
1020                            &Granularity
1021                            );
1022 
1023   Regs.X.AX = Legacy16InstallPciHandler;
1024   TempData  = (UINTN) &Private->IntThunk->PciHandler;
1025   Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
1026   Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
1027 
1028   DumpPciHandle (&Private->IntThunk->PciHandler);
1029 
1030   Private->LegacyBios.FarCall86 (
1031     &Private->LegacyBios,
1032     Private->Legacy16CallSegment,
1033     Private->Legacy16CallOffset,
1034     &Regs,
1035     NULL,
1036     0
1037     );
1038 
1039   Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
1040   Private->LegacyRegion->Lock (
1041                            Private->LegacyRegion,
1042                            0xE0000,
1043                            0x20000,
1044                            &Granularity
1045                            );
1046 
1047 }
1048 
1049 
1050 /**
1051   Program the interrupt routing register in all the PCI devices. On a PC AT system
1052   this register contains the 8259 IRQ vector that matches its PCI interrupt.
1053 
1054   @param  Private                Legacy  BIOS Instance data
1055 
1056   @retval EFI_SUCCESS            Succeed.
1057   @retval EFI_ALREADY_STARTED    All PCI devices have been processed.
1058 
1059 **/
1060 EFI_STATUS
PciProgramAllInterruptLineRegisters(IN LEGACY_BIOS_INSTANCE * Private)1061 PciProgramAllInterruptLineRegisters (
1062   IN  LEGACY_BIOS_INSTANCE      *Private
1063   )
1064 {
1065   EFI_STATUS                        Status;
1066   EFI_PCI_IO_PROTOCOL               *PciIo;
1067   EFI_LEGACY_8259_PROTOCOL          *Legacy8259;
1068   EFI_LEGACY_INTERRUPT_PROTOCOL     *LegacyInterrupt;
1069   EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
1070   UINT8                             InterruptPin;
1071   UINTN                             Index;
1072   UINTN                             HandleCount;
1073   EFI_HANDLE                        *HandleBuffer;
1074   UINTN                             MassStorageHandleCount;
1075   EFI_HANDLE                        *MassStorageHandleBuffer;
1076   UINTN                             MassStorageHandleIndex;
1077   UINT8                             PciIrq;
1078   UINT16                            Command;
1079   UINTN                             PciSegment;
1080   UINTN                             PciBus;
1081   UINTN                             PciDevice;
1082   UINTN                             PciFunction;
1083   EFI_LEGACY_IRQ_ROUTING_ENTRY      *RoutingTable;
1084   UINTN                             RoutingTableEntries;
1085   UINT16                            LegMask;
1086   UINT16                            LegEdgeLevel;
1087   PCI_TYPE00                        PciConfigHeader;
1088   EFI_LEGACY_PIRQ_TABLE_HEADER      *PirqTable;
1089   UINTN                             PirqTableSize;
1090   UINTN                             Flags;
1091   HDD_INFO                          *HddInfo;
1092   UINT64                            Supports;
1093 
1094   //
1095   // Note - This routine use to return immediately if Private->PciInterruptLine
1096   //        was true. Routine changed since resets etc can cause not all
1097   //        PciIo protocols to be registered the first time through.
1098   // New algorithm is to do the copy $PIR table on first pass and save
1099   // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives
1100   // a larger handle count then proceed with body of function else return
1101   // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.
1102   // If zero then function unprogrammed else skip function.
1103   //
1104   Legacy8259          = Private->Legacy8259;
1105   LegacyInterrupt     = Private->LegacyInterrupt;
1106   LegacyBiosPlatform  = Private->LegacyBiosPlatform;
1107 
1108   LegacyBiosPlatform->GetRoutingTable (
1109                         Private->LegacyBiosPlatform,
1110                         (VOID *) &RoutingTable,
1111                         &RoutingTableEntries,
1112                         (VOID *) &PirqTable,
1113                         &PirqTableSize,
1114                         NULL,
1115                         NULL
1116                         );
1117   CreateBridgeTable (RoutingTable, RoutingTableEntries);
1118 
1119   if (!Private->PciInterruptLine) {
1120     CopyPirqTable (
1121       Private,
1122       RoutingTable,
1123       RoutingTableEntries,
1124       PirqTable,
1125       PirqTableSize
1126       );
1127   }
1128 
1129   Status = gBS->LocateHandleBuffer (
1130                   ByProtocol,
1131                   &gEfiPciIoProtocolGuid,
1132                   NULL,
1133                   &HandleCount,
1134                   &HandleBuffer
1135                   );
1136   if (EFI_ERROR (Status)) {
1137     return EFI_NOT_FOUND;
1138   }
1139   if (HandleCount == mHandleCount) {
1140     FreePool (HandleBuffer);
1141     return EFI_ALREADY_STARTED;
1142   }
1143 
1144   if (mHandleCount == 0x00) {
1145     mHandleCount = HandleCount;
1146   }
1147 
1148   for (Index = 0; Index < HandleCount; Index++) {
1149     //
1150     // If VGA then only do VGA to allow drives fore time to spin up
1151     // otherwise assign PCI IRQs to all potential devices.
1152     //
1153     if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) {
1154       continue;
1155     } else {
1156       //
1157       // Force code to go through all handles next time called if video.
1158       // This will catch case where HandleCount doesn't change but want
1159       //  to get drive info etc.
1160       //
1161       mHandleCount = 0x00;
1162     }
1163 
1164     Status = gBS->HandleProtocol (
1165                     HandleBuffer[Index],
1166                     &gEfiPciIoProtocolGuid,
1167                     (VOID **) &PciIo
1168                     );
1169     ASSERT_EFI_ERROR (Status);
1170 
1171     //
1172     // Test whether the device can be enabled or not.
1173     // If it can't be enabled, then just skip it to avoid further operation.
1174     //
1175     PciIo->Pci.Read (
1176                  PciIo,
1177                  EfiPciIoWidthUint32,
1178                  0,
1179                  sizeof (PciConfigHeader) / sizeof (UINT32),
1180                  &PciConfigHeader
1181                  );
1182     Command = PciConfigHeader.Hdr.Command;
1183 
1184     //
1185     // Note PciIo->Attributes does not program the PCI command register
1186     //
1187     Status = PciIo->Attributes (
1188                       PciIo,
1189                       EfiPciIoAttributeOperationSupported,
1190                       0,
1191                       &Supports
1192                       );
1193     if (!EFI_ERROR (Status)) {
1194       Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
1195       Status = PciIo->Attributes (
1196                         PciIo,
1197                         EfiPciIoAttributeOperationEnable,
1198                         Supports,
1199                         NULL
1200                         );
1201     }
1202     PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command);
1203 
1204     if (EFI_ERROR (Status)) {
1205       continue;
1206     }
1207 
1208     InterruptPin = PciConfigHeader.Device.InterruptPin;
1209 
1210     if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) {
1211       PciIo->GetLocation (
1212                PciIo,
1213                &PciSegment,
1214                &PciBus,
1215                &PciDevice,
1216                &PciFunction
1217                );
1218       //
1219       // Translate PIRQ index back thru busses to slot bus with InterruptPin
1220       // zero based
1221       //
1222       InterruptPin -= 1;
1223 
1224       Status = GetBaseBus (
1225                  Private,
1226                  PciBus,
1227                  PciDevice,
1228                  RoutingTable,
1229                  RoutingTableEntries
1230                  );
1231 
1232       if (Status == EFI_NOT_FOUND) {
1233         TranslateBusPirq (
1234           Private,
1235           &PciBus,
1236           &PciDevice,
1237           &PciFunction,
1238           &InterruptPin
1239           );
1240       }
1241       //
1242       // Translate InterruptPin(0-3) into PIRQ
1243       //
1244       Status = LegacyBiosPlatform->TranslatePirq (
1245                                      LegacyBiosPlatform,
1246                                      PciBus,
1247                                      (PciDevice << 3),
1248                                      PciFunction,
1249                                      &InterruptPin,
1250                                      &PciIrq
1251                                      );
1252       //
1253       // TranslatePirq() should never fail or we are in trouble
1254       // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect
1255       //
1256       if (EFI_ERROR (Status)) {
1257         DEBUG ((DEBUG_ERROR, "Translate Pirq Failed - Status = %r\n ", Status));
1258         continue;
1259       }
1260 
1261       LegacyInterrupt->WritePirq (
1262                          LegacyInterrupt,
1263                          InterruptPin,
1264                          PciIrq
1265                          );
1266 
1267       //
1268       // Check if device has an OPROM associated with it.
1269       // If not invoke special 16-bit function, to allow 16-bit
1270       // code to install an interrupt handler.
1271       //
1272       Status = LegacyBiosCheckPciRom (
1273                  &Private->LegacyBios,
1274                  HandleBuffer[Index],
1275                  NULL,
1276                  NULL,
1277                  &Flags
1278                  );
1279       if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) {
1280         //
1281         // Device has no OPROM associated with it and is a mass storage
1282         // device. It needs to have an PCI IRQ handler installed. To
1283         // correctly install the handler we need to insure device is
1284         // connected. The device may just have register itself but not
1285         // been connected. Re-read PCI config space after as it can
1286         // change
1287         //
1288         //
1289         // Get IDE Handle. If matches handle then skip ConnectController
1290         // since ConnectController may force native mode and we don't
1291         // want that for primary IDE controller
1292         //
1293         MassStorageHandleCount = 0;
1294         MassStorageHandleBuffer = NULL;
1295         LegacyBiosPlatform->GetPlatformHandle (
1296                               Private->LegacyBiosPlatform,
1297                               EfiGetPlatformIdeHandle,
1298                               0,
1299                               &MassStorageHandleBuffer,
1300                               &MassStorageHandleCount,
1301                               NULL
1302                               );
1303 
1304         HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
1305 
1306         LegacyBiosBuildIdeData (Private, &HddInfo, 0);
1307         PciIo->Pci.Read (
1308                      PciIo,
1309                      EfiPciIoWidthUint32,
1310                      0,
1311                      sizeof (PciConfigHeader) / sizeof (UINT32),
1312                      &PciConfigHeader
1313                      );
1314 
1315         for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) {
1316           if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) {
1317             //
1318             // InstallLegacyIrqHandler according to Platform requirement
1319             //
1320             InstallLegacyIrqHandler (
1321               Private,
1322               PciIo,
1323               PciIrq,
1324               &PciConfigHeader
1325               );
1326             break;
1327           }
1328         }
1329       }
1330       //
1331       // Write InterruptPin and enable 8259.
1332       //
1333       PciIo->Pci.Write (
1334                    PciIo,
1335                    EfiPciIoWidthUint8,
1336                    0x3c,
1337                    1,
1338                    &PciIrq
1339                    );
1340       Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq));
1341 
1342       Legacy8259->GetMask (
1343                     Legacy8259,
1344                     &LegMask,
1345                     &LegEdgeLevel,
1346                     NULL,
1347                     NULL
1348                     );
1349 
1350       LegMask       = (UINT16) (LegMask & (UINT16)~(1 << PciIrq));
1351       LegEdgeLevel  = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq));
1352       Legacy8259->SetMask (
1353                     Legacy8259,
1354                     &LegMask,
1355                     &LegEdgeLevel,
1356                     NULL,
1357                     NULL
1358                     );
1359     }
1360   }
1361   FreePool (HandleBuffer);
1362   return EFI_SUCCESS;
1363 }
1364 
1365 
1366 /**
1367   Find & verify PnP Expansion header in ROM image
1368 
1369   @param  Private                Protocol instance pointer.
1370   @param  FirstHeader            1 = Find first header, 0 = Find successive headers
1371   @param  PnpPtr                 Input Rom start if FirstHeader =1, Current Header
1372                                  otherwise Output Next header, if it exists
1373 
1374   @retval EFI_SUCCESS            Next Header found at BasePnpPtr
1375   @retval EFI_NOT_FOUND          No more headers
1376 
1377 **/
1378 EFI_STATUS
FindNextPnpExpansionHeader(IN LEGACY_BIOS_INSTANCE * Private,IN BOOLEAN FirstHeader,IN OUT LEGACY_PNP_EXPANSION_HEADER ** PnpPtr)1379 FindNextPnpExpansionHeader (
1380   IN  LEGACY_BIOS_INSTANCE             *Private,
1381   IN BOOLEAN                           FirstHeader,
1382   IN OUT LEGACY_PNP_EXPANSION_HEADER   **PnpPtr
1383 
1384   )
1385 {
1386   UINTN                       TempData;
1387   LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr;
1388   LocalPnpPtr = *PnpPtr;
1389   if (FirstHeader == FIRST_INSTANCE) {
1390     mBasePnpPtr     = LocalPnpPtr;
1391     mBbsRomSegment  = (UINT16) ((UINTN) mBasePnpPtr >> 4);
1392     //
1393     // Offset 0x1a gives offset to PnP expansion header for the first
1394     // instance, there after the structure gives the offset to the next
1395     // structure
1396     //
1397     LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a);
1398     TempData    = (*((UINT16 *) LocalPnpPtr));
1399   } else {
1400     TempData = (UINT16) LocalPnpPtr->NextHeader;
1401   }
1402 
1403   LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData));
1404 
1405   //
1406   // Search for PnP table in Shadowed ROM
1407   //
1408   *PnpPtr = LocalPnpPtr;
1409   if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) {
1410     return EFI_SUCCESS;
1411   } else {
1412     return EFI_NOT_FOUND;
1413   }
1414 }
1415 
1416 
1417 /**
1418   Update list of Bev or BCV table entries.
1419 
1420   @param  Private                Protocol instance pointer.
1421   @param  RomStart               Table of ROM start address in RAM/ROM. PciIo  _
1422                                  Handle to PCI IO for this device
1423   @param  PciIo                  Instance of PCI I/O Protocol
1424 
1425   @retval EFI_SUCCESS            Always should succeed.
1426 
1427 **/
1428 EFI_STATUS
UpdateBevBcvTable(IN LEGACY_BIOS_INSTANCE * Private,IN EFI_LEGACY_EXPANSION_ROM_HEADER * RomStart,IN EFI_PCI_IO_PROTOCOL * PciIo)1429 UpdateBevBcvTable (
1430   IN  LEGACY_BIOS_INSTANCE             *Private,
1431   IN  EFI_LEGACY_EXPANSION_ROM_HEADER  *RomStart,
1432   IN  EFI_PCI_IO_PROTOCOL              *PciIo
1433   )
1434 {
1435   VOID                            *RomEnd;
1436   BBS_TABLE                       *BbsTable;
1437   UINTN                           BbsIndex;
1438   EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr;
1439   LEGACY_PNP_EXPANSION_HEADER     *PnpPtr;
1440   BOOLEAN                         Instance;
1441   EFI_STATUS                      Status;
1442   UINTN                           Segment;
1443   UINTN                           Bus;
1444   UINTN                           Device;
1445   UINTN                           Function;
1446   UINT8                           Class;
1447   UINT16                          DeviceType;
1448   Segment     = 0;
1449   Bus         = 0;
1450   Device      = 0;
1451   Function    = 0;
1452   Class       = 0;
1453   DeviceType  = BBS_UNKNOWN;
1454 
1455   //
1456   // Skip floppy and 2*onboard IDE controller entries(Master/Slave per
1457   // controller).
1458   //
1459   BbsIndex  = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
1460 
1461   BbsTable  = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable;
1462   PnpPtr    = (LEGACY_PNP_EXPANSION_HEADER *) RomStart;
1463   PciPtr    = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart;
1464 
1465   RomEnd    = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr);
1466   Instance  = FIRST_INSTANCE;
1467   //
1468   // OPROMs like PXE may not be tied to a piece of hardware and thus
1469   // don't have a PciIo associated with them
1470   //
1471   if (PciIo != NULL) {
1472     PciIo->GetLocation (
1473              PciIo,
1474              &Segment,
1475              &Bus,
1476              &Device,
1477              &Function
1478              );
1479     PciIo->Pci.Read (
1480                  PciIo,
1481                  EfiPciIoWidthUint8,
1482                  0x0b,
1483                  1,
1484                  &Class
1485                  );
1486 
1487     if (Class == PCI_CLASS_MASS_STORAGE) {
1488       DeviceType = BBS_HARDDISK;
1489     } else {
1490       if (Class == PCI_CLASS_NETWORK) {
1491         DeviceType = BBS_EMBED_NETWORK;
1492       }
1493     }
1494   }
1495 
1496   while (TRUE) {
1497     Status    = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr);
1498     Instance  = NOT_FIRST_INSTANCE;
1499     if (EFI_ERROR (Status)) {
1500       break;
1501     }
1502     //
1503     // There can be additional $PnP headers within the OPROM.
1504     // Example: SCSI can have one per drive.
1505     //
1506     BbsTable[BbsIndex].BootPriority             = BBS_UNPRIORITIZED_ENTRY;
1507     BbsTable[BbsIndex].DeviceType               = DeviceType;
1508     BbsTable[BbsIndex].Bus                      = (UINT32) Bus;
1509     BbsTable[BbsIndex].Device                   = (UINT32) Device;
1510     BbsTable[BbsIndex].Function                 = (UINT32) Function;
1511     BbsTable[BbsIndex].StatusFlags.OldPosition  = 0;
1512     BbsTable[BbsIndex].StatusFlags.Reserved1    = 0;
1513     BbsTable[BbsIndex].StatusFlags.Enabled      = 0;
1514     BbsTable[BbsIndex].StatusFlags.Failed       = 0;
1515     BbsTable[BbsIndex].StatusFlags.MediaPresent = 0;
1516     BbsTable[BbsIndex].StatusFlags.Reserved2    = 0;
1517     BbsTable[BbsIndex].Class                    = PnpPtr->Class;
1518     BbsTable[BbsIndex].SubClass                 = PnpPtr->SubClass;
1519     BbsTable[BbsIndex].DescStringOffset         = PnpPtr->ProductNamePointer;
1520     BbsTable[BbsIndex].DescStringSegment        = mBbsRomSegment;
1521     BbsTable[BbsIndex].MfgStringOffset          = PnpPtr->MfgPointer;
1522     BbsTable[BbsIndex].MfgStringSegment         = mBbsRomSegment;
1523     BbsTable[BbsIndex].BootHandlerSegment       = mBbsRomSegment;
1524 
1525     //
1526     // Have seen case where PXE base code have PnP expansion ROM
1527     // header but no Bcv or Bev vectors.
1528     //
1529     if (PnpPtr->Bcv != 0) {
1530       BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv;
1531       ++BbsIndex;
1532     }
1533 
1534     if (PnpPtr->Bev != 0) {
1535       BbsTable[BbsIndex].BootHandlerOffset  = PnpPtr->Bev;
1536       BbsTable[BbsIndex].DeviceType         = BBS_BEV_DEVICE;
1537       ++BbsIndex;
1538     }
1539 
1540     if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) {
1541       break;
1542     }
1543   }
1544 
1545   BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY;
1546   Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex;
1547   return EFI_SUCCESS;
1548 }
1549 
1550 
1551 /**
1552   Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
1553   to chose the order. Skip any devices that have already have legacy
1554   BIOS run.
1555 
1556   @param  Private                Protocol instance pointer.
1557 
1558   @retval EFI_SUCCESS            Succeed.
1559   @retval EFI_UNSUPPORTED        Cannot get VGA device handle.
1560 
1561 **/
1562 EFI_STATUS
PciShadowRoms(IN LEGACY_BIOS_INSTANCE * Private)1563 PciShadowRoms (
1564   IN  LEGACY_BIOS_INSTANCE      *Private
1565   )
1566 {
1567   EFI_STATUS                        Status;
1568   EFI_PCI_IO_PROTOCOL               *PciIo;
1569   PCI_TYPE00                        Pci;
1570   UINTN                             Index;
1571   UINTN                             HandleCount;
1572   EFI_HANDLE                        *HandleBuffer;
1573   EFI_HANDLE                        VgaHandle;
1574   EFI_HANDLE                        FirstHandle;
1575   VOID                              **RomStart;
1576   UINTN                             Flags;
1577   PCI_TYPE00                        PciConfigHeader;
1578   UINT16                            *Command;
1579   UINT64                            Supports;
1580 
1581   //
1582   // Make the VGA device first
1583   //
1584   Status = Private->LegacyBiosPlatform->GetPlatformHandle (
1585                                           Private->LegacyBiosPlatform,
1586                                           EfiGetPlatformVgaHandle,
1587                                           0,
1588                                           &HandleBuffer,
1589                                           &HandleCount,
1590                                           NULL
1591                                           );
1592   if (EFI_ERROR (Status)) {
1593     return EFI_UNSUPPORTED;
1594   }
1595 
1596   VgaHandle = HandleBuffer[0];
1597 
1598   Status = gBS->LocateHandleBuffer (
1599                   ByProtocol,
1600                   &gEfiPciIoProtocolGuid,
1601                   NULL,
1602                   &HandleCount,
1603                   &HandleBuffer
1604                   );
1605 
1606   if (EFI_ERROR (Status)) {
1607     return Status;
1608   }
1609   //
1610   // Place the VGA handle as first.
1611   //
1612   for (Index = 0; Index < HandleCount; Index++) {
1613     if (HandleBuffer[Index] == VgaHandle) {
1614       FirstHandle         = HandleBuffer[0];
1615       HandleBuffer[0]     = HandleBuffer[Index];
1616       HandleBuffer[Index] = FirstHandle;
1617       break;
1618     }
1619   }
1620   //
1621   // Allocate memory to save Command WORD from each device. We do this
1622   // to restore devices to same state as EFI after switching to legacy.
1623   //
1624   Command = (UINT16 *) AllocatePool (
1625                          sizeof (UINT16) * (HandleCount + 1)
1626                          );
1627   if (NULL == Command) {
1628     FreePool (HandleBuffer);
1629     return EFI_OUT_OF_RESOURCES;
1630   }
1631   //
1632   // Disconnect all EFI devices first. This covers cases where alegacy BIOS
1633   // may control multiple PCI devices.
1634   //
1635   for (Index = 0; Index < HandleCount; Index++) {
1636 
1637     Status = gBS->HandleProtocol (
1638                     HandleBuffer[Index],
1639                     &gEfiPciIoProtocolGuid,
1640                     (VOID **) &PciIo
1641                     );
1642     ASSERT_EFI_ERROR (Status);
1643 
1644     //
1645     // Save command register for "connect" loop
1646     //
1647     PciIo->Pci.Read (
1648                  PciIo,
1649                  EfiPciIoWidthUint32,
1650                  0,
1651                  sizeof (PciConfigHeader) / sizeof (UINT32),
1652                  &PciConfigHeader
1653                  );
1654     Command[Index] = PciConfigHeader.Hdr.Command;
1655     //
1656     // Skip any device that already has a legacy ROM run
1657     //
1658     Status = IsLegacyRom (HandleBuffer[Index]);
1659     if (!EFI_ERROR (Status)) {
1660       continue;
1661     }
1662     //
1663     // Stop EFI Drivers with oprom.
1664     //
1665     gBS->DisconnectController (
1666            HandleBuffer[Index],
1667            NULL,
1668            NULL
1669            );
1670   }
1671   //
1672   // For every device that has not had a legacy ROM started. Start a legacy ROM.
1673   //
1674   for (Index = 0; Index < HandleCount; Index++) {
1675 
1676     Status = gBS->HandleProtocol (
1677                     HandleBuffer[Index],
1678                     &gEfiPciIoProtocolGuid,
1679                     (VOID **) &PciIo
1680                     );
1681 
1682     ASSERT_EFI_ERROR (Status);
1683 
1684     //
1685     // Here make sure if one VGA have been shadowed,
1686     // then wil not shadowed another one.
1687     //
1688     PciIo->Pci.Read (
1689                  PciIo,
1690                  EfiPciIoWidthUint32,
1691                  0,
1692                  sizeof (Pci) / sizeof (UINT32),
1693                  &Pci
1694                  );
1695 
1696     //
1697     // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices,
1698     // one will work in legacy mode (OPROM will be given control) and
1699     // other Video devices will work in native mode (OS driver will handle these devices).
1700     //
1701     if (IS_PCI_DISPLAY (&Pci) && Index != 0) {
1702       continue;
1703     }
1704     //
1705     // Skip any device that already has a legacy ROM run
1706     //
1707     Status = IsLegacyRom (HandleBuffer[Index]);
1708     if (!EFI_ERROR (Status)) {
1709       continue;
1710     }
1711 
1712     //
1713     // If legacy VBIOS Oprom has not been dispatched before, install legacy VBIOS here.
1714     //
1715     if (IS_PCI_DISPLAY (&Pci) && Index == 0) {
1716       Status = LegacyBiosInstallVgaRom (Private);
1717       //
1718       // A return status of EFI_NOT_FOUND is considered valid (No EFI
1719       // driver is controlling video).
1720       //
1721       ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND));
1722       continue;
1723     }
1724 
1725     //
1726     // Install legacy ROM
1727     //
1728     Status = LegacyBiosInstallPciRom (
1729                &Private->LegacyBios,
1730                HandleBuffer[Index],
1731                NULL,
1732                &Flags,
1733                NULL,
1734                NULL,
1735                (VOID **) &RomStart,
1736                NULL
1737                );
1738     if (EFI_ERROR (Status)) {
1739       if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) {
1740         continue;
1741       }
1742     }
1743     //
1744     // Restore Command register so legacy has same devices enabled or disabled
1745     // as EFI.
1746     // If Flags = NO_ROM use command register as is. This covers the
1747     //            following cases:
1748     //              Device has no ROMs associated with it.
1749     //              Device has ROM associated with it but was already
1750     //              installed.
1751     //          = ROM_FOUND but not VALID_LEGACY_ROM, disable it.
1752     //          = ROM_FOUND and VALID_LEGACY_ROM, enable it.
1753     //
1754     if ((Flags & ROM_FOUND) == ROM_FOUND) {
1755       if ((Flags & VALID_LEGACY_ROM) == 0) {
1756         Command[Index] = 0;
1757       } else {
1758         //
1759         // For several VGAs, only one of them can be enabled.
1760         //
1761         Status = PciIo->Attributes (
1762                           PciIo,
1763                           EfiPciIoAttributeOperationSupported,
1764                           0,
1765                           &Supports
1766                           );
1767         if (!EFI_ERROR (Status)) {
1768           Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
1769           Status = PciIo->Attributes (
1770                             PciIo,
1771                             EfiPciIoAttributeOperationEnable,
1772                             Supports,
1773                             NULL
1774                             );
1775         }
1776         if (!EFI_ERROR (Status)) {
1777           Command[Index] = 0x1f;
1778         }
1779       }
1780     }
1781 
1782     PciIo->Pci.Write (
1783                  PciIo,
1784                  EfiPciIoWidthUint16,
1785                  0x04,
1786                  1,
1787                  &Command[Index]
1788                  );
1789   }
1790 
1791   FreePool (Command);
1792   FreePool (HandleBuffer);
1793   return EFI_SUCCESS;
1794 }
1795 
1796 
1797 /**
1798   Test to see if a legacy PCI ROM exists for this device. Optionally return
1799   the Legacy ROM instance for this PCI device.
1800 
1801   @param  This                   Protocol instance pointer.
1802   @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will
1803                                  be loaded
1804   @param  RomImage               Return the legacy PCI ROM for this device
1805   @param  RomSize                Size of ROM Image
1806   @param  Flags                  Indicates if ROM found and if PC-AT.
1807 
1808   @retval EFI_SUCCESS            Legacy Option ROM available for this device
1809   @retval EFI_UNSUPPORTED        Legacy Option ROM not supported.
1810 
1811 **/
1812 EFI_STATUS
1813 EFIAPI
LegacyBiosCheckPciRom(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN EFI_HANDLE PciHandle,OUT VOID ** RomImage,OPTIONAL OUT UINTN * RomSize,OPTIONAL OUT UINTN * Flags)1814 LegacyBiosCheckPciRom (
1815   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
1816   IN  EFI_HANDLE                        PciHandle,
1817   OUT VOID                              **RomImage, OPTIONAL
1818   OUT UINTN                             *RomSize, OPTIONAL
1819   OUT UINTN                             *Flags
1820   )
1821 {
1822   return LegacyBiosCheckPciRomEx (
1823            This,
1824            PciHandle,
1825            RomImage,
1826            RomSize,
1827            NULL,
1828            Flags,
1829            NULL,
1830            NULL
1831            );
1832 
1833 }
1834 
1835 /**
1836 
1837   Routine Description:
1838     Test to see if a legacy PCI ROM exists for this device. Optionally return
1839     the Legacy ROM instance for this PCI device.
1840 
1841     @param[in] This          Protocol instance pointer.
1842     @param[in] PciHandle               The PCI PC-AT OPROM from this devices ROM BAR will be loaded
1843     @param[out] RomImage               Return the legacy PCI ROM for this device
1844     @param[out] RomSize                Size of ROM Image
1845     @param[out] RuntimeImageLength     Runtime size of ROM Image
1846     @param[out] Flags                  Indicates if ROM found and if PC-AT.
1847     @param[out] OpromRevision          Revision of the PCI Rom
1848     @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
1849 
1850     @return EFI_SUCCESS            Legacy Option ROM available for this device
1851     @return EFI_ALREADY_STARTED    This device is already managed by its Oprom
1852     @return EFI_UNSUPPORTED        Legacy Option ROM not supported.
1853 
1854 **/
1855 EFI_STATUS
LegacyBiosCheckPciRomEx(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN EFI_HANDLE PciHandle,OUT VOID ** RomImage,OPTIONAL OUT UINTN * RomSize,OPTIONAL OUT UINTN * RuntimeImageLength,OPTIONAL OUT UINTN * Flags,OPTIONAL OUT UINT8 * OpromRevision,OPTIONAL OUT VOID ** ConfigUtilityCodeHeader OPTIONAL)1856 LegacyBiosCheckPciRomEx (
1857   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
1858   IN  EFI_HANDLE                        PciHandle,
1859   OUT VOID                              **RomImage, OPTIONAL
1860   OUT UINTN                             *RomSize, OPTIONAL
1861   OUT UINTN                             *RuntimeImageLength, OPTIONAL
1862   OUT UINTN                             *Flags, OPTIONAL
1863   OUT UINT8                             *OpromRevision, OPTIONAL
1864   OUT VOID                              **ConfigUtilityCodeHeader OPTIONAL
1865   )
1866 {
1867   EFI_STATUS                      Status;
1868   LEGACY_BIOS_INSTANCE            *Private;
1869   EFI_PCI_IO_PROTOCOL             *PciIo;
1870   UINTN                           LocalRomSize;
1871   VOID                            *LocalRomImage;
1872   PCI_TYPE00                      PciConfigHeader;
1873   VOID                            *LocalConfigUtilityCodeHeader;
1874 
1875   LocalConfigUtilityCodeHeader = NULL;
1876   *Flags = NO_ROM;
1877   Status = gBS->HandleProtocol (
1878                   PciHandle,
1879                   &gEfiPciIoProtocolGuid,
1880                   (VOID **) &PciIo
1881                   );
1882   if (EFI_ERROR (Status)) {
1883     return EFI_UNSUPPORTED;
1884   }
1885 
1886   //
1887   // See if the option ROM for PciHandle has already been executed
1888   //
1889   Status = IsLegacyRom (PciHandle);
1890   if (!EFI_ERROR (Status)) {
1891     *Flags |= (UINTN)(ROM_FOUND | VALID_LEGACY_ROM);
1892     return EFI_SUCCESS;
1893   }
1894   //
1895   // Check for PCI ROM Bar
1896   //
1897   LocalRomSize  = (UINTN) PciIo->RomSize;
1898   LocalRomImage = PciIo->RomImage;
1899   if (LocalRomSize != 0) {
1900     *Flags |= ROM_FOUND;
1901   }
1902 
1903   //
1904   // PCI specification states you should check VendorId and Device Id.
1905   //
1906   PciIo->Pci.Read (
1907                PciIo,
1908                EfiPciIoWidthUint32,
1909                0,
1910                sizeof (PciConfigHeader) / sizeof (UINT32),
1911                &PciConfigHeader
1912                );
1913 
1914   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
1915   Status = GetPciLegacyRom (
1916              Private->Csm16PciInterfaceVersion,
1917              PciConfigHeader.Hdr.VendorId,
1918              PciConfigHeader.Hdr.DeviceId,
1919              &LocalRomImage,
1920              &LocalRomSize,
1921              RuntimeImageLength,
1922              OpromRevision,
1923              &LocalConfigUtilityCodeHeader
1924              );
1925   if (EFI_ERROR (Status)) {
1926     return EFI_UNSUPPORTED;
1927   }
1928 
1929   *Flags |= VALID_LEGACY_ROM;
1930 
1931   //
1932   // See if Configuration Utility Code Header valid
1933   //
1934   if (LocalConfigUtilityCodeHeader != NULL) {
1935     *Flags |= ROM_WITH_CONFIG;
1936   }
1937 
1938   if (ConfigUtilityCodeHeader != NULL) {
1939     *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader;
1940   }
1941 
1942   if (RomImage != NULL) {
1943     *RomImage = LocalRomImage;
1944   }
1945 
1946   if (RomSize != NULL) {
1947     *RomSize = LocalRomSize;
1948   }
1949 
1950   return EFI_SUCCESS;
1951 }
1952 
1953 /**
1954   Load a legacy PC-AT OPROM on the PciHandle device. Return information
1955   about how many disks were added by the OPROM and the shadow address and
1956   size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
1957 
1958   @retval EFI_SUCCESS   Legacy ROM loaded for this device
1959   @retval EFI_NOT_FOUND No PS2 Keyboard found
1960 
1961 **/
1962 EFI_STATUS
EnablePs2Keyboard(VOID)1963 EnablePs2Keyboard (
1964   VOID
1965   )
1966 {
1967   EFI_STATUS                          Status;
1968   EFI_HANDLE                          *HandleBuffer;
1969   UINTN                               HandleCount;
1970   EFI_ISA_IO_PROTOCOL                 *IsaIo;
1971   UINTN                               Index;
1972 
1973   //
1974   // Get SimpleTextIn and find PS2 controller
1975   //
1976   Status = gBS->LocateHandleBuffer (
1977                   ByProtocol,
1978                   &gEfiSimpleTextInProtocolGuid,
1979                   NULL,
1980                   &HandleCount,
1981                   &HandleBuffer
1982                   );
1983   if (EFI_ERROR (Status)) {
1984     return EFI_NOT_FOUND;
1985   }
1986   for (Index = 0; Index < HandleCount; Index++) {
1987     //
1988     // Open the IO Abstraction(s) needed to perform the supported test
1989     //
1990     Status = gBS->OpenProtocol (
1991                     HandleBuffer[Index],
1992                     &gEfiIsaIoProtocolGuid,
1993                     (VOID **) &IsaIo,
1994                     NULL,
1995                     HandleBuffer[Index],
1996                     EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
1997                     );
1998 
1999     if (!EFI_ERROR (Status)) {
2000       //
2001       // Use the ISA I/O Protocol to see if Controller is the Keyboard
2002       // controller
2003       //
2004       if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
2005         Status = EFI_UNSUPPORTED;
2006       }
2007 
2008       gBS->CloseProtocol (
2009              HandleBuffer[Index],
2010              &gEfiIsaIoProtocolGuid,
2011              NULL,
2012              HandleBuffer[Index]
2013              );
2014     }
2015 
2016     if (!EFI_ERROR (Status)) {
2017       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
2018     }
2019   }
2020   FreePool (HandleBuffer);
2021   return EFI_SUCCESS;
2022 }
2023 
2024 
2025 /**
2026   Load a legacy PC-AT OpROM for VGA controller.
2027 
2028   @param  Private                Driver private data.
2029 
2030   @retval EFI_SUCCESS            Legacy ROM successfully installed for this device.
2031   @retval EFI_DEVICE_ERROR       No VGA device handle found, or native EFI video
2032                                  driver cannot be successfully disconnected, or VGA
2033                                  thunk driver cannot be successfully connected.
2034 
2035 **/
2036 EFI_STATUS
LegacyBiosInstallVgaRom(IN LEGACY_BIOS_INSTANCE * Private)2037 LegacyBiosInstallVgaRom (
2038   IN  LEGACY_BIOS_INSTANCE            *Private
2039   )
2040 {
2041   EFI_STATUS                           Status;
2042   EFI_HANDLE                           VgaHandle;
2043   UINTN                                HandleCount;
2044   EFI_HANDLE                           *HandleBuffer;
2045   EFI_HANDLE                           *ConnectHandleBuffer;
2046   EFI_PCI_IO_PROTOCOL                  *PciIo;
2047   PCI_TYPE00                           PciConfigHeader;
2048   UINT64                               Supports;
2049   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
2050   UINTN                                EntryCount;
2051   UINTN                                Index;
2052   VOID                                 *Interface;
2053 
2054   //
2055   // EfiLegacyBiosGuild attached to a device implies that there is a legacy
2056   // BIOS associated with that device.
2057   //
2058   // There are 3 cases to consider.
2059   //   Case 1: No EFI driver is controlling the video.
2060   //     Action: Return EFI_SUCCESS from DisconnectController, search
2061   //             video thunk driver, and connect it.
2062   //   Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is
2063   //           not on the image handle.
2064   //     Action: Disconnect EFI driver.
2065   //             ConnectController for video thunk
2066   //   Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is
2067   //           on the image handle.
2068   //     Action: Do nothing and set Private->VgaInstalled = TRUE.
2069   //             Then this routine is not called any more.
2070   //
2071   //
2072   // Get the VGA device.
2073   //
2074   Status = Private->LegacyBiosPlatform->GetPlatformHandle (
2075                                           Private->LegacyBiosPlatform,
2076                                           EfiGetPlatformVgaHandle,
2077                                           0,
2078                                           &HandleBuffer,
2079                                           &HandleCount,
2080                                           NULL
2081                                           );
2082   if (EFI_ERROR (Status)) {
2083     return EFI_DEVICE_ERROR;
2084   }
2085 
2086   VgaHandle = HandleBuffer[0];
2087 
2088   //
2089   // Check whether video thunk driver already starts.
2090   //
2091   Status = gBS->OpenProtocolInformation (
2092                   VgaHandle,
2093                   &gEfiPciIoProtocolGuid,
2094                   &OpenInfoBuffer,
2095                   &EntryCount
2096                   );
2097   if (EFI_ERROR (Status)) {
2098     return Status;
2099   }
2100 
2101   for (Index = 0; Index < EntryCount; Index++) {
2102     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
2103       Status = gBS->HandleProtocol (
2104                       OpenInfoBuffer[Index].AgentHandle,
2105                       &gEfiLegacyBiosGuid,
2106                       (VOID **) &Interface
2107                       );
2108       if (!EFI_ERROR (Status)) {
2109         //
2110         // This should be video thunk driver which is managing video device
2111         // So it need not start again
2112         //
2113         DEBUG ((DEBUG_INFO, "Video thunk driver already start! Return!\n"));
2114         Private->VgaInstalled = TRUE;
2115         return EFI_SUCCESS;
2116       }
2117     }
2118   }
2119 
2120   //
2121   // Kick off the native EFI driver
2122   //
2123   Status = gBS->DisconnectController (
2124                   VgaHandle,
2125                   NULL,
2126                   NULL
2127                   );
2128   if (EFI_ERROR (Status)) {
2129     if (Status != EFI_NOT_FOUND) {
2130       return EFI_DEVICE_ERROR;
2131     } else {
2132       return Status;
2133     }
2134   }
2135   //
2136   // Find all the Thunk Driver
2137   //
2138   HandleBuffer = NULL;
2139   Status = gBS->LocateHandleBuffer (
2140                   ByProtocol,
2141                   &gEfiLegacyBiosGuid,
2142                   NULL,
2143                   &HandleCount,
2144                   &HandleBuffer
2145                   );
2146   ASSERT_EFI_ERROR (Status);
2147   ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1));
2148   ASSERT (ConnectHandleBuffer != NULL);
2149 
2150   CopyMem (
2151     ConnectHandleBuffer,
2152     HandleBuffer,
2153     sizeof (EFI_HANDLE) * HandleCount
2154     );
2155   ConnectHandleBuffer[HandleCount] = NULL;
2156 
2157   FreePool (HandleBuffer);
2158 
2159   //
2160   // Enable the device and make sure VGA cycles are being forwarded to this VGA device
2161   //
2162   Status = gBS->HandleProtocol (
2163                   VgaHandle,
2164                   &gEfiPciIoProtocolGuid,
2165                   (VOID **) &PciIo
2166                   );
2167   ASSERT_EFI_ERROR (Status);
2168   PciIo->Pci.Read (
2169                PciIo,
2170                EfiPciIoWidthUint32,
2171                0,
2172                sizeof (PciConfigHeader) / sizeof (UINT32),
2173                &PciConfigHeader
2174                );
2175 
2176   Status = PciIo->Attributes (
2177                     PciIo,
2178                     EfiPciIoAttributeOperationSupported,
2179                     0,
2180                     &Supports
2181                     );
2182   if (!EFI_ERROR (Status)) {
2183     Supports &= (UINT64)(EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \
2184                          EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
2185     Status = PciIo->Attributes (
2186                       PciIo,
2187                       EfiPciIoAttributeOperationEnable,
2188                       Supports,
2189                       NULL
2190                       );
2191   }
2192 
2193   if (Status == EFI_SUCCESS) {
2194     Private->VgaInstalled = TRUE;
2195 
2196     //
2197     // Attach the VGA thunk driver.
2198     // Assume the video is installed. This prevents potential of infinite recursion.
2199     //
2200     Status = gBS->ConnectController (
2201                     VgaHandle,
2202                     ConnectHandleBuffer,
2203                     NULL,
2204                     TRUE
2205                     );
2206   }
2207 
2208   FreePool (ConnectHandleBuffer);
2209 
2210   if (EFI_ERROR (Status)) {
2211 
2212     Private->VgaInstalled = FALSE;
2213 
2214     //
2215     // Reconnect the EFI VGA driver.
2216     //
2217     gBS->ConnectController (VgaHandle, NULL, NULL, TRUE);
2218     return EFI_DEVICE_ERROR;
2219   }
2220 
2221   return EFI_SUCCESS;
2222 }
2223 
2224 
2225 /**
2226   Load a legacy PC-AT OpROM.
2227 
2228   @param  This                              Protocol instance pointer.
2229   @param  Private                          Driver's private data.
2230   @param  PciHandle                      The EFI handle for the PCI device. It could be
2231                                                     NULL if the  OpROM image is not associated with
2232                                                     any device.
2233   @param  OpromRevision              The revision of PCI PC-AT ROM image.
2234   @param  RomImage                    Pointer to PCI PC-AT ROM image header. It must not
2235                                                     be NULL.
2236   @param  ImageSize                     Size of the PCI PC-AT ROM image.
2237   @param  RuntimeImageLength      On input is the max runtime image length indicated by the PCIR structure
2238                                                     On output is the actual runtime image length
2239   @param  DiskStart                       Disk number of first device hooked by the ROM. If
2240                                                     DiskStart is the same as DiskEnd no disked were
2241                                                     hooked.
2242   @param  DiskEnd                         Disk number of the last device hooked by the ROM.
2243   @param  RomShadowAddress       Shadow address of PC-AT ROM
2244 
2245   @retval EFI_SUCCESS            Legacy ROM loaded for this device
2246   @retval EFI_OUT_OF_RESOURCES   No more space for this ROM
2247 
2248 **/
2249 EFI_STATUS
2250 EFIAPI
LegacyBiosInstallRom(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN LEGACY_BIOS_INSTANCE * Private,IN EFI_HANDLE PciHandle,IN UINT8 OpromRevision,IN VOID * RomImage,IN UINTN ImageSize,IN OUT UINTN * RuntimeImageLength,OUT UINT8 * DiskStart,OPTIONAL OUT UINT8 * DiskEnd,OPTIONAL OUT VOID ** RomShadowAddress OPTIONAL)2251 LegacyBiosInstallRom (
2252   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
2253   IN LEGACY_BIOS_INSTANCE               *Private,
2254   IN EFI_HANDLE                         PciHandle,
2255   IN UINT8                              OpromRevision,
2256   IN VOID                               *RomImage,
2257   IN UINTN                              ImageSize,
2258   IN OUT UINTN                          *RuntimeImageLength,
2259   OUT UINT8                             *DiskStart, OPTIONAL
2260   OUT UINT8                             *DiskEnd, OPTIONAL
2261   OUT VOID                              **RomShadowAddress OPTIONAL
2262   )
2263 {
2264   EFI_STATUS            Status;
2265   EFI_STATUS            PciEnableStatus;
2266   EFI_PCI_IO_PROTOCOL   *PciIo;
2267   UINT8                 LocalDiskStart;
2268   UINT8                 LocalDiskEnd;
2269   UINTN                 Segment;
2270   UINTN                 Bus;
2271   UINTN                 Device;
2272   UINTN                 Function;
2273   EFI_IA32_REGISTER_SET Regs;
2274   UINT8                 VideoMode;
2275   UINT8                 OldVideoMode;
2276   EFI_TIME              BootTime;
2277   UINT32                *BdaPtr;
2278   UINT32                LocalTime;
2279   UINT32                StartBbsIndex;
2280   UINT32                EndBbsIndex;
2281   UINT32                MaxRomAddr;
2282   UINTN                 TempData;
2283   UINTN                 InitAddress;
2284   UINTN                 RuntimeAddress;
2285   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
2286   UINT32                Granularity;
2287 
2288   PciIo           = NULL;
2289   LocalDiskStart  = 0;
2290   LocalDiskEnd    = 0;
2291   Segment         = 0;
2292   Bus             = 0;
2293   Device          = 0;
2294   Function        = 0;
2295   VideoMode       = 0;
2296   OldVideoMode    = 0;
2297   PhysicalAddress = 0;
2298   MaxRomAddr      = PcdGet32 (PcdEndOpromShadowAddress);
2299 
2300   if ((Private->Legacy16Table->TableLength >= OFFSET_OF(EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&
2301       (Private->Legacy16Table->UmaAddress != 0) &&
2302       (Private->Legacy16Table->UmaSize != 0) &&
2303       (MaxRomAddr > (Private->Legacy16Table->UmaAddress))) {
2304     MaxRomAddr = Private->Legacy16Table->UmaAddress;
2305   }
2306 
2307 
2308   PciProgramAllInterruptLineRegisters (Private);
2309 
2310   if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) {
2311     //
2312     // CSM16 3.0 meets PCI 3.0 OpROM
2313     //   first test if there is enough space for its INIT code
2314     //
2315     PhysicalAddress = CONVENTIONAL_MEMORY_TOP;
2316     Status = gBS->AllocatePages (
2317                     AllocateMaxAddress,
2318                     EfiBootServicesCode,
2319                     EFI_SIZE_TO_PAGES (ImageSize),
2320                     &PhysicalAddress
2321                     );
2322 
2323     if (EFI_ERROR (Status)) {
2324       DEBUG ((DEBUG_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
2325       //
2326       // Report Status Code to indicate that there is no enough space for OpROM
2327       //
2328       REPORT_STATUS_CODE (
2329         EFI_ERROR_CODE | EFI_ERROR_MINOR,
2330         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
2331         );
2332       return EFI_OUT_OF_RESOURCES;
2333     }
2334     InitAddress = (UINTN) PhysicalAddress;
2335     //
2336     //   then test if there is enough space for its RT code
2337     //
2338     RuntimeAddress = Private->OptionRom;
2339     if (RuntimeAddress + *RuntimeImageLength > MaxRomAddr) {
2340       DEBUG ((DEBUG_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
2341       gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
2342       //
2343       // Report Status Code to indicate that there is no enough space for OpROM
2344       //
2345       REPORT_STATUS_CODE (
2346         EFI_ERROR_CODE | EFI_ERROR_MINOR,
2347         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
2348         );
2349       return EFI_OUT_OF_RESOURCES;
2350     }
2351   } else {
2352     // CSM16 3.0 meets PCI 2.x OpROM
2353     // CSM16 2.x meets PCI 2.x/3.0 OpROM
2354     //   test if there is enough space for its INIT code
2355     //
2356     InitAddress    = PCI_START_ADDRESS (Private->OptionRom);
2357     if (InitAddress + ImageSize > MaxRomAddr) {
2358       DEBUG ((DEBUG_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
2359       //
2360       // Report Status Code to indicate that there is no enough space for OpROM
2361       //
2362       REPORT_STATUS_CODE (
2363         EFI_ERROR_CODE | EFI_ERROR_MINOR,
2364         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
2365         );
2366       return EFI_OUT_OF_RESOURCES;
2367     }
2368 
2369     RuntimeAddress = InitAddress;
2370   }
2371 
2372   Private->LegacyRegion->UnLock (
2373                            Private->LegacyRegion,
2374                            0xE0000,
2375                            0x20000,
2376                            &Granularity
2377                            );
2378 
2379   Private->LegacyRegion->UnLock (
2380                            Private->LegacyRegion,
2381                            (UINT32) RuntimeAddress,
2382                            (UINT32) ImageSize,
2383                            &Granularity
2384                            );
2385 
2386   DEBUG ((DEBUG_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize));
2387 
2388   CopyMem ((VOID *) InitAddress, RomImage, ImageSize);
2389 
2390   //
2391   // Read the highest disk number "installed: and assume a new disk will
2392   // show up on the first drive past the current value.
2393   // There are several considerations here:
2394   // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo
2395   //    the change until boot selection time frame.
2396   // 2. BBS compliants drives will not change 40:75 until boot time.
2397   // 3. Onboard IDE controllers will change 40:75
2398   //
2399   ACCESS_PAGE0_CODE (
2400     LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
2401     if ((Private->Disk4075 + 0x80) < LocalDiskStart) {
2402       //
2403       // Update table since onboard IDE drives found
2404       //
2405       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = 0xff;
2406       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = 0xff;
2407       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = 0xff;
2408       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = 0xff;
2409       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = (UINT8) (Private->Disk4075 + 0x80);
2410       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber    = LocalDiskStart;
2411       Private->LegacyEfiHddTableIndex ++;
2412       Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f);
2413       Private->DiskEnd  = LocalDiskStart;
2414     }
2415 
2416     if (PciHandle != mVgaHandle) {
2417 
2418       EnablePs2Keyboard ();
2419 
2420       //
2421       // Store current mode settings since PrepareToScanRom may change mode.
2422       //
2423       VideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));
2424     }
2425   );
2426 
2427   //
2428   // Notify the platform that we are about to scan the ROM
2429   //
2430   Status = Private->LegacyBiosPlatform->PlatformHooks (
2431                                           Private->LegacyBiosPlatform,
2432                                           EfiPlatformHookPrepareToScanRom,
2433                                           0,
2434                                           PciHandle,
2435                                           &InitAddress,
2436                                           NULL,
2437                                           NULL
2438                                           );
2439 
2440   //
2441   // If Status returned is EFI_UNSUPPORTED then abort due to platform
2442   // policy.
2443   //
2444   if (Status == EFI_UNSUPPORTED) {
2445     goto Done;
2446   }
2447 
2448   //
2449   // Report corresponding status code
2450   //
2451   REPORT_STATUS_CODE (
2452     EFI_PROGRESS_CODE,
2453     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT)
2454     );
2455 
2456   //
2457   // Generate number of ticks since midnight for BDA. Some OPROMs require
2458   // this. Place result in 40:6C-6F
2459   //
2460   gRT->GetTime (&BootTime, NULL);
2461   LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
2462 
2463   //
2464   // Multiply result by 18.2 for number of ticks since midnight.
2465   // Use 182/10 to avoid floating point math.
2466   //
2467   ACCESS_PAGE0_CODE (
2468     LocalTime = (LocalTime * 182) / 10;
2469     BdaPtr    = (UINT32 *) ((UINTN) 0x46C);
2470     *BdaPtr   = LocalTime;
2471   );
2472 
2473   //
2474   // Pass in handoff data
2475   //
2476   PciEnableStatus = EFI_UNSUPPORTED;
2477   ZeroMem (&Regs, sizeof (Regs));
2478   if (PciHandle != NULL) {
2479 
2480     Status = gBS->HandleProtocol (
2481                     PciHandle,
2482                     &gEfiPciIoProtocolGuid,
2483                     (VOID **) &PciIo
2484                     );
2485     ASSERT_EFI_ERROR (Status);
2486 
2487     //
2488     // Enable command register.
2489     //
2490     PciEnableStatus = PciIo->Attributes (
2491                                PciIo,
2492                                EfiPciIoAttributeOperationEnable,
2493                                EFI_PCI_DEVICE_ENABLE,
2494                                NULL
2495                                );
2496 
2497     PciIo->GetLocation (
2498              PciIo,
2499              &Segment,
2500              &Bus,
2501              &Device,
2502              &Function
2503              );
2504     DEBUG ((DEBUG_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function));
2505   }
2506 
2507   mIgnoreBbsUpdateFlag  = FALSE;
2508   Regs.X.AX             = Legacy16DispatchOprom;
2509 
2510   //
2511   // Generate DispatchOpRomTable data
2512   //
2513   Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment;
2514   Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset  = Private->Legacy16Table->PnPInstallationCheckOffset;
2515   Private->IntThunk->DispatchOpromTable.OpromSegment                = (UINT16) (InitAddress >> 4);
2516   Private->IntThunk->DispatchOpromTable.PciBus                      = (UINT8) Bus;
2517   Private->IntThunk->DispatchOpromTable.PciDeviceFunction           = (UINT8) ((Device << 3) | Function);
2518   Private->IntThunk->DispatchOpromTable.NumberBbsEntries            = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
2519   Private->IntThunk->DispatchOpromTable.BbsTablePointer             = (UINT32) (UINTN) Private->BbsTablePtr;
2520   Private->IntThunk->DispatchOpromTable.RuntimeSegment              = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4));
2521   TempData = (UINTN) &Private->IntThunk->DispatchOpromTable;
2522   Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
2523   Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
2524   //
2525   // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes
2526   // Otherwise, it may cause the system to hang in some cases
2527   //
2528   if (!EFI_ERROR (PciEnableStatus)) {
2529     DEBUG ((DEBUG_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function));
2530     Private->LegacyBios.FarCall86 (
2531       &Private->LegacyBios,
2532       Private->Legacy16CallSegment,
2533       Private->Legacy16CallOffset,
2534       &Regs,
2535       NULL,
2536       0
2537       );
2538   } else {
2539     Regs.X.BX = 0;
2540   }
2541 
2542   if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) {
2543     Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries  = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries;
2544     mIgnoreBbsUpdateFlag = TRUE;
2545   }
2546   //
2547   // Check if non-BBS compliant drives found
2548   //
2549   if (Regs.X.BX != 0) {
2550     LocalDiskEnd  = (UINT8) (LocalDiskStart + Regs.H.BL);
2551     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = (UINT8) Segment;
2552     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = (UINT8) Bus;
2553     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = (UINT8) Device;
2554     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = (UINT8) Function;
2555     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = Private->DiskEnd;
2556     Private->DiskEnd = LocalDiskEnd;
2557     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
2558     Private->LegacyEfiHddTableIndex += 1;
2559   }
2560   //
2561   // Skip video mode set, if installing VGA
2562   //
2563   if (PciHandle != mVgaHandle) {
2564     //
2565     // Set mode settings since PrepareToScanRom may change mode
2566     //
2567     ACCESS_PAGE0_CODE ({
2568       OldVideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));
2569     });
2570 
2571     if (VideoMode != OldVideoMode) {
2572       //
2573       // The active video mode is changed, restore it to original mode.
2574       //
2575       Regs.H.AH = 0x00;
2576       Regs.H.AL = VideoMode;
2577       Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs);
2578     }
2579   }
2580   //
2581   // Regs.X.AX from the adapter initializion is ignored since some adapters
2582   // do not follow the standard of setting AX = 0 on success.
2583   //
2584   //
2585   // The ROM could have updated its size so we need to read again.
2586   //
2587   if (((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
2588     //
2589     // Now we check the signature (0xaa55) to judge whether the run-time code is truly generated by INIT function.
2590     // If signature is not valid, that means the INIT function didn't copy the run-time code to RuntimeAddress.
2591     //
2592     *RuntimeImageLength = 0;
2593   } else {
2594     *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Size512 * 512;
2595   }
2596 
2597   DEBUG ((DEBUG_INFO, " fsize = %x\n", *RuntimeImageLength));
2598 
2599   //
2600   // If OpROM runs in 2.0 mode
2601   //
2602   if (PhysicalAddress == 0) {
2603     if (*RuntimeImageLength < ImageSize) {
2604       //
2605       // Make area from end of shadowed rom to end of original rom all ffs
2606       //
2607       gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff);
2608     }
2609   }
2610 
2611   ACCESS_PAGE0_CODE (
2612     LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
2613   );
2614 
2615   //
2616   // Allow platform to perform any required actions after the
2617   // OPROM has been initialized.
2618   //
2619   Status = Private->LegacyBiosPlatform->PlatformHooks (
2620                                           Private->LegacyBiosPlatform,
2621                                           EfiPlatformHookAfterRomInit,
2622                                           0,
2623                                           PciHandle,
2624                                           &RuntimeAddress,
2625                                           NULL,
2626                                           NULL
2627                                           );
2628   if (PciHandle != NULL) {
2629     //
2630     // If no PCI Handle then no header or Bevs.
2631     //
2632     if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) {
2633       StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
2634       TempData      = RuntimeAddress;
2635       UpdateBevBcvTable (
2636         Private,
2637         (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData,
2638         PciIo
2639         );
2640       EndBbsIndex   = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
2641       LocalDiskEnd  = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex));
2642       if (LocalDiskEnd != LocalDiskStart) {
2643         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = (UINT8) Segment;
2644         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = (UINT8) Bus;
2645         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = (UINT8) Device;
2646         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = (UINT8) Function;
2647         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = Private->DiskEnd;
2648         Private->DiskEnd = LocalDiskEnd;
2649         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
2650         Private->LegacyEfiHddTableIndex += 1;
2651       }
2652     }
2653     //
2654     // Mark PCI device as having a legacy BIOS ROM loaded.
2655     //
2656     RomShadow (
2657       PciHandle,
2658       (UINT32) RuntimeAddress,
2659       (UINT32) *RuntimeImageLength,
2660       LocalDiskStart,
2661       LocalDiskEnd
2662       );
2663   }
2664 
2665   //
2666   // Stuff caller's OPTIONAL return parameters.
2667   //
2668   if (RomShadowAddress != NULL) {
2669     *RomShadowAddress = (VOID *) RuntimeAddress;
2670   }
2671 
2672   if (DiskStart != NULL) {
2673     *DiskStart = LocalDiskStart;
2674   }
2675 
2676   if (DiskEnd != NULL) {
2677     *DiskEnd = LocalDiskEnd;
2678   }
2679 
2680   Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength);
2681 
2682   Status = EFI_SUCCESS;
2683 
2684 Done:
2685   if (PhysicalAddress != 0) {
2686     //
2687     // Free pages when OpROM is 3.0
2688     //
2689     gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
2690   }
2691 
2692   //
2693   // Insure all shadowed  areas are locked
2694   //
2695   Private->LegacyRegion->Lock (
2696                            Private->LegacyRegion,
2697                            0xC0000,
2698                            0x40000,
2699                            &Granularity
2700                            );
2701 
2702   return Status;
2703 }
2704 
2705 /**
2706   Let IOMMU grant DMA access for the PCI device.
2707 
2708   @param  PciHandle             The EFI handle for the PCI device.
2709   @param  HostAddress           The system memory address to map to the PCI controller.
2710   @param  NumberOfBytes         The number of bytes to map.
2711 
2712   @retval EFI_SUCCESS  The DMA access is granted.
2713 **/
2714 EFI_STATUS
IoMmuGrantAccess(IN EFI_HANDLE PciHandle,IN EFI_PHYSICAL_ADDRESS HostAddress,IN UINTN NumberOfBytes)2715 IoMmuGrantAccess (
2716   IN  EFI_HANDLE                        PciHandle,
2717   IN  EFI_PHYSICAL_ADDRESS              HostAddress,
2718   IN  UINTN                             NumberOfBytes
2719   )
2720 {
2721   EFI_PHYSICAL_ADDRESS            DeviceAddress;
2722   VOID                            *Mapping;
2723   EFI_STATUS                      Status;
2724 
2725   if (PciHandle == NULL) {
2726     return EFI_UNSUPPORTED;
2727   }
2728 
2729   Status = EFI_SUCCESS;
2730   if (mIoMmu == NULL) {
2731     gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu);
2732   }
2733   if (mIoMmu != NULL) {
2734     Status = mIoMmu->Map (
2735                        mIoMmu,
2736                        EdkiiIoMmuOperationBusMasterCommonBuffer,
2737                        (VOID *)(UINTN)HostAddress,
2738                        &NumberOfBytes,
2739                        &DeviceAddress,
2740                        &Mapping
2741                        );
2742     if (EFI_ERROR(Status)) {
2743       DEBUG ((DEBUG_ERROR, "LegacyPci - IoMmuMap - %r\n", Status));
2744     } else {
2745       ASSERT (DeviceAddress == HostAddress);
2746       Status = mIoMmu->SetAttribute (
2747                          mIoMmu,
2748                          PciHandle,
2749                          Mapping,
2750                          EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
2751                          );
2752       if (EFI_ERROR(Status)) {
2753         DEBUG ((DEBUG_ERROR, "LegacyPci - IoMmuSetAttribute - %r\n", Status));
2754       }
2755     }
2756   }
2757   return Status;
2758 }
2759 
2760 /**
2761   Load a legacy PC-AT OPROM on the PciHandle device. Return information
2762   about how many disks were added by the OPROM and the shadow address and
2763   size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
2764 
2765   @param  This                   Protocol instance pointer.
2766   @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will
2767                                  be loaded. This value is NULL if RomImage is
2768                                  non-NULL. This is the normal case.
2769   @param  RomImage               A PCI PC-AT ROM image. This argument is non-NULL
2770                                  if there is no hardware associated with the ROM
2771                                  and thus no PciHandle, otherwise is must be NULL.
2772                                  Example is PXE base code.
2773   @param  Flags                  Indicates if ROM found and if PC-AT.
2774   @param  DiskStart              Disk number of first device hooked by the ROM. If
2775                                  DiskStart is the same as DiskEnd no disked were
2776                                  hooked.
2777   @param  DiskEnd                Disk number of the last device hooked by the ROM.
2778   @param  RomShadowAddress       Shadow address of PC-AT ROM
2779   @param  RomShadowedSize        Size of RomShadowAddress in bytes
2780 
2781   @retval EFI_SUCCESS            Legacy ROM loaded for this device
2782   @retval EFI_INVALID_PARAMETER  PciHandle not found
2783   @retval EFI_UNSUPPORTED        There is no PCI ROM in the ROM BAR or no onboard
2784                                  ROM
2785 
2786 **/
2787 EFI_STATUS
2788 EFIAPI
LegacyBiosInstallPciRom(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN EFI_HANDLE PciHandle,IN VOID ** RomImage,OUT UINTN * Flags,OUT UINT8 * DiskStart,OPTIONAL OUT UINT8 * DiskEnd,OPTIONAL OUT VOID ** RomShadowAddress,OPTIONAL OUT UINT32 * RomShadowedSize OPTIONAL)2789 LegacyBiosInstallPciRom (
2790   IN EFI_LEGACY_BIOS_PROTOCOL           * This,
2791   IN  EFI_HANDLE                        PciHandle,
2792   IN  VOID                              **RomImage,
2793   OUT UINTN                             *Flags,
2794   OUT UINT8                             *DiskStart, OPTIONAL
2795   OUT UINT8                             *DiskEnd, OPTIONAL
2796   OUT VOID                              **RomShadowAddress, OPTIONAL
2797   OUT UINT32                            *RomShadowedSize OPTIONAL
2798   )
2799 {
2800   EFI_STATUS                      Status;
2801   LEGACY_BIOS_INSTANCE            *Private;
2802   VOID                            *LocalRomImage;
2803   UINTN                           ImageSize;
2804   UINTN                           RuntimeImageLength;
2805   EFI_PCI_IO_PROTOCOL             *PciIo;
2806   PCI_TYPE01                      PciConfigHeader;
2807   UINTN                           HandleCount;
2808   EFI_HANDLE                      *HandleBuffer;
2809   UINTN                           PciSegment;
2810   UINTN                           PciBus;
2811   UINTN                           PciDevice;
2812   UINTN                           PciFunction;
2813   UINTN                           LastBus;
2814   UINTN                           Index;
2815   UINT8                           OpromRevision;
2816   UINT32                          Granularity;
2817   PCI_3_0_DATA_STRUCTURE          *Pcir;
2818 
2819   OpromRevision = 0;
2820 
2821   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
2822   if (Private->Legacy16Table->LastPciBus == 0) {
2823     //
2824     // Get last bus number if not already found
2825     //
2826     Status = gBS->LocateHandleBuffer (
2827                     ByProtocol,
2828                     &gEfiPciIoProtocolGuid,
2829                     NULL,
2830                     &HandleCount,
2831                     &HandleBuffer
2832                     );
2833 
2834     LastBus = 0;
2835     for (Index = 0; Index < HandleCount; Index++) {
2836       Status = gBS->HandleProtocol (
2837                       HandleBuffer[Index],
2838                       &gEfiPciIoProtocolGuid,
2839                       (VOID **) &PciIo
2840                       );
2841       if (EFI_ERROR (Status)) {
2842         continue;
2843       }
2844 
2845       Status = PciIo->GetLocation (
2846                         PciIo,
2847                         &PciSegment,
2848                         &PciBus,
2849                         &PciDevice,
2850                         &PciFunction
2851                         );
2852       if (PciBus > LastBus) {
2853         LastBus = PciBus;
2854       }
2855     }
2856 
2857     Private->LegacyRegion->UnLock (
2858                              Private->LegacyRegion,
2859                              0xE0000,
2860                              0x20000,
2861                              &Granularity
2862                              );
2863     Private->Legacy16Table->LastPciBus = (UINT8) LastBus;
2864     Private->LegacyRegion->Lock (
2865                              Private->LegacyRegion,
2866                              0xE0000,
2867                              0x20000,
2868                              &Granularity
2869                              );
2870   }
2871 
2872   *Flags = 0;
2873   if ((PciHandle != NULL) && (RomImage == NULL)) {
2874     //
2875     // If PciHandle has OpRom to Execute
2876     // and OpRom are all associated with Hardware
2877     //
2878     Status = gBS->HandleProtocol (
2879                     PciHandle,
2880                     &gEfiPciIoProtocolGuid,
2881                     (VOID **) &PciIo
2882                     );
2883 
2884     if (!EFI_ERROR (Status)) {
2885       PciIo->Pci.Read (
2886                    PciIo,
2887                    EfiPciIoWidthUint32,
2888                    0,
2889                    sizeof (PciConfigHeader) / sizeof (UINT32),
2890                    &PciConfigHeader
2891                    );
2892 
2893       //
2894       // if video installed & OPROM is video return
2895       //
2896       if (
2897           (
2898            ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) &&
2899             (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA))
2900            ||
2901            ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) &&
2902             (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA))
2903           )
2904           &&
2905           (!Private->VgaInstalled)
2906          ) {
2907         mVgaInstallationInProgress = TRUE;
2908 
2909         //
2910         //      return EFI_UNSUPPORTED;
2911         //
2912       }
2913     }
2914     //
2915     // To run any legacy image, the VGA needs to be installed first.
2916     // if installing the video, then don't need the thunk as already installed.
2917     //
2918     Status = Private->LegacyBiosPlatform->GetPlatformHandle (
2919                                             Private->LegacyBiosPlatform,
2920                                             EfiGetPlatformVgaHandle,
2921                                             0,
2922                                             &HandleBuffer,
2923                                             &HandleCount,
2924                                             NULL
2925                                             );
2926 
2927     if (!EFI_ERROR (Status)) {
2928       mVgaHandle = HandleBuffer[0];
2929       if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) {
2930         //
2931         // A return status of EFI_NOT_FOUND is considered valid (No EFI
2932         // driver is controlling video.
2933         //
2934         mVgaInstallationInProgress  = TRUE;
2935         Status                      = LegacyBiosInstallVgaRom (Private);
2936         if (EFI_ERROR (Status)) {
2937           if (Status != EFI_NOT_FOUND) {
2938             mVgaInstallationInProgress = FALSE;
2939             return Status;
2940           }
2941         } else {
2942           mVgaInstallationInProgress = FALSE;
2943         }
2944       }
2945     }
2946     //
2947     // See if the option ROM for PciHandle has already been executed
2948     //
2949     Status = IsLegacyRom (PciHandle);
2950 
2951     if (!EFI_ERROR (Status)) {
2952       mVgaInstallationInProgress = FALSE;
2953       GetShadowedRomParameters (
2954         PciHandle,
2955         DiskStart,
2956         DiskEnd,
2957         RomShadowAddress,
2958         (UINTN *) RomShadowedSize
2959         );
2960       return EFI_SUCCESS;
2961     }
2962 
2963     Status = LegacyBiosCheckPciRomEx (
2964                &Private->LegacyBios,
2965                PciHandle,
2966                &LocalRomImage,
2967                &ImageSize,
2968                &RuntimeImageLength,
2969                Flags,
2970                &OpromRevision,
2971                NULL
2972                );
2973     if (EFI_ERROR (Status)) {
2974       //
2975       // There is no PCI ROM in the ROM BAR or no onboard ROM
2976       //
2977       mVgaInstallationInProgress = FALSE;
2978       return EFI_UNSUPPORTED;
2979     }
2980   } else {
2981     if ((RomImage == NULL) || (*RomImage == NULL)) {
2982       //
2983       // If PciHandle is NULL, and no OpRom is to be associated
2984       //
2985       mVgaInstallationInProgress = FALSE;
2986       return EFI_UNSUPPORTED;
2987     }
2988 
2989     Status = Private->LegacyBiosPlatform->GetPlatformHandle (
2990                                             Private->LegacyBiosPlatform,
2991                                             EfiGetPlatformVgaHandle,
2992                                             0,
2993                                             &HandleBuffer,
2994                                             &HandleCount,
2995                                             NULL
2996                                             );
2997     if ((!EFI_ERROR (Status)) && (!Private->VgaInstalled)) {
2998       //
2999       // A return status of EFI_NOT_FOUND is considered valid (No EFI
3000       // driver is controlling video.
3001       //
3002       mVgaInstallationInProgress  = TRUE;
3003       Status                      = LegacyBiosInstallVgaRom (Private);
3004       if (EFI_ERROR (Status)) {
3005         if (Status != EFI_NOT_FOUND) {
3006           mVgaInstallationInProgress = FALSE;
3007           return Status;
3008         }
3009       } else {
3010         mVgaInstallationInProgress = FALSE;
3011       }
3012     }
3013 
3014     LocalRomImage = *RomImage;
3015     if (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE ||
3016         ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset == 0 ||
3017         (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset & 3 ) != 0) {
3018       mVgaInstallationInProgress = FALSE;
3019       return EFI_UNSUPPORTED;
3020     }
3021 
3022     Pcir = (PCI_3_0_DATA_STRUCTURE *)
3023            ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset);
3024 
3025     if ((Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) || (Pcir->CodeType != PCI_CODE_TYPE_PCAT_IMAGE)) {
3026       mVgaInstallationInProgress = FALSE;
3027       return EFI_UNSUPPORTED;
3028     }
3029 
3030     ImageSize = Pcir->ImageLength * 512;
3031     if (Pcir->Length >= 0x1C) {
3032       OpromRevision = Pcir->Revision;
3033     } else {
3034       OpromRevision = 0;
3035     }
3036     if (Pcir->Revision < 3) {
3037       RuntimeImageLength = 0;
3038     } else {
3039       RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
3040     }
3041   }
3042 
3043   //
3044   // Grant access for below 1M
3045   // BDA/EBDA/LowPMM and scratch memory for OPROM.
3046   //
3047   IoMmuGrantAccess (PciHandle, 0, SIZE_1MB);
3048   //
3049   // Grant access for HiPmm
3050   //
3051   IoMmuGrantAccess (
3052     PciHandle,
3053     Private->IntThunk->EfiToLegacy16InitTable.HiPmmMemory,
3054     Private->IntThunk->EfiToLegacy16InitTable.HiPmmMemorySizeInBytes
3055     );
3056 
3057   //
3058   // Shadow and initialize the OpROM.
3059   //
3060   ASSERT (Private->TraceIndex < 0x200);
3061   Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000;
3062   Private->TraceIndex ++;
3063   Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200);
3064   Status = LegacyBiosInstallRom (
3065              This,
3066              Private,
3067              PciHandle,
3068              OpromRevision,
3069              LocalRomImage,
3070              ImageSize,
3071              &RuntimeImageLength,
3072              DiskStart,
3073              DiskEnd,
3074              RomShadowAddress
3075              );
3076   if (RomShadowedSize != NULL) {
3077     *RomShadowedSize = (UINT32) RuntimeImageLength;
3078   }
3079 
3080   mVgaInstallationInProgress = FALSE;
3081   return Status;
3082 }
3083 
3084