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