3 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
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
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.
16 #include "LegacyBiosInterface.h"
17 #include <IndustryStandard/Pci30.h>
19 #define PCI_START_ADDRESS(x) (((x) + 0x7ff) & ~0x7ff)
21 #define MAX_BRIDGE_INDEX 0x20
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
;
39 EFI_HANDLE mVgaHandle
;
40 BOOLEAN mIgnoreBbsUpdateFlag
;
41 BOOLEAN mVgaInstallationInProgress
= FALSE
;
42 UINT32 mRomCount
= 0x00;
43 ROM_INSTANCE_ENTRY mRomEntry
[ROM_MAX_ENTRIES
];
44 EDKII_IOMMU_PROTOCOL
*mIoMmu
;
47 Query shadowed legacy ROM parameters registered by RomShadow() previously.
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
55 @retval EFI_SUCCESS Query Logging successful.
56 @retval EFI_NOT_FOUND No logged data found about PciHandle.
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
69 EFI_PCI_IO_PROTOCOL
*PciIo
;
77 // Get the PCI I/O Protocol on PciHandle
79 Status
= gBS
->HandleProtocol (
81 &gEfiPciIoProtocolGuid
,
84 if (EFI_ERROR (Status
)) {
89 // Get the location of the PCI device
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
)) {
108 if (Index
== mRomCount
) {
109 return EFI_NOT_FOUND
;
112 if (DiskStart
!= NULL
) {
113 *DiskStart
= mRomEntry
[Index
].DiskStart
;
116 if (DiskEnd
!= NULL
) {
117 *DiskEnd
= mRomEntry
[Index
].DiskEnd
;
120 if (RomShadowAddress
!= NULL
) {
121 *RomShadowAddress
= (VOID
*)(UINTN
)mRomEntry
[Index
].ShadowAddress
;
124 if (ShadowedSize
!= NULL
) {
125 *ShadowedSize
= mRomEntry
[Index
].ShadowedSize
;
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
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
144 @retval EFI_SUCCESS Logging successful.
145 @retval EFI_OUT_OF_RESOURCES No remaining room for registering another option
151 IN EFI_HANDLE PciHandle
,
152 IN UINT32 ShadowAddress
,
153 IN UINT32 ShadowedSize
,
159 EFI_PCI_IO_PROTOCOL
*PciIo
;
162 // See if there is room to register another option ROM
164 if (mRomCount
>= ROM_MAX_ENTRIES
) {
165 return EFI_OUT_OF_RESOURCES
;
168 // Get the PCI I/O Protocol on PciHandle
170 Status
= gBS
->HandleProtocol (
172 &gEfiPciIoProtocolGuid
,
175 if (EFI_ERROR (Status
)) {
179 // Get the location of the PCI device
183 &mRomEntry
[mRomCount
].PciSegment
,
184 &mRomEntry
[mRomCount
].PciBus
,
185 &mRomEntry
[mRomCount
].PciDevice
,
186 &mRomEntry
[mRomCount
].PciFunction
188 mRomEntry
[mRomCount
].ShadowAddress
= ShadowAddress
;
189 mRomEntry
[mRomCount
].ShadowedSize
= ShadowedSize
;
190 mRomEntry
[mRomCount
].DiskStart
= DiskStart
;
191 mRomEntry
[mRomCount
].DiskEnd
= DiskEnd
;
200 Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This
201 information represents every call to RomShadow ()
203 @param PciHandle PCI device to get status for
205 @retval EFI_SUCCESS Legacy ROM loaded for this device
206 @retval EFI_NOT_FOUND No Legacy ROM loaded for this device
211 IN EFI_HANDLE PciHandle
215 EFI_PCI_IO_PROTOCOL
*PciIo
;
223 // Get the PCI I/O Protocol on PciHandle
225 Status
= gBS
->HandleProtocol (
227 &gEfiPciIoProtocolGuid
,
230 if (EFI_ERROR (Status
)) {
234 // Get the location of the PCI device
245 // See if the option ROM from PciHandle has been previously posted
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
257 return EFI_NOT_FOUND
;
261 Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the
262 related information from the header.
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
275 @retval EFI_SUCCESS Successfully find the legacy PCI ROM
276 @retval EFI_NOT_FOUND Failed to find the legacy PCI ROM
281 IN UINT16 Csm16Revision
,
285 IN OUT UINTN
*ImageSize
,
286 OUT UINTN
*MaxRuntimeImageLength
, OPTIONAL
287 OUT UINT8
*OpRomRevision
, OPTIONAL
288 OUT VOID
**ConfigUtilityCodeHeader OPTIONAL
292 UINT16
*DeviceIdList
;
293 EFI_PCI_ROM_HEADER RomHeader
;
294 PCI_3_0_DATA_STRUCTURE
*Pcir
;
299 if (*ImageSize
< sizeof (EFI_PCI_ROM_HEADER
)) {
300 return EFI_NOT_FOUND
;
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
)) {
313 Pcir
= (PCI_3_0_DATA_STRUCTURE
*) (RomHeader
.Raw
+ RomHeader
.Generic
->PcirOffset
);
315 // Check signature in the PCI Data Structure.
317 if (Pcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
321 if (((UINTN
)RomHeader
.Raw
- (UINTN
)*Rom
) + Pcir
->ImageLength
* 512 > *ImageSize
) {
325 if (Pcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
327 if (Pcir
->VendorId
== VendorId
) {
328 if (Pcir
->DeviceId
== DeviceId
) {
330 } else if ((Pcir
->Revision
>= 3) && (Pcir
->DeviceListOffset
!= 0)) {
331 DeviceIdList
= (UINT16
*)(((UINT8
*) Pcir
) + Pcir
->DeviceListOffset
);
333 // Checking the device list
335 while (*DeviceIdList
!= 0) {
336 if (*DeviceIdList
== DeviceId
) {
346 if (Csm16Revision
>= 0x0300) {
350 if (Pcir
->Revision
>= 3) {
352 // case 1.1: meets OpRom 3.0
355 BestImage
= RomHeader
.Raw
;
359 // case 1.2: meets OpRom 2.x
360 // Store it and try to find the OpRom 3.0
362 BackupImage
= RomHeader
.Raw
;
368 if (Pcir
->Revision
>= 3) {
370 // case 2.1: meets OpRom 3.0
371 // Store it and try to find the OpRom 2.x
373 BackupImage
= RomHeader
.Raw
;
376 // case 2.2: meets OpRom 2.x
379 BestImage
= RomHeader
.Raw
;
384 DEBUG ((EFI_D_ERROR
, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN
)VendorId
, (UINTN
)DeviceId
));
388 if ((Pcir
->Indicator
& 0x80) == 0x80) {
391 RomHeader
.Raw
+= 512 * Pcir
->ImageLength
;
395 if (BestImage
== NULL
) {
396 if (BackupImage
== NULL
) {
397 return EFI_NOT_FOUND
;
400 // The versions of CSM16 and OpRom don't match exactly
402 BestImage
= BackupImage
;
404 RomHeader
.Raw
= BestImage
;
405 Pcir
= (PCI_3_0_DATA_STRUCTURE
*) (RomHeader
.Raw
+ RomHeader
.Generic
->PcirOffset
);
407 *ImageSize
= Pcir
->ImageLength
* 512;
409 if (MaxRuntimeImageLength
!= NULL
) {
410 if (Pcir
->Revision
< 3) {
411 *MaxRuntimeImageLength
= 0;
413 *MaxRuntimeImageLength
= Pcir
->MaxRuntimeImageLength
* 512;
417 if (OpRomRevision
!= NULL
) {
419 // Optional return PCI Data Structure revision
421 if (Pcir
->Length
>= 0x1C) {
422 *OpRomRevision
= Pcir
->Revision
;
428 if (ConfigUtilityCodeHeader
!= NULL
) {
430 // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM
432 if ((Pcir
->Revision
< 3) || (Pcir
->ConfigUtilityCodeHeaderOffset
== 0)) {
433 *ConfigUtilityCodeHeader
= NULL
;
435 *ConfigUtilityCodeHeader
= RomHeader
.Raw
+ Pcir
->ConfigUtilityCodeHeaderOffset
;
443 Build a table of bridge info for PIRQ translation.
445 @param RoutingTable RoutingTable obtained from Platform.
446 @param RoutingTableEntries Number of RoutingTable entries.
448 @retval EFI_SUCCESS New Subordinate bus.
449 @retval EFI_NOT_FOUND No more Subordinate busses.
454 IN EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
,
455 IN UINTN RoutingTableEntries
460 EFI_HANDLE
*HandleBuffer
;
464 EFI_PCI_IO_PROTOCOL
*PciIo
;
465 PCI_TYPE01 PciConfigHeader
;
466 BRIDGE_TABLE SlotBridges
[MAX_BRIDGE_INDEX
];
467 UINTN SlotBridgeIndex
;
470 SlotBridgeIndex
= 0x00;
473 // Assumption is table is built from low bus to high bus numbers.
475 Status
= gBS
->LocateHandleBuffer (
477 &gEfiPciIoProtocolGuid
,
482 if (EFI_ERROR (Status
)) {
483 return EFI_NOT_FOUND
;
485 for (Index
= 0; Index
< HandleCount
; Index
++) {
486 Status
= gBS
->HandleProtocol (
488 &gEfiPciIoProtocolGuid
,
491 if (EFI_ERROR (Status
)) {
499 sizeof (PciConfigHeader
) / sizeof (UINT32
),
503 if (IS_PCI_P2P (&PciConfigHeader
) && (BridgeIndex
< MAX_BRIDGE_INDEX
)) {
506 &Bridges
[BridgeIndex
].PciSegment
,
507 &Bridges
[BridgeIndex
].PciBus
,
508 &Bridges
[BridgeIndex
].PciDevice
,
509 &Bridges
[BridgeIndex
].PciFunction
512 Bridges
[BridgeIndex
].PrimaryBus
= PciConfigHeader
.Bridge
.PrimaryBus
;
514 Bridges
[BridgeIndex
].SecondaryBus
= PciConfigHeader
.Bridge
.SecondaryBus
;
516 Bridges
[BridgeIndex
].SubordinateBus
= PciConfigHeader
.Bridge
.SubordinateBus
;
518 for (Index1
= 0; Index1
< RoutingTableEntries
; Index1
++){
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[]
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
));
537 // Pack up Bridges by removing those useless ones
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
))) {
544 // We have found one that meets our criteria
552 // This one doesn't meet criteria, pack it
554 if (Index1
>= SlotBridgeIndex
) {
555 for (Index1
= Index
; BridgeIndex
> 1 && Index1
< BridgeIndex
- 1 ; Index1
++) {
556 CopyMem (&Bridges
[Index1
], &Bridges
[Index1
+ 1], sizeof (BRIDGE_TABLE
));
563 NumberOfBridges
= BridgeIndex
;
566 // Sort bridges low to high by Secondary bus followed by subordinate bus
568 if (NumberOfBridges
> 1) {
571 SortedBridgeIndex
[Index
] = Index
;
573 } while (Index
< NumberOfBridges
);
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
;
582 if ((Bridges
[Index
].SecondaryBus
== Bridges
[Index1
].SecondaryBus
) &&
583 (Bridges
[Index
].SubordinateBus
> Bridges
[Index1
].SubordinateBus
)
585 SortedBridgeIndex
[Index
] = Index1
;
586 SortedBridgeIndex
[Index1
] = Index
;
591 FreePool (HandleBuffer
);
597 Find base Bridge for device.
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
605 @retval EFI_SUCCESS At base bus.
606 @retval EFI_NOT_FOUND Behind a bridge.
611 IN LEGACY_BIOS_INSTANCE
*Private
,
614 IN EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
,
615 IN UINTN RoutingTableEntries
619 for (Index
= 0; Index
< RoutingTableEntries
; Index
++) {
620 if ((RoutingTable
[Index
].Bus
== PciBus
) && (RoutingTable
[Index
].Device
== (PciDevice
<< 3))) {
625 return EFI_NOT_FOUND
;
629 Translate PIRQ through busses
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
639 @retval EFI_SUCCESS Pirq successfully translated.
640 @retval EFI_NOT_FOUND The device is not behind any known bridge.
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
653 This routine traverses the PCI busses from base slot
654 and translates the PIRQ register to the appropriate one.
658 Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.
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.
667 Subordinate bus # = 5
668 Bus 2, Device 6 is a bridge. It has no bridges behind it.
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.
675 Secondary bus = 4 Device 6 takes bus 2.
677 Bridge PIRQ routing is D,A,B,C
678 Bus 4, Device 2 is a bridge. It has no bridges behind it.
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
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
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
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.
704 UINT8 LocalPirqIndex
;
705 BOOLEAN BaseIndexFlag
;
708 BaseIndexFlag
= FALSE
;
711 LocalPirqIndex
= *PirqIndex
;
713 LocalDevice
= *PciDevice
;
715 BaseDevice
= *PciDevice
;
716 BaseFunction
= *PciFunction
;
719 // LocalPirqIndex list PIRQs in rotated fashion
726 for (BridgeIndex
= 0; BridgeIndex
< NumberOfBridges
; BridgeIndex
++) {
727 SBridgeIndex
= SortedBridgeIndex
[BridgeIndex
];
729 // Check if device behind this bridge
731 if ((LocalBus
>= Bridges
[SBridgeIndex
].SecondaryBus
) && (LocalBus
<= Bridges
[SBridgeIndex
].SubordinateBus
)) {
733 // If BaseIndexFlag = FALSE then have found base bridge, i.e
734 // bridge in slot. Save info for use by IRQ routing table.
736 if (!BaseIndexFlag
) {
737 BaseBus
= Bridges
[SBridgeIndex
].PciBus
;
738 BaseDevice
= Bridges
[SBridgeIndex
].PciDevice
;
739 BaseFunction
= Bridges
[SBridgeIndex
].PciFunction
;
740 BaseIndexFlag
= TRUE
;
742 LocalPirqIndex
= (UINT8
) ((LocalPirqIndex
+ (UINT8
)Bridges
[SBridgeIndex
].PciDevice
)%4);
746 // Check if at device. If not get new PCI location & PIRQ
748 if (Bridges
[SBridgeIndex
].SecondaryBus
== (UINT8
) LocalBus
) {
752 LocalPirqIndex
= (UINT8
) ((LocalPirqIndex
+ (UINT8
) (LocalDevice
)) % 4);
759 // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user
761 if(BridgeIndex
>= NumberOfBridges
){
762 DEBUG ((EFI_D_ERROR
, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus
, *PciDevice
, *PciFunction
));
765 *PirqIndex
= LocalPirqIndex
;
767 *PciDevice
= BaseDevice
;
768 *PciFunction
= BaseFunction
;
775 Copy the $PIR table as required.
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
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
793 EFI_IA32_REGISTER_SET Regs
;
797 // Copy $PIR table, if it exists.
799 if (PirqTable
!= NULL
) {
800 Private
->LegacyRegion
->UnLock (
801 Private
->LegacyRegion
,
807 Private
->InternalIrqRoutingTable
= RoutingTable
;
808 Private
->NumberIrqRoutingEntries
= (UINT16
) (RoutingTableEntries
);
809 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
811 Regs
.X
.AX
= Legacy16GetTableAddress
;
812 Regs
.X
.CX
= (UINT16
) PirqTableSize
;
814 // Allocate at F segment according to PCI IRQ Routing Table Specification
816 Regs
.X
.BX
= (UINT16
) 0x1;
818 // 16-byte boundary alignment requirement according to
819 // PCI IRQ Routing Table Specification
822 Private
->LegacyBios
.FarCall86 (
823 &Private
->LegacyBios
,
824 Private
->Legacy16CallSegment
,
825 Private
->Legacy16CallOffset
,
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
));
835 DEBUG ((EFI_D_INFO
, "PIRQ table in legacy region - %x\n", Private
->Legacy16Table
->IrqRoutingTablePointer
));
836 Private
->Legacy16Table
->IrqRoutingTableLength
= (UINT32
)PirqTableSize
;
838 (VOID
*) (UINTN
)Private
->Legacy16Table
->IrqRoutingTablePointer
,
844 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
845 Private
->LegacyRegion
->Lock (
846 Private
->LegacyRegion
,
853 Private
->PciInterruptLine
= TRUE
;
858 Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.
860 @param PciHandle The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
865 IN EFI_LEGACY_INSTALL_PCI_HANDLER
*PciHandle
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
));
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
));
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
));
890 Copy the $PIR table as required.
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
899 InstallLegacyIrqHandler (
900 IN LEGACY_BIOS_INSTANCE
*Private
,
901 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
903 IN PCI_TYPE00
*PciConfigHeader
906 EFI_IA32_REGISTER_SET Regs
;
912 EFI_LEGACY_8259_PROTOCOL
*Legacy8259
;
913 UINT16 PrimaryMaster
;
914 UINT16 SecondaryMaster
;
916 UINTN RegisterAddress
;
921 Legacy8259
= Private
->Legacy8259
;
923 // Disable interrupt in PIC, in case shared, to prevent an
924 // interrupt from occuring.
926 Legacy8259
->GetMask (
934 LegMask
= (UINT16
) (LegMask
| (UINT16
) (1 << PciIrq
));
936 Legacy8259
->SetMask (
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];
959 // Use native mode base address registers in two cases:
960 // 1. Programming Interface (PI) register indicates Primary Controller is
962 // 2. PCI device Sub Class Code is not IDE
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);
970 Private
->IntThunk
->PciHandler
.PrimaryIrq
= 14;
971 Private
->IntThunk
->PciHandler
.PrimaryBase
= 0x1f0;
972 Private
->IntThunk
->PciHandler
.PrimaryControl
= 0x3f6;
975 // Secondary controller data
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);
983 // Clear pending interrupts in Bus Master registers
985 IoWrite16 (PrimaryMaster
, 0x04);
986 IoWrite16 (SecondaryMaster
, 0x04);
991 // Use native mode base address registers in two cases:
992 // 1. Programming Interface (PI) register indicates Secondary Controller is
994 // 2. PCI device Sub Class Code is not IDE
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);
1002 Private
->IntThunk
->PciHandler
.SecondaryIrq
= 15;
1003 Private
->IntThunk
->PciHandler
.SecondaryBase
= 0x170;
1004 Private
->IntThunk
->PciHandler
.SecondaryControl
= 0x376;
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.
1013 // Read IDE CMD blk status reg to clear out any pending interrupts.
1014 // Do here for Primary and Secondary IDE channels
1016 RegisterAddress
= (UINT16
)Private
->IntThunk
->PciHandler
.PrimaryBase
+ 0x07;
1017 IoRead8 (RegisterAddress
);
1018 RegisterAddress
= (UINT16
)Private
->IntThunk
->PciHandler
.SecondaryBase
+ 0x07;
1019 IoRead8 (RegisterAddress
);
1021 Private
->IntThunk
->PciHandler
.PrimaryReserved
= 0;
1022 Private
->IntThunk
->PciHandler
.SecondaryReserved
= 0;
1023 Private
->LegacyRegion
->UnLock (
1024 Private
->LegacyRegion
,
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
);
1035 DumpPciHandle (&Private
->IntThunk
->PciHandler
);
1037 Private
->LegacyBios
.FarCall86 (
1038 &Private
->LegacyBios
,
1039 Private
->Legacy16CallSegment
,
1040 Private
->Legacy16CallOffset
,
1046 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
1047 Private
->LegacyRegion
->Lock (
1048 Private
->LegacyRegion
,
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.
1061 @param Private Legacy BIOS Instance data
1063 @retval EFI_SUCCESS Succeed.
1064 @retval EFI_ALREADY_STARTED All PCI devices have been processed.
1068 PciProgramAllInterruptLineRegisters (
1069 IN LEGACY_BIOS_INSTANCE
*Private
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
;
1080 EFI_HANDLE
*HandleBuffer
;
1081 UINTN MassStorageHandleCount
;
1082 EFI_HANDLE
*MassStorageHandleBuffer
;
1083 UINTN MassStorageHandleIndex
;
1090 EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
;
1091 UINTN RoutingTableEntries
;
1093 UINT16 LegEdgeLevel
;
1094 PCI_TYPE00 PciConfigHeader
;
1095 EFI_LEGACY_PIRQ_TABLE_HEADER
*PirqTable
;
1096 UINTN PirqTableSize
;
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.
1111 Legacy8259
= Private
->Legacy8259
;
1112 LegacyInterrupt
= Private
->LegacyInterrupt
;
1113 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
1115 LegacyBiosPlatform
->GetRoutingTable (
1116 Private
->LegacyBiosPlatform
,
1117 (VOID
*) &RoutingTable
,
1118 &RoutingTableEntries
,
1119 (VOID
*) &PirqTable
,
1124 CreateBridgeTable (RoutingTable
, RoutingTableEntries
);
1126 if (!Private
->PciInterruptLine
) {
1130 RoutingTableEntries
,
1136 Status
= gBS
->LocateHandleBuffer (
1138 &gEfiPciIoProtocolGuid
,
1143 if (EFI_ERROR (Status
)) {
1144 return EFI_NOT_FOUND
;
1146 if (HandleCount
== mHandleCount
) {
1147 FreePool (HandleBuffer
);
1148 return EFI_ALREADY_STARTED
;
1151 if (mHandleCount
== 0x00) {
1152 mHandleCount
= HandleCount
;
1155 for (Index
= 0; Index
< HandleCount
; Index
++) {
1157 // If VGA then only do VGA to allow drives fore time to spin up
1158 // otherwise assign PCI IRQs to all potential devices.
1160 if ((mVgaInstallationInProgress
) && (HandleBuffer
[Index
] != mVgaHandle
)) {
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.
1168 mHandleCount
= 0x00;
1171 Status
= gBS
->HandleProtocol (
1172 HandleBuffer
[Index
],
1173 &gEfiPciIoProtocolGuid
,
1176 ASSERT_EFI_ERROR (Status
);
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.
1184 EfiPciIoWidthUint32
,
1186 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1189 Command
= PciConfigHeader
.Hdr
.Command
;
1192 // Note PciIo->Attributes does not program the PCI command register
1194 Status
= PciIo
->Attributes (
1196 EfiPciIoAttributeOperationSupported
,
1200 if (!EFI_ERROR (Status
)) {
1201 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
1202 Status
= PciIo
->Attributes (
1204 EfiPciIoAttributeOperationEnable
,
1209 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x04, 1, &Command
);
1211 if (EFI_ERROR (Status
)) {
1215 InterruptPin
= PciConfigHeader
.Device
.InterruptPin
;
1217 if ((InterruptPin
!= 0) && (PciConfigHeader
.Device
.InterruptLine
== PCI_INT_LINE_UNKNOWN
)) {
1218 PciIo
->GetLocation (
1226 // Translate PIRQ index back thru busses to slot bus with InterruptPin
1231 Status
= GetBaseBus (
1239 if (Status
== EFI_NOT_FOUND
) {
1249 // Translate InterruptPin(0-3) into PIRQ
1251 Status
= LegacyBiosPlatform
->TranslatePirq (
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
1263 if (EFI_ERROR (Status
)) {
1264 DEBUG ((EFI_D_ERROR
, "Translate Pirq Failed - Status = %r\n ", Status
));
1268 LegacyInterrupt
->WritePirq (
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.
1279 Status
= LegacyBiosCheckPciRom (
1280 &Private
->LegacyBios
,
1281 HandleBuffer
[Index
],
1286 if ((EFI_ERROR (Status
)) && (PciConfigHeader
.Hdr
.ClassCode
[2] == PCI_CLASS_MASS_STORAGE
)) {
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
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
1300 MassStorageHandleCount
= 0;
1301 MassStorageHandleBuffer
= NULL
;
1302 LegacyBiosPlatform
->GetPlatformHandle (
1303 Private
->LegacyBiosPlatform
,
1304 EfiGetPlatformIdeHandle
,
1306 &MassStorageHandleBuffer
,
1307 &MassStorageHandleCount
,
1311 HddInfo
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
[0];
1313 LegacyBiosBuildIdeData (Private
, &HddInfo
, 0);
1316 EfiPciIoWidthUint32
,
1318 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1322 for (MassStorageHandleIndex
= 0; MassStorageHandleIndex
< MassStorageHandleCount
; MassStorageHandleIndex
++) {
1323 if (MassStorageHandleBuffer
[MassStorageHandleIndex
] == HandleBuffer
[Index
]) {
1325 // InstallLegacyIrqHandler according to Platform requirement
1327 InstallLegacyIrqHandler (
1338 // Write InterruptPin and enable 8259.
1347 Private
->IntThunk
->EfiToLegacy16BootTable
.PciIrqMask
= (UINT16
) (Private
->IntThunk
->EfiToLegacy16BootTable
.PciIrqMask
| (UINT16
) (1 << PciIrq
));
1349 Legacy8259
->GetMask (
1357 LegMask
= (UINT16
) (LegMask
& (UINT16
)~(1 << PciIrq
));
1358 LegEdgeLevel
= (UINT16
) (LegEdgeLevel
| (UINT16
) (1 << PciIrq
));
1359 Legacy8259
->SetMask (
1368 FreePool (HandleBuffer
);
1374 Find & verify PnP Expansion header in ROM image
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
1381 @retval EFI_SUCCESS Next Header found at BasePnpPtr
1382 @retval EFI_NOT_FOUND No more headers
1386 FindNextPnpExpansionHeader (
1387 IN LEGACY_BIOS_INSTANCE
*Private
,
1388 IN BOOLEAN FirstHeader
,
1389 IN OUT LEGACY_PNP_EXPANSION_HEADER
**PnpPtr
1394 LEGACY_PNP_EXPANSION_HEADER
*LocalPnpPtr
;
1395 LocalPnpPtr
= *PnpPtr
;
1396 if (FirstHeader
== FIRST_INSTANCE
) {
1397 mBasePnpPtr
= LocalPnpPtr
;
1398 mBbsRomSegment
= (UINT16
) ((UINTN
) mBasePnpPtr
>> 4);
1400 // Offset 0x1a gives offset to PnP expansion header for the first
1401 // instance, there after the structure gives the offset to the next
1404 LocalPnpPtr
= (LEGACY_PNP_EXPANSION_HEADER
*) ((UINT8
*) LocalPnpPtr
+ 0x1a);
1405 TempData
= (*((UINT16
*) LocalPnpPtr
));
1407 TempData
= (UINT16
) LocalPnpPtr
->NextHeader
;
1410 LocalPnpPtr
= (LEGACY_PNP_EXPANSION_HEADER
*) (((UINT8
*) mBasePnpPtr
+ TempData
));
1413 // Search for PnP table in Shadowed ROM
1415 *PnpPtr
= LocalPnpPtr
;
1416 if (*(UINT32
*) LocalPnpPtr
== SIGNATURE_32 ('$', 'P', 'n', 'P')) {
1419 return EFI_NOT_FOUND
;
1425 Update list of Bev or BCV table entries.
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
1432 @retval EFI_SUCCESS Always should succeed.
1437 IN LEGACY_BIOS_INSTANCE
*Private
,
1438 IN EFI_LEGACY_EXPANSION_ROM_HEADER
*RomStart
,
1439 IN EFI_PCI_IO_PROTOCOL
*PciIo
1443 BBS_TABLE
*BbsTable
;
1445 EFI_LEGACY_EXPANSION_ROM_HEADER
*PciPtr
;
1446 LEGACY_PNP_EXPANSION_HEADER
*PnpPtr
;
1460 DeviceType
= BBS_UNKNOWN
;
1463 // Skip floppy and 2*onboard IDE controller entries(Master/Slave per
1466 BbsIndex
= Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
;
1468 BbsTable
= (BBS_TABLE
*)(UINTN
) Private
->IntThunk
->EfiToLegacy16BootTable
.BbsTable
;
1469 PnpPtr
= (LEGACY_PNP_EXPANSION_HEADER
*) RomStart
;
1470 PciPtr
= (EFI_LEGACY_EXPANSION_ROM_HEADER
*) RomStart
;
1472 RomEnd
= (VOID
*) (PciPtr
->Size512
* 512 + (UINTN
) PciPtr
);
1473 Instance
= FIRST_INSTANCE
;
1475 // OPROMs like PXE may not be tied to a piece of hardware and thus
1476 // don't have a PciIo associated with them
1478 if (PciIo
!= NULL
) {
1479 PciIo
->GetLocation (
1494 if (Class
== PCI_CLASS_MASS_STORAGE
) {
1495 DeviceType
= BBS_HARDDISK
;
1497 if (Class
== PCI_CLASS_NETWORK
) {
1498 DeviceType
= BBS_EMBED_NETWORK
;
1504 Status
= FindNextPnpExpansionHeader (Private
, Instance
, &PnpPtr
);
1505 Instance
= NOT_FIRST_INSTANCE
;
1506 if (EFI_ERROR (Status
)) {
1510 // There can be additional $PnP headers within the OPROM.
1511 // Example: SCSI can have one per drive.
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
;
1533 // Have seen case where PXE base code have PnP expansion ROM
1534 // header but no Bcv or Bev vectors.
1536 if (PnpPtr
->Bcv
!= 0) {
1537 BbsTable
[BbsIndex
].BootHandlerOffset
= PnpPtr
->Bcv
;
1541 if (PnpPtr
->Bev
!= 0) {
1542 BbsTable
[BbsIndex
].BootHandlerOffset
= PnpPtr
->Bev
;
1543 BbsTable
[BbsIndex
].DeviceType
= BBS_BEV_DEVICE
;
1547 if ((PnpPtr
== (LEGACY_PNP_EXPANSION_HEADER
*) PciPtr
) || (PnpPtr
> (LEGACY_PNP_EXPANSION_HEADER
*) RomEnd
)) {
1552 BbsTable
[BbsIndex
].BootPriority
= BBS_IGNORE_ENTRY
;
1553 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
= (UINT32
) BbsIndex
;
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
1563 @param Private Protocol instance pointer.
1565 @retval EFI_SUCCESS Succeed.
1566 @retval EFI_UNSUPPORTED Cannot get VGA device handle.
1571 IN LEGACY_BIOS_INSTANCE
*Private
1575 EFI_PCI_IO_PROTOCOL
*PciIo
;
1579 EFI_HANDLE
*HandleBuffer
;
1580 EFI_HANDLE VgaHandle
;
1581 EFI_HANDLE FirstHandle
;
1584 PCI_TYPE00 PciConfigHeader
;
1589 // Make the VGA device first
1591 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
1592 Private
->LegacyBiosPlatform
,
1593 EfiGetPlatformVgaHandle
,
1599 if (EFI_ERROR (Status
)) {
1600 return EFI_UNSUPPORTED
;
1603 VgaHandle
= HandleBuffer
[0];
1605 Status
= gBS
->LocateHandleBuffer (
1607 &gEfiPciIoProtocolGuid
,
1613 if (EFI_ERROR (Status
)) {
1617 // Place the VGA handle as first.
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
;
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.
1631 Command
= (UINT16
*) AllocatePool (
1632 sizeof (UINT16
) * (HandleCount
+ 1)
1634 if (NULL
== Command
) {
1635 FreePool (HandleBuffer
);
1636 return EFI_OUT_OF_RESOURCES
;
1639 // Disconnect all EFI devices first. This covers cases where alegacy BIOS
1640 // may control multiple PCI devices.
1642 for (Index
= 0; Index
< HandleCount
; Index
++) {
1644 Status
= gBS
->HandleProtocol (
1645 HandleBuffer
[Index
],
1646 &gEfiPciIoProtocolGuid
,
1649 ASSERT_EFI_ERROR (Status
);
1652 // Save command register for "connect" loop
1656 EfiPciIoWidthUint32
,
1658 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1661 Command
[Index
] = PciConfigHeader
.Hdr
.Command
;
1663 // Skip any device that already has a legacy ROM run
1665 Status
= IsLegacyRom (HandleBuffer
[Index
]);
1666 if (!EFI_ERROR (Status
)) {
1670 // Stop EFI Drivers with oprom.
1672 gBS
->DisconnectController (
1673 HandleBuffer
[Index
],
1679 // For every device that has not had a legacy ROM started. Start a legacy ROM.
1681 for (Index
= 0; Index
< HandleCount
; Index
++) {
1683 Status
= gBS
->HandleProtocol (
1684 HandleBuffer
[Index
],
1685 &gEfiPciIoProtocolGuid
,
1689 ASSERT_EFI_ERROR (Status
);
1692 // Here make sure if one VGA have been shadowed,
1693 // then wil not shadowed another one.
1697 EfiPciIoWidthUint32
,
1699 sizeof (Pci
) / sizeof (UINT32
),
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).
1708 if (IS_PCI_DISPLAY (&Pci
) && Index
!= 0) {
1712 // Skip any device that already has a legacy ROM run
1714 Status
= IsLegacyRom (HandleBuffer
[Index
]);
1715 if (!EFI_ERROR (Status
)) {
1720 // If legacy VBIOS Oprom has not been dispatched before, install legacy VBIOS here.
1722 if (IS_PCI_DISPLAY (&Pci
) && Index
== 0) {
1723 Status
= LegacyBiosInstallVgaRom (Private
);
1725 // A return status of EFI_NOT_FOUND is considered valid (No EFI
1726 // driver is controlling video).
1728 ASSERT ((Status
== EFI_SUCCESS
) || (Status
== EFI_NOT_FOUND
));
1733 // Install legacy ROM
1735 Status
= LegacyBiosInstallPciRom (
1736 &Private
->LegacyBios
,
1737 HandleBuffer
[Index
],
1742 (VOID
**) &RomStart
,
1745 if (EFI_ERROR (Status
)) {
1746 if (!((Status
== EFI_UNSUPPORTED
) && (Flags
== NO_ROM
))) {
1751 // Restore Command register so legacy has same devices enabled or disabled
1753 // If Flags = NO_ROM use command register as is. This covers the
1755 // Device has no ROMs associated with it.
1756 // Device has ROM associated with it but was already
1758 // = ROM_FOUND but not VALID_LEGACY_ROM, disable it.
1759 // = ROM_FOUND and VALID_LEGACY_ROM, enable it.
1761 if ((Flags
& ROM_FOUND
) == ROM_FOUND
) {
1762 if ((Flags
& VALID_LEGACY_ROM
) == 0) {
1766 // For several VGAs, only one of them can be enabled.
1768 Status
= PciIo
->Attributes (
1770 EfiPciIoAttributeOperationSupported
,
1774 if (!EFI_ERROR (Status
)) {
1775 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
1776 Status
= PciIo
->Attributes (
1778 EfiPciIoAttributeOperationEnable
,
1783 if (!EFI_ERROR (Status
)) {
1784 Command
[Index
] = 0x1f;
1791 EfiPciIoWidthUint16
,
1799 FreePool (HandleBuffer
);
1805 Test to see if a legacy PCI ROM exists for this device. Optionally return
1806 the Legacy ROM instance for this PCI device.
1808 @param This Protocol instance pointer.
1809 @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
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.
1815 @retval EFI_SUCCESS Legacy Option ROM available for this device
1816 @retval EFI_UNSUPPORTED Legacy Option ROM not supported.
1821 LegacyBiosCheckPciRom (
1822 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1823 IN EFI_HANDLE PciHandle
,
1824 OUT VOID
**RomImage
, OPTIONAL
1825 OUT UINTN
*RomSize
, OPTIONAL
1829 return LegacyBiosCheckPciRomEx (
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.
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
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.
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
1875 LEGACY_BIOS_INSTANCE
*Private
;
1876 EFI_PCI_IO_PROTOCOL
*PciIo
;
1878 VOID
*LocalRomImage
;
1879 PCI_TYPE00 PciConfigHeader
;
1880 VOID
*LocalConfigUtilityCodeHeader
;
1882 LocalConfigUtilityCodeHeader
= NULL
;
1884 Status
= gBS
->HandleProtocol (
1886 &gEfiPciIoProtocolGuid
,
1889 if (EFI_ERROR (Status
)) {
1890 return EFI_UNSUPPORTED
;
1894 // See if the option ROM for PciHandle has already been executed
1896 Status
= IsLegacyRom (PciHandle
);
1897 if (!EFI_ERROR (Status
)) {
1898 *Flags
|= (UINTN
)(ROM_FOUND
| VALID_LEGACY_ROM
);
1902 // Check for PCI ROM Bar
1904 LocalRomSize
= (UINTN
) PciIo
->RomSize
;
1905 LocalRomImage
= PciIo
->RomImage
;
1906 if (LocalRomSize
!= 0) {
1907 *Flags
|= ROM_FOUND
;
1911 // PCI specification states you should check VendorId and Device Id.
1915 EfiPciIoWidthUint32
,
1917 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1921 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1922 Status
= GetPciLegacyRom (
1923 Private
->Csm16PciInterfaceVersion
,
1924 PciConfigHeader
.Hdr
.VendorId
,
1925 PciConfigHeader
.Hdr
.DeviceId
,
1930 &LocalConfigUtilityCodeHeader
1932 if (EFI_ERROR (Status
)) {
1933 return EFI_UNSUPPORTED
;
1936 *Flags
|= VALID_LEGACY_ROM
;
1939 // See if Configuration Utility Code Header valid
1941 if (LocalConfigUtilityCodeHeader
!= NULL
) {
1942 *Flags
|= ROM_WITH_CONFIG
;
1945 if (ConfigUtilityCodeHeader
!= NULL
) {
1946 *ConfigUtilityCodeHeader
= LocalConfigUtilityCodeHeader
;
1949 if (RomImage
!= NULL
) {
1950 *RomImage
= LocalRomImage
;
1953 if (RomSize
!= NULL
) {
1954 *RomSize
= LocalRomSize
;
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:
1965 @retval EFI_SUCCESS Legacy ROM loaded for this device
1966 @retval EFI_NOT_FOUND No PS2 Keyboard found
1975 EFI_HANDLE
*HandleBuffer
;
1977 EFI_ISA_IO_PROTOCOL
*IsaIo
;
1981 // Get SimpleTextIn and find PS2 controller
1983 Status
= gBS
->LocateHandleBuffer (
1985 &gEfiSimpleTextInProtocolGuid
,
1990 if (EFI_ERROR (Status
)) {
1991 return EFI_NOT_FOUND
;
1993 for (Index
= 0; Index
< HandleCount
; Index
++) {
1995 // Open the IO Abstraction(s) needed to perform the supported test
1997 Status
= gBS
->OpenProtocol (
1998 HandleBuffer
[Index
],
1999 &gEfiIsaIoProtocolGuid
,
2002 HandleBuffer
[Index
],
2003 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
2006 if (!EFI_ERROR (Status
)) {
2008 // Use the ISA I/O Protocol to see if Controller is the Keyboard
2011 if (IsaIo
->ResourceList
->Device
.HID
!= EISA_PNP_ID (0x303) || IsaIo
->ResourceList
->Device
.UID
!= 0) {
2012 Status
= EFI_UNSUPPORTED
;
2015 gBS
->CloseProtocol (
2016 HandleBuffer
[Index
],
2017 &gEfiIsaIoProtocolGuid
,
2023 if (!EFI_ERROR (Status
)) {
2024 gBS
->ConnectController (HandleBuffer
[Index
], NULL
, NULL
, FALSE
);
2027 FreePool (HandleBuffer
);
2033 Load a legacy PC-AT OpROM for VGA controller.
2035 @param Private Driver private data.
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.
2044 LegacyBiosInstallVgaRom (
2045 IN LEGACY_BIOS_INSTANCE
*Private
2049 EFI_HANDLE VgaHandle
;
2051 EFI_HANDLE
*HandleBuffer
;
2052 EFI_HANDLE
*ConnectHandleBuffer
;
2053 EFI_PCI_IO_PROTOCOL
*PciIo
;
2054 PCI_TYPE00 PciConfigHeader
;
2056 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
2062 // EfiLegacyBiosGuild attached to a device implies that there is a legacy
2063 // BIOS associated with that device.
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.
2079 // Get the VGA device.
2081 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
2082 Private
->LegacyBiosPlatform
,
2083 EfiGetPlatformVgaHandle
,
2089 if (EFI_ERROR (Status
)) {
2090 return EFI_DEVICE_ERROR
;
2093 VgaHandle
= HandleBuffer
[0];
2096 // Check whether video thunk driver already starts.
2098 Status
= gBS
->OpenProtocolInformation (
2100 &gEfiPciIoProtocolGuid
,
2104 if (EFI_ERROR (Status
)) {
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
2115 if (!EFI_ERROR (Status
)) {
2117 // This should be video thunk driver which is managing video device
2118 // So it need not start again
2120 DEBUG ((EFI_D_INFO
, "Video thunk driver already start! Return!\n"));
2121 Private
->VgaInstalled
= TRUE
;
2128 // Kick off the native EFI driver
2130 Status
= gBS
->DisconnectController (
2135 if (EFI_ERROR (Status
)) {
2136 if (Status
!= EFI_NOT_FOUND
) {
2137 return EFI_DEVICE_ERROR
;
2143 // Find all the Thunk Driver
2145 HandleBuffer
= NULL
;
2146 Status
= gBS
->LocateHandleBuffer (
2148 &gEfiLegacyBiosGuid
,
2153 ASSERT_EFI_ERROR (Status
);
2154 ConnectHandleBuffer
= (EFI_HANDLE
*) AllocatePool (sizeof (EFI_HANDLE
) * (HandleCount
+ 1));
2155 ASSERT (ConnectHandleBuffer
!= NULL
);
2158 ConnectHandleBuffer
,
2160 sizeof (EFI_HANDLE
) * HandleCount
2162 ConnectHandleBuffer
[HandleCount
] = NULL
;
2164 FreePool (HandleBuffer
);
2167 // Enable the device and make sure VGA cycles are being forwarded to this VGA device
2169 Status
= gBS
->HandleProtocol (
2171 &gEfiPciIoProtocolGuid
,
2174 ASSERT_EFI_ERROR (Status
);
2177 EfiPciIoWidthUint32
,
2179 sizeof (PciConfigHeader
) / sizeof (UINT32
),
2183 Status
= PciIo
->Attributes (
2185 EfiPciIoAttributeOperationSupported
,
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 (
2194 EfiPciIoAttributeOperationEnable
,
2200 if (Status
== EFI_SUCCESS
) {
2201 Private
->VgaInstalled
= TRUE
;
2204 // Attach the VGA thunk driver.
2205 // Assume the video is installed. This prevents potential of infinite recursion.
2207 Status
= gBS
->ConnectController (
2209 ConnectHandleBuffer
,
2215 FreePool (ConnectHandleBuffer
);
2217 if (EFI_ERROR (Status
)) {
2219 Private
->VgaInstalled
= FALSE
;
2222 // Reconnect the EFI VGA driver.
2224 gBS
->ConnectController (VgaHandle
, NULL
, NULL
, TRUE
);
2225 return EFI_DEVICE_ERROR
;
2233 Load a legacy PC-AT OpROM.
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
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
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
2249 @param DiskEnd Disk number of the last device hooked by the ROM.
2250 @param RomShadowAddress Shadow address of PC-AT ROM
2252 @retval EFI_SUCCESS Legacy ROM loaded for this device
2253 @retval EFI_OUT_OF_RESOURCES No more space for this ROM
2258 LegacyBiosInstallRom (
2259 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
2260 IN LEGACY_BIOS_INSTANCE
*Private
,
2261 IN EFI_HANDLE PciHandle
,
2262 IN UINT8 OpromRevision
,
2265 IN OUT UINTN
*RuntimeImageLength
,
2266 OUT UINT8
*DiskStart
, OPTIONAL
2267 OUT UINT8
*DiskEnd
, OPTIONAL
2268 OUT VOID
**RomShadowAddress OPTIONAL
2272 EFI_STATUS PciEnableStatus
;
2273 EFI_PCI_IO_PROTOCOL
*PciIo
;
2274 UINT8 LocalDiskStart
;
2280 EFI_IA32_REGISTER_SET Regs
;
2285 UINT32 StartBbsIndex
;
2290 UINTN RuntimeAddress
;
2291 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
2302 PhysicalAddress
= 0;
2303 MaxRomAddr
= PcdGet32 (PcdEndOpromShadowAddress
);
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
;
2313 PciProgramAllInterruptLineRegisters (Private
);
2315 if ((OpromRevision
>= 3) && (Private
->Csm16PciInterfaceVersion
>= 0x0300)) {
2317 // CSM16 3.0 meets PCI 3.0 OpROM
2318 // first test if there is enough space for its INIT code
2320 PhysicalAddress
= CONVENTIONAL_MEMORY_TOP
;
2321 Status
= gBS
->AllocatePages (
2323 EfiBootServicesCode
,
2324 EFI_SIZE_TO_PAGES (ImageSize
),
2328 if (EFI_ERROR (Status
)) {
2329 DEBUG ((EFI_D_ERROR
, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__
));
2331 // Report Status Code to indicate that there is no enough space for OpROM
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
)
2337 return EFI_OUT_OF_RESOURCES
;
2339 InitAddress
= (UINTN
) PhysicalAddress
;
2341 // then test if there is enough space for its RT code
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
));
2348 // Report Status Code to indicate that there is no enough space for OpROM
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
)
2354 return EFI_OUT_OF_RESOURCES
;
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
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__
));
2365 // Report Status Code to indicate that there is no enough space for OpROM
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
)
2371 return EFI_OUT_OF_RESOURCES
;
2374 RuntimeAddress
= InitAddress
;
2377 Private
->LegacyRegion
->UnLock (
2378 Private
->LegacyRegion
,
2384 Private
->LegacyRegion
->UnLock (
2385 Private
->LegacyRegion
,
2386 (UINT32
) RuntimeAddress
,
2391 DEBUG ((EFI_D_INFO
, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress
, RuntimeAddress
, ImageSize
));
2393 CopyMem ((VOID
*) InitAddress
, RomImage
, ImageSize
);
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
2404 LocalDiskStart
= (UINT8
) ((*(UINT8
*) ((UINTN
) 0x475)) + 0x80);
2405 if ((Private
->Disk4075
+ 0x80) < LocalDiskStart
) {
2407 // Update table since onboard IDE drives found
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
;
2420 if (PciHandle
!= mVgaHandle
) {
2422 EnablePs2Keyboard ();
2425 // Store current mode settings since PrepareToScanRom may change mode.
2427 VideoMode
= *(UINT8
*) ((UINTN
) (0x400 + BDA_VIDEO_MODE
));
2430 // Notify the platform that we are about to scan the ROM
2432 Status
= Private
->LegacyBiosPlatform
->PlatformHooks (
2433 Private
->LegacyBiosPlatform
,
2434 EfiPlatformHookPrepareToScanRom
,
2443 // If Status returned is EFI_UNSUPPORTED then abort due to platform
2446 if (Status
== EFI_UNSUPPORTED
) {
2451 // Report corresponding status code
2453 REPORT_STATUS_CODE (
2455 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_CSM_LEGACY_ROM_INIT
)
2459 // Generate number of ticks since midnight for BDA. Some OPROMs require
2460 // this. Place result in 40:6C-6F
2462 gRT
->GetTime (&BootTime
, NULL
);
2463 LocalTime
= BootTime
.Hour
* 3600 + BootTime
.Minute
* 60 + BootTime
.Second
;
2466 // Multiply result by 18.2 for number of ticks since midnight.
2467 // Use 182/10 to avoid floating point math.
2469 LocalTime
= (LocalTime
* 182) / 10;
2470 BdaPtr
= (UINT32
*) ((UINTN
) 0x46C);
2471 *BdaPtr
= LocalTime
;
2474 // Pass in handoff data
2476 PciEnableStatus
= EFI_UNSUPPORTED
;
2477 ZeroMem (&Regs
, sizeof (Regs
));
2478 if (PciHandle
!= NULL
) {
2480 Status
= gBS
->HandleProtocol (
2482 &gEfiPciIoProtocolGuid
,
2485 ASSERT_EFI_ERROR (Status
);
2488 // Enable command register.
2490 PciEnableStatus
= PciIo
->Attributes (
2492 EfiPciIoAttributeOperationEnable
,
2493 EFI_PCI_DEVICE_ENABLE
,
2497 PciIo
->GetLocation (
2504 DEBUG ((EFI_D_INFO
, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus
, Device
, Function
));
2507 mIgnoreBbsUpdateFlag
= FALSE
;
2508 Regs
.X
.AX
= Legacy16DispatchOprom
;
2511 // Generate DispatchOpRomTable data
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
);
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
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
,
2542 if (Private
->IntThunk
->DispatchOpromTable
.NumberBbsEntries
!= (UINT8
) Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
) {
2543 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
= (UINT8
) Private
->IntThunk
->DispatchOpromTable
.NumberBbsEntries
;
2544 mIgnoreBbsUpdateFlag
= TRUE
;
2547 // Check if non-BBS compliant drives found
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;
2561 // Skip video mode set, if installing VGA
2563 if (PciHandle
!= mVgaHandle
) {
2565 // Set mode settings since PrepareToScanRom may change mode
2567 if (VideoMode
!= *(UINT8
*) ((UINTN
) (0x400 + BDA_VIDEO_MODE
))) {
2569 // The active video mode is changed, restore it to original mode.
2572 Regs
.H
.AL
= VideoMode
;
2573 Private
->LegacyBios
.Int86 (&Private
->LegacyBios
, 0x10, &Regs
);
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.
2581 // The ROM could have updated it's size so we need to read again.
2583 if (((EFI_LEGACY_EXPANSION_ROM_HEADER
*) RuntimeAddress
)->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
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.
2588 *RuntimeImageLength
= 0;
2590 *RuntimeImageLength
= ((EFI_LEGACY_EXPANSION_ROM_HEADER
*) RuntimeAddress
)->Size512
* 512;
2593 DEBUG ((EFI_D_INFO
, " fsize = %x\n", *RuntimeImageLength
));
2596 // If OpROM runs in 2.0 mode
2598 if (PhysicalAddress
== 0) {
2599 if (*RuntimeImageLength
< ImageSize
) {
2601 // Make area from end of shadowed rom to end of original rom all ffs
2603 gBS
->SetMem ((VOID
*) (InitAddress
+ *RuntimeImageLength
), ImageSize
- *RuntimeImageLength
, 0xff);
2607 LocalDiskEnd
= (UINT8
) ((*(UINT8
*) ((UINTN
) 0x475)) + 0x80);
2610 // Allow platform to perform any required actions after the
2611 // OPROM has been initialized.
2613 Status
= Private
->LegacyBiosPlatform
->PlatformHooks (
2614 Private
->LegacyBiosPlatform
,
2615 EfiPlatformHookAfterRomInit
,
2622 if (PciHandle
!= NULL
) {
2624 // If no PCI Handle then no header or Bevs.
2626 if ((*RuntimeImageLength
!= 0) && (!mIgnoreBbsUpdateFlag
)) {
2627 StartBbsIndex
= Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
;
2628 TempData
= RuntimeAddress
;
2631 (EFI_LEGACY_EXPANSION_ROM_HEADER
*) TempData
,
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;
2648 // Mark PCI device as having a legacy BIOS ROM loaded.
2652 (UINT32
) RuntimeAddress
,
2653 (UINT32
) *RuntimeImageLength
,
2660 // Stuff caller's OPTIONAL return parameters.
2662 if (RomShadowAddress
!= NULL
) {
2663 *RomShadowAddress
= (VOID
*) RuntimeAddress
;
2666 if (DiskStart
!= NULL
) {
2667 *DiskStart
= LocalDiskStart
;
2670 if (DiskEnd
!= NULL
) {
2671 *DiskEnd
= LocalDiskEnd
;
2674 Private
->OptionRom
= (UINT32
) (RuntimeAddress
+ *RuntimeImageLength
);
2676 Status
= EFI_SUCCESS
;
2679 if (PhysicalAddress
!= 0) {
2681 // Free pages when OpROM is 3.0
2683 gBS
->FreePages (PhysicalAddress
, EFI_SIZE_TO_PAGES (ImageSize
));
2687 // Insure all shadowed areas are locked
2689 Private
->LegacyRegion
->Lock (
2690 Private
->LegacyRegion
,
2700 Let IOMMU grant DMA access for the PCI device.
2702 @param PciHandle The EFI handle for the PCI device.
2703 @param HostAddress The system memory address to map to the PCI controller.
2704 @param NumberOfBytes The number of bytes to map.
2706 @retval EFI_SUCCESS The DMA access is granted.
2710 IN EFI_HANDLE PciHandle
,
2711 IN EFI_PHYSICAL_ADDRESS HostAddress
,
2712 IN UINTN NumberOfBytes
2715 EFI_PHYSICAL_ADDRESS DeviceAddress
;
2719 if (PciHandle
== NULL
) {
2720 return EFI_UNSUPPORTED
;
2723 Status
= EFI_SUCCESS
;
2724 if (mIoMmu
== NULL
) {
2725 gBS
->LocateProtocol (&gEdkiiIoMmuProtocolGuid
, NULL
, (VOID
**)&mIoMmu
);
2727 if (mIoMmu
!= NULL
) {
2728 Status
= mIoMmu
->Map (
2730 EdkiiIoMmuOperationBusMasterCommonBuffer
,
2731 (VOID
*)(UINTN
)HostAddress
,
2736 if (EFI_ERROR(Status
)) {
2737 DEBUG ((DEBUG_ERROR
, "LegacyPci - IoMmuMap - %r\n", Status
));
2739 ASSERT (DeviceAddress
== HostAddress
);
2740 Status
= mIoMmu
->SetAttribute (
2744 EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
2746 if (EFI_ERROR(Status
)) {
2747 DEBUG ((DEBUG_ERROR
, "LegacyPci - IoMmuSetAttribute - %r\n", Status
));
2755 Load a legacy PC-AT OPROM on the PciHandle device. Return information
2756 about how many disks were added by the OPROM and the shadow address and
2757 size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
2759 @param This Protocol instance pointer.
2760 @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
2761 be loaded. This value is NULL if RomImage is
2762 non-NULL. This is the normal case.
2763 @param RomImage A PCI PC-AT ROM image. This argument is non-NULL
2764 if there is no hardware associated with the ROM
2765 and thus no PciHandle, otherwise is must be NULL.
2766 Example is PXE base code.
2767 @param Flags Indicates if ROM found and if PC-AT.
2768 @param DiskStart Disk number of first device hooked by the ROM. If
2769 DiskStart is the same as DiskEnd no disked were
2771 @param DiskEnd Disk number of the last device hooked by the ROM.
2772 @param RomShadowAddress Shadow address of PC-AT ROM
2773 @param RomShadowedSize Size of RomShadowAddress in bytes
2775 @retval EFI_SUCCESS Legacy ROM loaded for this device
2776 @retval EFI_INVALID_PARAMETER PciHandle not found
2777 @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard
2783 LegacyBiosInstallPciRom (
2784 IN EFI_LEGACY_BIOS_PROTOCOL
* This
,
2785 IN EFI_HANDLE PciHandle
,
2788 OUT UINT8
*DiskStart
, OPTIONAL
2789 OUT UINT8
*DiskEnd
, OPTIONAL
2790 OUT VOID
**RomShadowAddress
, OPTIONAL
2791 OUT UINT32
*RomShadowedSize OPTIONAL
2795 LEGACY_BIOS_INSTANCE
*Private
;
2796 VOID
*LocalRomImage
;
2798 UINTN RuntimeImageLength
;
2799 EFI_PCI_IO_PROTOCOL
*PciIo
;
2800 PCI_TYPE01 PciConfigHeader
;
2802 EFI_HANDLE
*HandleBuffer
;
2809 UINT8 OpromRevision
;
2811 PCI_3_0_DATA_STRUCTURE
*Pcir
;
2815 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
2816 if (Private
->Legacy16Table
->LastPciBus
== 0) {
2818 // Get last bus number if not already found
2820 Status
= gBS
->LocateHandleBuffer (
2822 &gEfiPciIoProtocolGuid
,
2829 for (Index
= 0; Index
< HandleCount
; Index
++) {
2830 Status
= gBS
->HandleProtocol (
2831 HandleBuffer
[Index
],
2832 &gEfiPciIoProtocolGuid
,
2835 if (EFI_ERROR (Status
)) {
2839 Status
= PciIo
->GetLocation (
2846 if (PciBus
> LastBus
) {
2851 Private
->LegacyRegion
->UnLock (
2852 Private
->LegacyRegion
,
2857 Private
->Legacy16Table
->LastPciBus
= (UINT8
) LastBus
;
2858 Private
->LegacyRegion
->Lock (
2859 Private
->LegacyRegion
,
2867 if ((PciHandle
!= NULL
) && (RomImage
== NULL
)) {
2869 // If PciHandle has OpRom to Execute
2870 // and OpRom are all associated with Hardware
2872 Status
= gBS
->HandleProtocol (
2874 &gEfiPciIoProtocolGuid
,
2878 if (!EFI_ERROR (Status
)) {
2881 EfiPciIoWidthUint32
,
2883 sizeof (PciConfigHeader
) / sizeof (UINT32
),
2888 // if video installed & OPROM is video return
2892 ((PciConfigHeader
.Hdr
.ClassCode
[2] == PCI_CLASS_OLD
) &&
2893 (PciConfigHeader
.Hdr
.ClassCode
[1] == PCI_CLASS_OLD_VGA
))
2895 ((PciConfigHeader
.Hdr
.ClassCode
[2] == PCI_CLASS_DISPLAY
) &&
2896 (PciConfigHeader
.Hdr
.ClassCode
[1] == PCI_CLASS_DISPLAY_VGA
))
2899 (!Private
->VgaInstalled
)
2901 mVgaInstallationInProgress
= TRUE
;
2904 // return EFI_UNSUPPORTED;
2909 // To run any legacy image, the VGA needs to be installed first.
2910 // if installing the video, then don't need the thunk as already installed.
2912 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
2913 Private
->LegacyBiosPlatform
,
2914 EfiGetPlatformVgaHandle
,
2921 if (!EFI_ERROR (Status
)) {
2922 mVgaHandle
= HandleBuffer
[0];
2923 if ((!Private
->VgaInstalled
) && (PciHandle
!= mVgaHandle
)) {
2925 // A return status of EFI_NOT_FOUND is considered valid (No EFI
2926 // driver is controlling video.
2928 mVgaInstallationInProgress
= TRUE
;
2929 Status
= LegacyBiosInstallVgaRom (Private
);
2930 if (EFI_ERROR (Status
)) {
2931 if (Status
!= EFI_NOT_FOUND
) {
2932 mVgaInstallationInProgress
= FALSE
;
2936 mVgaInstallationInProgress
= FALSE
;
2941 // See if the option ROM for PciHandle has already been executed
2943 Status
= IsLegacyRom (PciHandle
);
2945 if (!EFI_ERROR (Status
)) {
2946 mVgaInstallationInProgress
= FALSE
;
2947 GetShadowedRomParameters (
2952 (UINTN
*) RomShadowedSize
2957 Status
= LegacyBiosCheckPciRomEx (
2958 &Private
->LegacyBios
,
2962 &RuntimeImageLength
,
2967 if (EFI_ERROR (Status
)) {
2969 // There is no PCI ROM in the ROM BAR or no onboard ROM
2971 mVgaInstallationInProgress
= FALSE
;
2972 return EFI_UNSUPPORTED
;
2975 if ((RomImage
== NULL
) || (*RomImage
== NULL
)) {
2977 // If PciHandle is NULL, and no OpRom is to be associated
2979 mVgaInstallationInProgress
= FALSE
;
2980 return EFI_UNSUPPORTED
;
2983 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
2984 Private
->LegacyBiosPlatform
,
2985 EfiGetPlatformVgaHandle
,
2991 if ((!EFI_ERROR (Status
)) && (!Private
->VgaInstalled
)) {
2993 // A return status of EFI_NOT_FOUND is considered valid (No EFI
2994 // driver is controlling video.
2996 mVgaInstallationInProgress
= TRUE
;
2997 Status
= LegacyBiosInstallVgaRom (Private
);
2998 if (EFI_ERROR (Status
)) {
2999 if (Status
!= EFI_NOT_FOUND
) {
3000 mVgaInstallationInProgress
= FALSE
;
3004 mVgaInstallationInProgress
= FALSE
;
3008 LocalRomImage
= *RomImage
;
3009 if (((PCI_EXPANSION_ROM_HEADER
*) LocalRomImage
)->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
||
3010 ((PCI_EXPANSION_ROM_HEADER
*) LocalRomImage
)->PcirOffset
== 0 ||
3011 (((PCI_EXPANSION_ROM_HEADER
*) LocalRomImage
)->PcirOffset
& 3 ) != 0) {
3012 mVgaInstallationInProgress
= FALSE
;
3013 return EFI_UNSUPPORTED
;
3016 Pcir
= (PCI_3_0_DATA_STRUCTURE
*)
3017 ((UINT8
*) LocalRomImage
+ ((PCI_EXPANSION_ROM_HEADER
*) LocalRomImage
)->PcirOffset
);
3019 if ((Pcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) || (Pcir
->CodeType
!= PCI_CODE_TYPE_PCAT_IMAGE
)) {
3020 mVgaInstallationInProgress
= FALSE
;
3021 return EFI_UNSUPPORTED
;
3024 ImageSize
= Pcir
->ImageLength
* 512;
3025 if (Pcir
->Length
>= 0x1C) {
3026 OpromRevision
= Pcir
->Revision
;
3030 if (Pcir
->Revision
< 3) {
3031 RuntimeImageLength
= 0;
3033 RuntimeImageLength
= Pcir
->MaxRuntimeImageLength
* 512;
3038 // Grant access for below 1M
3039 // BDA/EBDA/LowPMM and scratch memory for OPROM.
3041 IoMmuGrantAccess (PciHandle
, 0, SIZE_1MB
);
3043 // Grant access for HiPmm
3047 Private
->IntThunk
->EfiToLegacy16InitTable
.HiPmmMemory
,
3048 Private
->IntThunk
->EfiToLegacy16InitTable
.HiPmmMemorySizeInBytes
3052 // Shadow and initialize the OpROM.
3054 ASSERT (Private
->TraceIndex
< 0x200);
3055 Private
->Trace
[Private
->TraceIndex
] = LEGACY_PCI_TRACE_000
;
3056 Private
->TraceIndex
++;
3057 Private
->TraceIndex
= (UINT16
) (Private
->TraceIndex
% 0x200);
3058 Status
= LegacyBiosInstallRom (
3065 &RuntimeImageLength
,
3070 if (RomShadowedSize
!= NULL
) {
3071 *RomShadowedSize
= (UINT32
) RuntimeImageLength
;
3074 mVgaInstallationInProgress
= FALSE
;