3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "LegacyBiosInterface.h"
10 #include <IndustryStandard/Pci30.h>
12 #define PCI_START_ADDRESS(x) (((x) + 0x7ff) & ~0x7ff)
14 #define MAX_BRIDGE_INDEX 0x20
25 #define ROM_MAX_ENTRIES 24
26 BRIDGE_TABLE Bridges
[MAX_BRIDGE_INDEX
];
27 UINTN SortedBridgeIndex
[MAX_BRIDGE_INDEX
];
28 UINTN NumberOfBridges
;
29 LEGACY_PNP_EXPANSION_HEADER
*mBasePnpPtr
;
30 UINT16 mBbsRomSegment
;
32 EFI_HANDLE mVgaHandle
;
33 BOOLEAN mIgnoreBbsUpdateFlag
;
34 BOOLEAN mVgaInstallationInProgress
= FALSE
;
35 UINT32 mRomCount
= 0x00;
36 ROM_INSTANCE_ENTRY mRomEntry
[ROM_MAX_ENTRIES
];
37 EDKII_IOMMU_PROTOCOL
*mIoMmu
;
40 Query shadowed legacy ROM parameters registered by RomShadow() previously.
42 @param PciHandle PCI device whos ROM has been shadowed
43 @param DiskStart DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
44 @param DiskEnd DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
45 @param RomShadowAddress Address where ROM was shadowed
46 @param ShadowedSize Runtime size of ROM
48 @retval EFI_SUCCESS Query Logging successful.
49 @retval EFI_NOT_FOUND No logged data found about PciHandle.
53 GetShadowedRomParameters (
54 IN EFI_HANDLE PciHandle
,
55 OUT UINT8
*DiskStart
, OPTIONAL
56 OUT UINT8
*DiskEnd
, OPTIONAL
57 OUT VOID
**RomShadowAddress
, OPTIONAL
58 OUT UINTN
*ShadowedSize OPTIONAL
62 EFI_PCI_IO_PROTOCOL
*PciIo
;
70 // Get the PCI I/O Protocol on PciHandle
72 Status
= gBS
->HandleProtocol (
74 &gEfiPciIoProtocolGuid
,
77 if (EFI_ERROR (Status
)) {
82 // Get the location of the PCI device
92 for(Index
= 0; Index
< mRomCount
; Index
++) {
93 if ((mRomEntry
[Index
].PciSegment
== PciSegment
) &&
94 (mRomEntry
[Index
].PciBus
== PciBus
) &&
95 (mRomEntry
[Index
].PciDevice
== PciDevice
) &&
96 (mRomEntry
[Index
].PciFunction
== PciFunction
)) {
101 if (Index
== mRomCount
) {
102 return EFI_NOT_FOUND
;
105 if (DiskStart
!= NULL
) {
106 *DiskStart
= mRomEntry
[Index
].DiskStart
;
109 if (DiskEnd
!= NULL
) {
110 *DiskEnd
= mRomEntry
[Index
].DiskEnd
;
113 if (RomShadowAddress
!= NULL
) {
114 *RomShadowAddress
= (VOID
*)(UINTN
)mRomEntry
[Index
].ShadowAddress
;
117 if (ShadowedSize
!= NULL
) {
118 *ShadowedSize
= mRomEntry
[Index
].ShadowedSize
;
125 Every legacy ROM that is shadowed by the Legacy BIOS driver will be
126 registered into this API so that the policy code can know what has
129 @param PciHandle PCI device whos ROM is being shadowed
130 @param ShadowAddress Address that ROM was shadowed
131 @param ShadowedSize Runtime size of ROM
132 @param DiskStart DiskStart value from
133 EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
134 @param DiskEnd DiskEnd value from
135 EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
137 @retval EFI_SUCCESS Logging successful.
138 @retval EFI_OUT_OF_RESOURCES No remaining room for registering another option
144 IN EFI_HANDLE PciHandle
,
145 IN UINT32 ShadowAddress
,
146 IN UINT32 ShadowedSize
,
152 EFI_PCI_IO_PROTOCOL
*PciIo
;
155 // See if there is room to register another option ROM
157 if (mRomCount
>= ROM_MAX_ENTRIES
) {
158 return EFI_OUT_OF_RESOURCES
;
161 // Get the PCI I/O Protocol on PciHandle
163 Status
= gBS
->HandleProtocol (
165 &gEfiPciIoProtocolGuid
,
168 if (EFI_ERROR (Status
)) {
172 // Get the location of the PCI device
176 &mRomEntry
[mRomCount
].PciSegment
,
177 &mRomEntry
[mRomCount
].PciBus
,
178 &mRomEntry
[mRomCount
].PciDevice
,
179 &mRomEntry
[mRomCount
].PciFunction
181 mRomEntry
[mRomCount
].ShadowAddress
= ShadowAddress
;
182 mRomEntry
[mRomCount
].ShadowedSize
= ShadowedSize
;
183 mRomEntry
[mRomCount
].DiskStart
= DiskStart
;
184 mRomEntry
[mRomCount
].DiskEnd
= DiskEnd
;
193 Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This
194 information represents every call to RomShadow ()
196 @param PciHandle PCI device to get status for
198 @retval EFI_SUCCESS Legacy ROM loaded for this device
199 @retval EFI_NOT_FOUND No Legacy ROM loaded for this device
204 IN EFI_HANDLE PciHandle
208 EFI_PCI_IO_PROTOCOL
*PciIo
;
216 // Get the PCI I/O Protocol on PciHandle
218 Status
= gBS
->HandleProtocol (
220 &gEfiPciIoProtocolGuid
,
223 if (EFI_ERROR (Status
)) {
227 // Get the location of the PCI device
238 // See if the option ROM from PciHandle has been previously posted
240 for (Index
= 0; Index
< mRomCount
; Index
++) {
241 if (mRomEntry
[Index
].PciSegment
== Segment
&&
242 mRomEntry
[Index
].PciBus
== Bus
&&
243 mRomEntry
[Index
].PciDevice
== Device
&&
244 mRomEntry
[Index
].PciFunction
== Function
250 return EFI_NOT_FOUND
;
254 Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the
255 related information from the header.
257 @param Csm16Revision The PCI interface version of underlying CSM16
258 @param VendorId Vendor ID of the PCI device
259 @param DeviceId Device ID of the PCI device
260 @param Rom On input pointing to beginning of the raw PCI OpROM
261 On output pointing to the first legacy PCI OpROM
262 @param ImageSize On input is the size of Raw PCI Rom
263 On output is the size of the first legacy PCI ROM
264 @param MaxRuntimeImageLength The max runtime image length only valid if OpRomRevision >= 3
265 @param OpRomRevision Revision of the PCI Rom
266 @param ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header
268 @retval EFI_SUCCESS Successfully find the legacy PCI ROM
269 @retval EFI_NOT_FOUND Failed to find the legacy PCI ROM
274 IN UINT16 Csm16Revision
,
278 IN OUT UINTN
*ImageSize
,
279 OUT UINTN
*MaxRuntimeImageLength
, OPTIONAL
280 OUT UINT8
*OpRomRevision
, OPTIONAL
281 OUT VOID
**ConfigUtilityCodeHeader OPTIONAL
285 UINT16
*DeviceIdList
;
286 EFI_PCI_ROM_HEADER RomHeader
;
287 PCI_3_0_DATA_STRUCTURE
*Pcir
;
292 if (*ImageSize
< sizeof (EFI_PCI_ROM_HEADER
)) {
293 return EFI_NOT_FOUND
;
298 RomHeader
.Raw
= *Rom
;
299 while (RomHeader
.Generic
->Signature
== PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
300 if (RomHeader
.Generic
->PcirOffset
== 0 ||
301 (RomHeader
.Generic
->PcirOffset
& 3) !=0 ||
302 *ImageSize
< RomHeader
.Raw
- (UINT8
*) *Rom
+ RomHeader
.Generic
->PcirOffset
+ sizeof (PCI_DATA_STRUCTURE
)) {
306 Pcir
= (PCI_3_0_DATA_STRUCTURE
*) (RomHeader
.Raw
+ RomHeader
.Generic
->PcirOffset
);
308 // Check signature in the PCI Data Structure.
310 if (Pcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
314 if (((UINTN
)RomHeader
.Raw
- (UINTN
)*Rom
) + Pcir
->ImageLength
* 512 > *ImageSize
) {
318 if (Pcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
320 if (Pcir
->VendorId
== VendorId
) {
321 if (Pcir
->DeviceId
== DeviceId
) {
323 } else if ((Pcir
->Revision
>= 3) && (Pcir
->DeviceListOffset
!= 0)) {
324 DeviceIdList
= (UINT16
*)(((UINT8
*) Pcir
) + Pcir
->DeviceListOffset
);
326 // Checking the device list
328 while (*DeviceIdList
!= 0) {
329 if (*DeviceIdList
== DeviceId
) {
339 if (Csm16Revision
>= 0x0300) {
343 if (Pcir
->Revision
>= 3) {
345 // case 1.1: meets OpRom 3.0
348 BestImage
= RomHeader
.Raw
;
352 // case 1.2: meets OpRom 2.x
353 // Store it and try to find the OpRom 3.0
355 BackupImage
= RomHeader
.Raw
;
361 if (Pcir
->Revision
>= 3) {
363 // case 2.1: meets OpRom 3.0
364 // Store it and try to find the OpRom 2.x
366 BackupImage
= RomHeader
.Raw
;
369 // case 2.2: meets OpRom 2.x
372 BestImage
= RomHeader
.Raw
;
377 DEBUG ((EFI_D_ERROR
, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN
)VendorId
, (UINTN
)DeviceId
));
381 if ((Pcir
->Indicator
& 0x80) == 0x80) {
384 RomHeader
.Raw
+= 512 * Pcir
->ImageLength
;
388 if (BestImage
== NULL
) {
389 if (BackupImage
== NULL
) {
390 return EFI_NOT_FOUND
;
393 // The versions of CSM16 and OpRom don't match exactly
395 BestImage
= BackupImage
;
397 RomHeader
.Raw
= BestImage
;
398 Pcir
= (PCI_3_0_DATA_STRUCTURE
*) (RomHeader
.Raw
+ RomHeader
.Generic
->PcirOffset
);
400 *ImageSize
= Pcir
->ImageLength
* 512;
402 if (MaxRuntimeImageLength
!= NULL
) {
403 if (Pcir
->Revision
< 3) {
404 *MaxRuntimeImageLength
= 0;
406 *MaxRuntimeImageLength
= Pcir
->MaxRuntimeImageLength
* 512;
410 if (OpRomRevision
!= NULL
) {
412 // Optional return PCI Data Structure revision
414 if (Pcir
->Length
>= 0x1C) {
415 *OpRomRevision
= Pcir
->Revision
;
421 if (ConfigUtilityCodeHeader
!= NULL
) {
423 // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM
425 if ((Pcir
->Revision
< 3) || (Pcir
->ConfigUtilityCodeHeaderOffset
== 0)) {
426 *ConfigUtilityCodeHeader
= NULL
;
428 *ConfigUtilityCodeHeader
= RomHeader
.Raw
+ Pcir
->ConfigUtilityCodeHeaderOffset
;
436 Build a table of bridge info for PIRQ translation.
438 @param RoutingTable RoutingTable obtained from Platform.
439 @param RoutingTableEntries Number of RoutingTable entries.
441 @retval EFI_SUCCESS New Subordinate bus.
442 @retval EFI_NOT_FOUND No more Subordinate busses.
447 IN EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
,
448 IN UINTN RoutingTableEntries
453 EFI_HANDLE
*HandleBuffer
;
457 EFI_PCI_IO_PROTOCOL
*PciIo
;
458 PCI_TYPE01 PciConfigHeader
;
459 BRIDGE_TABLE SlotBridges
[MAX_BRIDGE_INDEX
];
460 UINTN SlotBridgeIndex
;
463 SlotBridgeIndex
= 0x00;
466 // Assumption is table is built from low bus to high bus numbers.
468 Status
= gBS
->LocateHandleBuffer (
470 &gEfiPciIoProtocolGuid
,
475 if (EFI_ERROR (Status
)) {
476 return EFI_NOT_FOUND
;
478 for (Index
= 0; Index
< HandleCount
; Index
++) {
479 Status
= gBS
->HandleProtocol (
481 &gEfiPciIoProtocolGuid
,
484 if (EFI_ERROR (Status
)) {
492 sizeof (PciConfigHeader
) / sizeof (UINT32
),
496 if (IS_PCI_P2P (&PciConfigHeader
) && (BridgeIndex
< MAX_BRIDGE_INDEX
)) {
499 &Bridges
[BridgeIndex
].PciSegment
,
500 &Bridges
[BridgeIndex
].PciBus
,
501 &Bridges
[BridgeIndex
].PciDevice
,
502 &Bridges
[BridgeIndex
].PciFunction
505 Bridges
[BridgeIndex
].PrimaryBus
= PciConfigHeader
.Bridge
.PrimaryBus
;
507 Bridges
[BridgeIndex
].SecondaryBus
= PciConfigHeader
.Bridge
.SecondaryBus
;
509 Bridges
[BridgeIndex
].SubordinateBus
= PciConfigHeader
.Bridge
.SubordinateBus
;
511 for (Index1
= 0; Index1
< RoutingTableEntries
; Index1
++){
513 // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board
514 // Once we find one, store it in the SlotBridges[]
516 if ((RoutingTable
[Index1
].Slot
!= 0) && (Bridges
[BridgeIndex
].PrimaryBus
== RoutingTable
[Index1
].Bus
)
517 && ((Bridges
[BridgeIndex
].PciDevice
<< 3) == RoutingTable
[Index1
].Device
)) {
518 CopyMem (&SlotBridges
[SlotBridgeIndex
], &Bridges
[BridgeIndex
], sizeof (BRIDGE_TABLE
));
530 // Pack up Bridges by removing those useless ones
532 for (Index
= 0; Index
< BridgeIndex
;){
533 for (Index1
= 0; Index1
< SlotBridgeIndex
; Index1
++) {
534 if (((Bridges
[Index
].PciBus
== SlotBridges
[Index1
].PrimaryBus
) && (Bridges
[Index
].PciDevice
== SlotBridges
[Index1
].PciDevice
)) ||
535 ((Bridges
[Index
].PciBus
>= SlotBridges
[Index1
].SecondaryBus
) && (Bridges
[Index
].PciBus
<= SlotBridges
[Index1
].SubordinateBus
))) {
537 // We have found one that meets our criteria
545 // This one doesn't meet criteria, pack it
547 if (Index1
>= SlotBridgeIndex
) {
548 for (Index1
= Index
; BridgeIndex
> 1 && Index1
< BridgeIndex
- 1 ; Index1
++) {
549 CopyMem (&Bridges
[Index1
], &Bridges
[Index1
+ 1], sizeof (BRIDGE_TABLE
));
556 NumberOfBridges
= BridgeIndex
;
559 // Sort bridges low to high by Secondary bus followed by subordinate bus
561 if (NumberOfBridges
> 1) {
564 SortedBridgeIndex
[Index
] = Index
;
566 } while (Index
< NumberOfBridges
);
568 for (Index
= 0; Index
< NumberOfBridges
- 1; Index
++) {
569 for (Index1
= Index
+ 1; Index1
< NumberOfBridges
; Index1
++) {
570 if (Bridges
[Index
].SecondaryBus
> Bridges
[Index1
].SecondaryBus
) {
571 SortedBridgeIndex
[Index
] = Index1
;
572 SortedBridgeIndex
[Index1
] = Index
;
575 if ((Bridges
[Index
].SecondaryBus
== Bridges
[Index1
].SecondaryBus
) &&
576 (Bridges
[Index
].SubordinateBus
> Bridges
[Index1
].SubordinateBus
)
578 SortedBridgeIndex
[Index
] = Index1
;
579 SortedBridgeIndex
[Index1
] = Index
;
584 FreePool (HandleBuffer
);
590 Find base Bridge for device.
592 @param Private Legacy BIOS Instance data
593 @param PciBus Input = Bus of device.
594 @param PciDevice Input = Device.
595 @param RoutingTable The platform specific routing table
596 @param RoutingTableEntries Number of entries in table
598 @retval EFI_SUCCESS At base bus.
599 @retval EFI_NOT_FOUND Behind a bridge.
604 IN LEGACY_BIOS_INSTANCE
*Private
,
607 IN EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
,
608 IN UINTN RoutingTableEntries
612 for (Index
= 0; Index
< RoutingTableEntries
; Index
++) {
613 if ((RoutingTable
[Index
].Bus
== PciBus
) && (RoutingTable
[Index
].Device
== (PciDevice
<< 3))) {
618 return EFI_NOT_FOUND
;
622 Translate PIRQ through busses
624 @param Private Legacy BIOS Instance data
625 @param PciBus Input = Bus of device. Output = Translated Bus
626 @param PciDevice Input = Device. Output = Translated Device
627 @param PciFunction Input = Function. Output = Translated Function
628 @param PirqIndex Input = Original PIRQ index. If single function
629 device then 0, otherwise 0-3.
630 Output = Translated Index
632 @retval EFI_SUCCESS Pirq successfully translated.
633 @retval EFI_NOT_FOUND The device is not behind any known bridge.
638 IN LEGACY_BIOS_INSTANCE
*Private
,
639 IN OUT UINTN
*PciBus
,
640 IN OUT UINTN
*PciDevice
,
641 IN OUT UINTN
*PciFunction
,
642 IN OUT UINT8
*PirqIndex
646 This routine traverses the PCI busses from base slot
647 and translates the PIRQ register to the appropriate one.
651 Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.
654 Subordinate bus # is highest bus # behind this bus
655 Bus 1, Device 0 is Slot 0 and is not a bridge.
656 Bus 1, Device 1 is Slot 1 and is a bridge.
657 Slot PIRQ routing is A,B,C,D.
660 Subordinate bus # = 5
661 Bus 2, Device 6 is a bridge. It has no bridges behind it.
664 Subordinate bus # = 3
665 Bridge PIRQ routing is C,D,A,B
666 Bus 2, Device 7 is a bridge. It has 1 bridge behind it.
668 Secondary bus = 4 Device 6 takes bus 2.
670 Bridge PIRQ routing is D,A,B,C
671 Bus 4, Device 2 is a bridge. It has no bridges behind it.
675 Bridge PIRQ routing is B,C,D,A
676 Bus 5, Device 1 is to be programmed.
677 Device PIRQ routing is C,D,A,B
680 Search busses starting from slot bus for final bus >= Secondary bus and
681 final bus <= Suborninate bus. Assumption is bus entries increase in bus
683 Starting PIRQ is A,B,C,D.
684 Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device
685 7 modulo 4 giving (D,A,B,C).
686 Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving
688 No other busses match criteria. Device to be programmed is Bus 5, Device 1.
689 Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.
697 UINT8 LocalPirqIndex
;
698 BOOLEAN BaseIndexFlag
;
701 BaseIndexFlag
= FALSE
;
704 LocalPirqIndex
= *PirqIndex
;
706 LocalDevice
= *PciDevice
;
708 BaseDevice
= *PciDevice
;
709 BaseFunction
= *PciFunction
;
712 // LocalPirqIndex list PIRQs in rotated fashion
719 for (BridgeIndex
= 0; BridgeIndex
< NumberOfBridges
; BridgeIndex
++) {
720 SBridgeIndex
= SortedBridgeIndex
[BridgeIndex
];
722 // Check if device behind this bridge
724 if ((LocalBus
>= Bridges
[SBridgeIndex
].SecondaryBus
) && (LocalBus
<= Bridges
[SBridgeIndex
].SubordinateBus
)) {
726 // If BaseIndexFlag = FALSE then have found base bridge, i.e
727 // bridge in slot. Save info for use by IRQ routing table.
729 if (!BaseIndexFlag
) {
730 BaseBus
= Bridges
[SBridgeIndex
].PciBus
;
731 BaseDevice
= Bridges
[SBridgeIndex
].PciDevice
;
732 BaseFunction
= Bridges
[SBridgeIndex
].PciFunction
;
733 BaseIndexFlag
= TRUE
;
735 LocalPirqIndex
= (UINT8
) ((LocalPirqIndex
+ (UINT8
)Bridges
[SBridgeIndex
].PciDevice
)%4);
739 // Check if at device. If not get new PCI location & PIRQ
741 if (Bridges
[SBridgeIndex
].SecondaryBus
== (UINT8
) LocalBus
) {
745 LocalPirqIndex
= (UINT8
) ((LocalPirqIndex
+ (UINT8
) (LocalDevice
)) % 4);
752 // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user
754 if(BridgeIndex
>= NumberOfBridges
){
755 DEBUG ((EFI_D_ERROR
, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus
, *PciDevice
, *PciFunction
));
758 *PirqIndex
= LocalPirqIndex
;
760 *PciDevice
= BaseDevice
;
761 *PciFunction
= BaseFunction
;
768 Copy the $PIR table as required.
770 @param Private Legacy BIOS Instance data
771 @param RoutingTable Pointer to IRQ routing table
772 @param RoutingTableEntries IRQ routing table entries
773 @param PirqTable Pointer to $PIR table
774 @param PirqTableSize Length of table
779 IN LEGACY_BIOS_INSTANCE
*Private
,
780 IN EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
,
781 IN UINTN RoutingTableEntries
,
782 IN EFI_LEGACY_PIRQ_TABLE_HEADER
*PirqTable
,
783 IN UINTN PirqTableSize
786 EFI_IA32_REGISTER_SET Regs
;
790 // Copy $PIR table, if it exists.
792 if (PirqTable
!= NULL
) {
793 Private
->LegacyRegion
->UnLock (
794 Private
->LegacyRegion
,
800 Private
->InternalIrqRoutingTable
= RoutingTable
;
801 Private
->NumberIrqRoutingEntries
= (UINT16
) (RoutingTableEntries
);
802 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
804 Regs
.X
.AX
= Legacy16GetTableAddress
;
805 Regs
.X
.CX
= (UINT16
) PirqTableSize
;
807 // Allocate at F segment according to PCI IRQ Routing Table Specification
809 Regs
.X
.BX
= (UINT16
) 0x1;
811 // 16-byte boundary alignment requirement according to
812 // PCI IRQ Routing Table Specification
815 Private
->LegacyBios
.FarCall86 (
816 &Private
->LegacyBios
,
817 Private
->Legacy16CallSegment
,
818 Private
->Legacy16CallOffset
,
824 Private
->Legacy16Table
->IrqRoutingTablePointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
825 if (Regs
.X
.AX
!= 0) {
826 DEBUG ((EFI_D_ERROR
, "PIRQ table length insufficient - %x\n", PirqTableSize
));
828 DEBUG ((EFI_D_INFO
, "PIRQ table in legacy region - %x\n", Private
->Legacy16Table
->IrqRoutingTablePointer
));
829 Private
->Legacy16Table
->IrqRoutingTableLength
= (UINT32
)PirqTableSize
;
831 (VOID
*) (UINTN
)Private
->Legacy16Table
->IrqRoutingTablePointer
,
837 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
838 Private
->LegacyRegion
->Lock (
839 Private
->LegacyRegion
,
846 Private
->PciInterruptLine
= TRUE
;
851 Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.
853 @param PciHandle The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
858 IN EFI_LEGACY_INSTALL_PCI_HANDLER
*PciHandle
861 DEBUG ((EFI_D_INFO
, "PciBus - %02x\n", (UINTN
)PciHandle
->PciBus
));
862 DEBUG ((EFI_D_INFO
, "PciDeviceFun - %02x\n", (UINTN
)PciHandle
->PciDeviceFun
));
863 DEBUG ((EFI_D_INFO
, "PciSegment - %02x\n", (UINTN
)PciHandle
->PciSegment
));
864 DEBUG ((EFI_D_INFO
, "PciClass - %02x\n", (UINTN
)PciHandle
->PciClass
));
865 DEBUG ((EFI_D_INFO
, "PciSubclass - %02x\n", (UINTN
)PciHandle
->PciSubclass
));
866 DEBUG ((EFI_D_INFO
, "PciInterface - %02x\n", (UINTN
)PciHandle
->PciInterface
));
868 DEBUG ((EFI_D_INFO
, "PrimaryIrq - %02x\n", (UINTN
)PciHandle
->PrimaryIrq
));
869 DEBUG ((EFI_D_INFO
, "PrimaryReserved - %02x\n", (UINTN
)PciHandle
->PrimaryReserved
));
870 DEBUG ((EFI_D_INFO
, "PrimaryControl - %04x\n", (UINTN
)PciHandle
->PrimaryControl
));
871 DEBUG ((EFI_D_INFO
, "PrimaryBase - %04x\n", (UINTN
)PciHandle
->PrimaryBase
));
872 DEBUG ((EFI_D_INFO
, "PrimaryBusMaster - %04x\n", (UINTN
)PciHandle
->PrimaryBusMaster
));
874 DEBUG ((EFI_D_INFO
, "SecondaryIrq - %02x\n", (UINTN
)PciHandle
->SecondaryIrq
));
875 DEBUG ((EFI_D_INFO
, "SecondaryReserved - %02x\n", (UINTN
)PciHandle
->SecondaryReserved
));
876 DEBUG ((EFI_D_INFO
, "SecondaryControl - %04x\n", (UINTN
)PciHandle
->SecondaryControl
));
877 DEBUG ((EFI_D_INFO
, "SecondaryBase - %04x\n", (UINTN
)PciHandle
->SecondaryBase
));
878 DEBUG ((EFI_D_INFO
, "SecondaryBusMaster - %04x\n", (UINTN
)PciHandle
->SecondaryBusMaster
));
883 Copy the $PIR table as required.
885 @param Private Legacy BIOS Instance data
886 @param PciIo Pointer to PCI_IO protocol
887 @param PciIrq Pci IRQ number
888 @param PciConfigHeader Type00 Pci configuration header
892 InstallLegacyIrqHandler (
893 IN LEGACY_BIOS_INSTANCE
*Private
,
894 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
896 IN PCI_TYPE00
*PciConfigHeader
899 EFI_IA32_REGISTER_SET Regs
;
905 EFI_LEGACY_8259_PROTOCOL
*Legacy8259
;
906 UINT16 PrimaryMaster
;
907 UINT16 SecondaryMaster
;
909 UINTN RegisterAddress
;
914 Legacy8259
= Private
->Legacy8259
;
916 // Disable interrupt in PIC, in case shared, to prevent an
917 // interrupt from occuring.
919 Legacy8259
->GetMask (
927 LegMask
= (UINT16
) (LegMask
| (UINT16
) (1 << PciIrq
));
929 Legacy8259
->SetMask (
944 Private
->IntThunk
->PciHandler
.PciBus
= (UINT8
) PciBus
;
945 Private
->IntThunk
->PciHandler
.PciDeviceFun
= (UINT8
) ((PciDevice
<< 3) + PciFunction
);
946 Private
->IntThunk
->PciHandler
.PciSegment
= (UINT8
) PciSegment
;
947 Private
->IntThunk
->PciHandler
.PciClass
= PciConfigHeader
->Hdr
.ClassCode
[2];
948 Private
->IntThunk
->PciHandler
.PciSubclass
= PciConfigHeader
->Hdr
.ClassCode
[1];
949 Private
->IntThunk
->PciHandler
.PciInterface
= PciConfigHeader
->Hdr
.ClassCode
[0];
952 // Use native mode base address registers in two cases:
953 // 1. Programming Interface (PI) register indicates Primary Controller is
955 // 2. PCI device Sub Class Code is not IDE
957 Private
->IntThunk
->PciHandler
.PrimaryBusMaster
= (UINT16
)(PciConfigHeader
->Device
.Bar
[4] & 0xfffc);
958 if (((PciConfigHeader
->Hdr
.ClassCode
[0] & 0x01) != 0) || (PciConfigHeader
->Hdr
.ClassCode
[1] != PCI_CLASS_MASS_STORAGE_IDE
)) {
959 Private
->IntThunk
->PciHandler
.PrimaryIrq
= PciIrq
;
960 Private
->IntThunk
->PciHandler
.PrimaryBase
= (UINT16
) (PciConfigHeader
->Device
.Bar
[0] & 0xfffc);
961 Private
->IntThunk
->PciHandler
.PrimaryControl
= (UINT16
) ((PciConfigHeader
->Device
.Bar
[1] & 0xfffc) + 2);
963 Private
->IntThunk
->PciHandler
.PrimaryIrq
= 14;
964 Private
->IntThunk
->PciHandler
.PrimaryBase
= 0x1f0;
965 Private
->IntThunk
->PciHandler
.PrimaryControl
= 0x3f6;
968 // Secondary controller data
970 if (Private
->IntThunk
->PciHandler
.PrimaryBusMaster
!= 0) {
971 Private
->IntThunk
->PciHandler
.SecondaryBusMaster
= (UINT16
) ((PciConfigHeader
->Device
.Bar
[4] & 0xfffc) + 8);
972 PrimaryMaster
= (UINT16
) (Private
->IntThunk
->PciHandler
.PrimaryBusMaster
+ 2);
973 SecondaryMaster
= (UINT16
) (Private
->IntThunk
->PciHandler
.SecondaryBusMaster
+ 2);
976 // Clear pending interrupts in Bus Master registers
978 IoWrite16 (PrimaryMaster
, 0x04);
979 IoWrite16 (SecondaryMaster
, 0x04);
984 // Use native mode base address registers in two cases:
985 // 1. Programming Interface (PI) register indicates Secondary Controller is
987 // 2. PCI device Sub Class Code is not IDE
989 if (((PciConfigHeader
->Hdr
.ClassCode
[0] & 0x04) != 0) || (PciConfigHeader
->Hdr
.ClassCode
[1] != PCI_CLASS_MASS_STORAGE_IDE
)) {
990 Private
->IntThunk
->PciHandler
.SecondaryIrq
= PciIrq
;
991 Private
->IntThunk
->PciHandler
.SecondaryBase
= (UINT16
) (PciConfigHeader
->Device
.Bar
[2] & 0xfffc);
992 Private
->IntThunk
->PciHandler
.SecondaryControl
= (UINT16
) ((PciConfigHeader
->Device
.Bar
[3] & 0xfffc) + 2);
995 Private
->IntThunk
->PciHandler
.SecondaryIrq
= 15;
996 Private
->IntThunk
->PciHandler
.SecondaryBase
= 0x170;
997 Private
->IntThunk
->PciHandler
.SecondaryControl
= 0x376;
1001 // Clear pending interrupts in IDE Command Block Status reg before we
1002 // Thunk to CSM16 below. Don't want a pending Interrupt before we
1003 // install the handlers as wierd corruption would occur and hang system.
1006 // Read IDE CMD blk status reg to clear out any pending interrupts.
1007 // Do here for Primary and Secondary IDE channels
1009 RegisterAddress
= (UINT16
)Private
->IntThunk
->PciHandler
.PrimaryBase
+ 0x07;
1010 IoRead8 (RegisterAddress
);
1011 RegisterAddress
= (UINT16
)Private
->IntThunk
->PciHandler
.SecondaryBase
+ 0x07;
1012 IoRead8 (RegisterAddress
);
1014 Private
->IntThunk
->PciHandler
.PrimaryReserved
= 0;
1015 Private
->IntThunk
->PciHandler
.SecondaryReserved
= 0;
1016 Private
->LegacyRegion
->UnLock (
1017 Private
->LegacyRegion
,
1023 Regs
.X
.AX
= Legacy16InstallPciHandler
;
1024 TempData
= (UINTN
) &Private
->IntThunk
->PciHandler
;
1025 Regs
.X
.ES
= EFI_SEGMENT ((UINT32
) TempData
);
1026 Regs
.X
.BX
= EFI_OFFSET ((UINT32
) TempData
);
1028 DumpPciHandle (&Private
->IntThunk
->PciHandler
);
1030 Private
->LegacyBios
.FarCall86 (
1031 &Private
->LegacyBios
,
1032 Private
->Legacy16CallSegment
,
1033 Private
->Legacy16CallOffset
,
1039 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
1040 Private
->LegacyRegion
->Lock (
1041 Private
->LegacyRegion
,
1051 Program the interrupt routing register in all the PCI devices. On a PC AT system
1052 this register contains the 8259 IRQ vector that matches it's PCI interrupt.
1054 @param Private Legacy BIOS Instance data
1056 @retval EFI_SUCCESS Succeed.
1057 @retval EFI_ALREADY_STARTED All PCI devices have been processed.
1061 PciProgramAllInterruptLineRegisters (
1062 IN LEGACY_BIOS_INSTANCE
*Private
1066 EFI_PCI_IO_PROTOCOL
*PciIo
;
1067 EFI_LEGACY_8259_PROTOCOL
*Legacy8259
;
1068 EFI_LEGACY_INTERRUPT_PROTOCOL
*LegacyInterrupt
;
1069 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
1073 EFI_HANDLE
*HandleBuffer
;
1074 UINTN MassStorageHandleCount
;
1075 EFI_HANDLE
*MassStorageHandleBuffer
;
1076 UINTN MassStorageHandleIndex
;
1083 EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
;
1084 UINTN RoutingTableEntries
;
1086 UINT16 LegEdgeLevel
;
1087 PCI_TYPE00 PciConfigHeader
;
1088 EFI_LEGACY_PIRQ_TABLE_HEADER
*PirqTable
;
1089 UINTN PirqTableSize
;
1095 // Note - This routine use to return immediately if Private->PciInterruptLine
1096 // was true. Routine changed since resets etc can cause not all
1097 // PciIo protocols to be registered the first time through.
1098 // New algorithm is to do the copy $PIR table on first pass and save
1099 // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives
1100 // a larger handle count then proceed with body of function else return
1101 // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.
1102 // If zero then function unprogrammed else skip function.
1104 Legacy8259
= Private
->Legacy8259
;
1105 LegacyInterrupt
= Private
->LegacyInterrupt
;
1106 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
1108 LegacyBiosPlatform
->GetRoutingTable (
1109 Private
->LegacyBiosPlatform
,
1110 (VOID
*) &RoutingTable
,
1111 &RoutingTableEntries
,
1112 (VOID
*) &PirqTable
,
1117 CreateBridgeTable (RoutingTable
, RoutingTableEntries
);
1119 if (!Private
->PciInterruptLine
) {
1123 RoutingTableEntries
,
1129 Status
= gBS
->LocateHandleBuffer (
1131 &gEfiPciIoProtocolGuid
,
1136 if (EFI_ERROR (Status
)) {
1137 return EFI_NOT_FOUND
;
1139 if (HandleCount
== mHandleCount
) {
1140 FreePool (HandleBuffer
);
1141 return EFI_ALREADY_STARTED
;
1144 if (mHandleCount
== 0x00) {
1145 mHandleCount
= HandleCount
;
1148 for (Index
= 0; Index
< HandleCount
; Index
++) {
1150 // If VGA then only do VGA to allow drives fore time to spin up
1151 // otherwise assign PCI IRQs to all potential devices.
1153 if ((mVgaInstallationInProgress
) && (HandleBuffer
[Index
] != mVgaHandle
)) {
1157 // Force code to go through all handles next time called if video.
1158 // This will catch case where HandleCount doesn't change but want
1159 // to get drive info etc.
1161 mHandleCount
= 0x00;
1164 Status
= gBS
->HandleProtocol (
1165 HandleBuffer
[Index
],
1166 &gEfiPciIoProtocolGuid
,
1169 ASSERT_EFI_ERROR (Status
);
1172 // Test whether the device can be enabled or not.
1173 // If it can't be enabled, then just skip it to avoid further operation.
1177 EfiPciIoWidthUint32
,
1179 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1182 Command
= PciConfigHeader
.Hdr
.Command
;
1185 // Note PciIo->Attributes does not program the PCI command register
1187 Status
= PciIo
->Attributes (
1189 EfiPciIoAttributeOperationSupported
,
1193 if (!EFI_ERROR (Status
)) {
1194 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
1195 Status
= PciIo
->Attributes (
1197 EfiPciIoAttributeOperationEnable
,
1202 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x04, 1, &Command
);
1204 if (EFI_ERROR (Status
)) {
1208 InterruptPin
= PciConfigHeader
.Device
.InterruptPin
;
1210 if ((InterruptPin
!= 0) && (PciConfigHeader
.Device
.InterruptLine
== PCI_INT_LINE_UNKNOWN
)) {
1211 PciIo
->GetLocation (
1219 // Translate PIRQ index back thru busses to slot bus with InterruptPin
1224 Status
= GetBaseBus (
1232 if (Status
== EFI_NOT_FOUND
) {
1242 // Translate InterruptPin(0-3) into PIRQ
1244 Status
= LegacyBiosPlatform
->TranslatePirq (
1253 // TranslatePirq() should never fail or we are in trouble
1254 // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect
1256 if (EFI_ERROR (Status
)) {
1257 DEBUG ((EFI_D_ERROR
, "Translate Pirq Failed - Status = %r\n ", Status
));
1261 LegacyInterrupt
->WritePirq (
1268 // Check if device has an OPROM associated with it.
1269 // If not invoke special 16-bit function, to allow 16-bit
1270 // code to install an interrupt handler.
1272 Status
= LegacyBiosCheckPciRom (
1273 &Private
->LegacyBios
,
1274 HandleBuffer
[Index
],
1279 if ((EFI_ERROR (Status
)) && (PciConfigHeader
.Hdr
.ClassCode
[2] == PCI_CLASS_MASS_STORAGE
)) {
1281 // Device has no OPROM associated with it and is a mass storage
1282 // device. It needs to have an PCI IRQ handler installed. To
1283 // correctly install the handler we need to insure device is
1284 // connected. The device may just have register itself but not
1285 // been connected. Re-read PCI config space after as it can
1289 // Get IDE Handle. If matches handle then skip ConnectController
1290 // since ConnectController may force native mode and we don't
1291 // want that for primary IDE controller
1293 MassStorageHandleCount
= 0;
1294 MassStorageHandleBuffer
= NULL
;
1295 LegacyBiosPlatform
->GetPlatformHandle (
1296 Private
->LegacyBiosPlatform
,
1297 EfiGetPlatformIdeHandle
,
1299 &MassStorageHandleBuffer
,
1300 &MassStorageHandleCount
,
1304 HddInfo
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
[0];
1306 LegacyBiosBuildIdeData (Private
, &HddInfo
, 0);
1309 EfiPciIoWidthUint32
,
1311 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1315 for (MassStorageHandleIndex
= 0; MassStorageHandleIndex
< MassStorageHandleCount
; MassStorageHandleIndex
++) {
1316 if (MassStorageHandleBuffer
[MassStorageHandleIndex
] == HandleBuffer
[Index
]) {
1318 // InstallLegacyIrqHandler according to Platform requirement
1320 InstallLegacyIrqHandler (
1331 // Write InterruptPin and enable 8259.
1340 Private
->IntThunk
->EfiToLegacy16BootTable
.PciIrqMask
= (UINT16
) (Private
->IntThunk
->EfiToLegacy16BootTable
.PciIrqMask
| (UINT16
) (1 << PciIrq
));
1342 Legacy8259
->GetMask (
1350 LegMask
= (UINT16
) (LegMask
& (UINT16
)~(1 << PciIrq
));
1351 LegEdgeLevel
= (UINT16
) (LegEdgeLevel
| (UINT16
) (1 << PciIrq
));
1352 Legacy8259
->SetMask (
1361 FreePool (HandleBuffer
);
1367 Find & verify PnP Expansion header in ROM image
1369 @param Private Protocol instance pointer.
1370 @param FirstHeader 1 = Find first header, 0 = Find successive headers
1371 @param PnpPtr Input Rom start if FirstHeader =1, Current Header
1372 otherwise Output Next header, if it exists
1374 @retval EFI_SUCCESS Next Header found at BasePnpPtr
1375 @retval EFI_NOT_FOUND No more headers
1379 FindNextPnpExpansionHeader (
1380 IN LEGACY_BIOS_INSTANCE
*Private
,
1381 IN BOOLEAN FirstHeader
,
1382 IN OUT LEGACY_PNP_EXPANSION_HEADER
**PnpPtr
1387 LEGACY_PNP_EXPANSION_HEADER
*LocalPnpPtr
;
1388 LocalPnpPtr
= *PnpPtr
;
1389 if (FirstHeader
== FIRST_INSTANCE
) {
1390 mBasePnpPtr
= LocalPnpPtr
;
1391 mBbsRomSegment
= (UINT16
) ((UINTN
) mBasePnpPtr
>> 4);
1393 // Offset 0x1a gives offset to PnP expansion header for the first
1394 // instance, there after the structure gives the offset to the next
1397 LocalPnpPtr
= (LEGACY_PNP_EXPANSION_HEADER
*) ((UINT8
*) LocalPnpPtr
+ 0x1a);
1398 TempData
= (*((UINT16
*) LocalPnpPtr
));
1400 TempData
= (UINT16
) LocalPnpPtr
->NextHeader
;
1403 LocalPnpPtr
= (LEGACY_PNP_EXPANSION_HEADER
*) (((UINT8
*) mBasePnpPtr
+ TempData
));
1406 // Search for PnP table in Shadowed ROM
1408 *PnpPtr
= LocalPnpPtr
;
1409 if (*(UINT32
*) LocalPnpPtr
== SIGNATURE_32 ('$', 'P', 'n', 'P')) {
1412 return EFI_NOT_FOUND
;
1418 Update list of Bev or BCV table entries.
1420 @param Private Protocol instance pointer.
1421 @param RomStart Table of ROM start address in RAM/ROM. PciIo _
1422 Handle to PCI IO for this device
1423 @param PciIo Instance of PCI I/O Protocol
1425 @retval EFI_SUCCESS Always should succeed.
1430 IN LEGACY_BIOS_INSTANCE
*Private
,
1431 IN EFI_LEGACY_EXPANSION_ROM_HEADER
*RomStart
,
1432 IN EFI_PCI_IO_PROTOCOL
*PciIo
1436 BBS_TABLE
*BbsTable
;
1438 EFI_LEGACY_EXPANSION_ROM_HEADER
*PciPtr
;
1439 LEGACY_PNP_EXPANSION_HEADER
*PnpPtr
;
1453 DeviceType
= BBS_UNKNOWN
;
1456 // Skip floppy and 2*onboard IDE controller entries(Master/Slave per
1459 BbsIndex
= Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
;
1461 BbsTable
= (BBS_TABLE
*)(UINTN
) Private
->IntThunk
->EfiToLegacy16BootTable
.BbsTable
;
1462 PnpPtr
= (LEGACY_PNP_EXPANSION_HEADER
*) RomStart
;
1463 PciPtr
= (EFI_LEGACY_EXPANSION_ROM_HEADER
*) RomStart
;
1465 RomEnd
= (VOID
*) (PciPtr
->Size512
* 512 + (UINTN
) PciPtr
);
1466 Instance
= FIRST_INSTANCE
;
1468 // OPROMs like PXE may not be tied to a piece of hardware and thus
1469 // don't have a PciIo associated with them
1471 if (PciIo
!= NULL
) {
1472 PciIo
->GetLocation (
1487 if (Class
== PCI_CLASS_MASS_STORAGE
) {
1488 DeviceType
= BBS_HARDDISK
;
1490 if (Class
== PCI_CLASS_NETWORK
) {
1491 DeviceType
= BBS_EMBED_NETWORK
;
1497 Status
= FindNextPnpExpansionHeader (Private
, Instance
, &PnpPtr
);
1498 Instance
= NOT_FIRST_INSTANCE
;
1499 if (EFI_ERROR (Status
)) {
1503 // There can be additional $PnP headers within the OPROM.
1504 // Example: SCSI can have one per drive.
1506 BbsTable
[BbsIndex
].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1507 BbsTable
[BbsIndex
].DeviceType
= DeviceType
;
1508 BbsTable
[BbsIndex
].Bus
= (UINT32
) Bus
;
1509 BbsTable
[BbsIndex
].Device
= (UINT32
) Device
;
1510 BbsTable
[BbsIndex
].Function
= (UINT32
) Function
;
1511 BbsTable
[BbsIndex
].StatusFlags
.OldPosition
= 0;
1512 BbsTable
[BbsIndex
].StatusFlags
.Reserved1
= 0;
1513 BbsTable
[BbsIndex
].StatusFlags
.Enabled
= 0;
1514 BbsTable
[BbsIndex
].StatusFlags
.Failed
= 0;
1515 BbsTable
[BbsIndex
].StatusFlags
.MediaPresent
= 0;
1516 BbsTable
[BbsIndex
].StatusFlags
.Reserved2
= 0;
1517 BbsTable
[BbsIndex
].Class
= PnpPtr
->Class
;
1518 BbsTable
[BbsIndex
].SubClass
= PnpPtr
->SubClass
;
1519 BbsTable
[BbsIndex
].DescStringOffset
= PnpPtr
->ProductNamePointer
;
1520 BbsTable
[BbsIndex
].DescStringSegment
= mBbsRomSegment
;
1521 BbsTable
[BbsIndex
].MfgStringOffset
= PnpPtr
->MfgPointer
;
1522 BbsTable
[BbsIndex
].MfgStringSegment
= mBbsRomSegment
;
1523 BbsTable
[BbsIndex
].BootHandlerSegment
= mBbsRomSegment
;
1526 // Have seen case where PXE base code have PnP expansion ROM
1527 // header but no Bcv or Bev vectors.
1529 if (PnpPtr
->Bcv
!= 0) {
1530 BbsTable
[BbsIndex
].BootHandlerOffset
= PnpPtr
->Bcv
;
1534 if (PnpPtr
->Bev
!= 0) {
1535 BbsTable
[BbsIndex
].BootHandlerOffset
= PnpPtr
->Bev
;
1536 BbsTable
[BbsIndex
].DeviceType
= BBS_BEV_DEVICE
;
1540 if ((PnpPtr
== (LEGACY_PNP_EXPANSION_HEADER
*) PciPtr
) || (PnpPtr
> (LEGACY_PNP_EXPANSION_HEADER
*) RomEnd
)) {
1545 BbsTable
[BbsIndex
].BootPriority
= BBS_IGNORE_ENTRY
;
1546 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
= (UINT32
) BbsIndex
;
1552 Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
1553 to chose the order. Skip any devices that have already have legacy
1556 @param Private Protocol instance pointer.
1558 @retval EFI_SUCCESS Succeed.
1559 @retval EFI_UNSUPPORTED Cannot get VGA device handle.
1564 IN LEGACY_BIOS_INSTANCE
*Private
1568 EFI_PCI_IO_PROTOCOL
*PciIo
;
1572 EFI_HANDLE
*HandleBuffer
;
1573 EFI_HANDLE VgaHandle
;
1574 EFI_HANDLE FirstHandle
;
1577 PCI_TYPE00 PciConfigHeader
;
1582 // Make the VGA device first
1584 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
1585 Private
->LegacyBiosPlatform
,
1586 EfiGetPlatformVgaHandle
,
1592 if (EFI_ERROR (Status
)) {
1593 return EFI_UNSUPPORTED
;
1596 VgaHandle
= HandleBuffer
[0];
1598 Status
= gBS
->LocateHandleBuffer (
1600 &gEfiPciIoProtocolGuid
,
1606 if (EFI_ERROR (Status
)) {
1610 // Place the VGA handle as first.
1612 for (Index
= 0; Index
< HandleCount
; Index
++) {
1613 if (HandleBuffer
[Index
] == VgaHandle
) {
1614 FirstHandle
= HandleBuffer
[0];
1615 HandleBuffer
[0] = HandleBuffer
[Index
];
1616 HandleBuffer
[Index
] = FirstHandle
;
1621 // Allocate memory to save Command WORD from each device. We do this
1622 // to restore devices to same state as EFI after switching to legacy.
1624 Command
= (UINT16
*) AllocatePool (
1625 sizeof (UINT16
) * (HandleCount
+ 1)
1627 if (NULL
== Command
) {
1628 FreePool (HandleBuffer
);
1629 return EFI_OUT_OF_RESOURCES
;
1632 // Disconnect all EFI devices first. This covers cases where alegacy BIOS
1633 // may control multiple PCI devices.
1635 for (Index
= 0; Index
< HandleCount
; Index
++) {
1637 Status
= gBS
->HandleProtocol (
1638 HandleBuffer
[Index
],
1639 &gEfiPciIoProtocolGuid
,
1642 ASSERT_EFI_ERROR (Status
);
1645 // Save command register for "connect" loop
1649 EfiPciIoWidthUint32
,
1651 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1654 Command
[Index
] = PciConfigHeader
.Hdr
.Command
;
1656 // Skip any device that already has a legacy ROM run
1658 Status
= IsLegacyRom (HandleBuffer
[Index
]);
1659 if (!EFI_ERROR (Status
)) {
1663 // Stop EFI Drivers with oprom.
1665 gBS
->DisconnectController (
1666 HandleBuffer
[Index
],
1672 // For every device that has not had a legacy ROM started. Start a legacy ROM.
1674 for (Index
= 0; Index
< HandleCount
; Index
++) {
1676 Status
= gBS
->HandleProtocol (
1677 HandleBuffer
[Index
],
1678 &gEfiPciIoProtocolGuid
,
1682 ASSERT_EFI_ERROR (Status
);
1685 // Here make sure if one VGA have been shadowed,
1686 // then wil not shadowed another one.
1690 EfiPciIoWidthUint32
,
1692 sizeof (Pci
) / sizeof (UINT32
),
1697 // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices,
1698 // one will work in legacy mode (OPROM will be given control) and
1699 // other Video devices will work in native mode (OS driver will handle these devices).
1701 if (IS_PCI_DISPLAY (&Pci
) && Index
!= 0) {
1705 // Skip any device that already has a legacy ROM run
1707 Status
= IsLegacyRom (HandleBuffer
[Index
]);
1708 if (!EFI_ERROR (Status
)) {
1713 // If legacy VBIOS Oprom has not been dispatched before, install legacy VBIOS here.
1715 if (IS_PCI_DISPLAY (&Pci
) && Index
== 0) {
1716 Status
= LegacyBiosInstallVgaRom (Private
);
1718 // A return status of EFI_NOT_FOUND is considered valid (No EFI
1719 // driver is controlling video).
1721 ASSERT ((Status
== EFI_SUCCESS
) || (Status
== EFI_NOT_FOUND
));
1726 // Install legacy ROM
1728 Status
= LegacyBiosInstallPciRom (
1729 &Private
->LegacyBios
,
1730 HandleBuffer
[Index
],
1735 (VOID
**) &RomStart
,
1738 if (EFI_ERROR (Status
)) {
1739 if (!((Status
== EFI_UNSUPPORTED
) && (Flags
== NO_ROM
))) {
1744 // Restore Command register so legacy has same devices enabled or disabled
1746 // If Flags = NO_ROM use command register as is. This covers the
1748 // Device has no ROMs associated with it.
1749 // Device has ROM associated with it but was already
1751 // = ROM_FOUND but not VALID_LEGACY_ROM, disable it.
1752 // = ROM_FOUND and VALID_LEGACY_ROM, enable it.
1754 if ((Flags
& ROM_FOUND
) == ROM_FOUND
) {
1755 if ((Flags
& VALID_LEGACY_ROM
) == 0) {
1759 // For several VGAs, only one of them can be enabled.
1761 Status
= PciIo
->Attributes (
1763 EfiPciIoAttributeOperationSupported
,
1767 if (!EFI_ERROR (Status
)) {
1768 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
1769 Status
= PciIo
->Attributes (
1771 EfiPciIoAttributeOperationEnable
,
1776 if (!EFI_ERROR (Status
)) {
1777 Command
[Index
] = 0x1f;
1784 EfiPciIoWidthUint16
,
1792 FreePool (HandleBuffer
);
1798 Test to see if a legacy PCI ROM exists for this device. Optionally return
1799 the Legacy ROM instance for this PCI device.
1801 @param This Protocol instance pointer.
1802 @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
1804 @param RomImage Return the legacy PCI ROM for this device
1805 @param RomSize Size of ROM Image
1806 @param Flags Indicates if ROM found and if PC-AT.
1808 @retval EFI_SUCCESS Legacy Option ROM available for this device
1809 @retval EFI_UNSUPPORTED Legacy Option ROM not supported.
1814 LegacyBiosCheckPciRom (
1815 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1816 IN EFI_HANDLE PciHandle
,
1817 OUT VOID
**RomImage
, OPTIONAL
1818 OUT UINTN
*RomSize
, OPTIONAL
1822 return LegacyBiosCheckPciRomEx (
1837 Routine Description:
1838 Test to see if a legacy PCI ROM exists for this device. Optionally return
1839 the Legacy ROM instance for this PCI device.
1841 @param[in] This Protocol instance pointer.
1842 @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded
1843 @param[out] RomImage Return the legacy PCI ROM for this device
1844 @param[out] RomSize Size of ROM Image
1845 @param[out] RuntimeImageLength Runtime size of ROM Image
1846 @param[out] Flags Indicates if ROM found and if PC-AT.
1847 @param[out] OpromRevision Revision of the PCI Rom
1848 @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
1850 @return EFI_SUCCESS Legacy Option ROM available for this device
1851 @return EFI_ALREADY_STARTED This device is already managed by its Oprom
1852 @return EFI_UNSUPPORTED Legacy Option ROM not supported.
1856 LegacyBiosCheckPciRomEx (
1857 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1858 IN EFI_HANDLE PciHandle
,
1859 OUT VOID
**RomImage
, OPTIONAL
1860 OUT UINTN
*RomSize
, OPTIONAL
1861 OUT UINTN
*RuntimeImageLength
, OPTIONAL
1862 OUT UINTN
*Flags
, OPTIONAL
1863 OUT UINT8
*OpromRevision
, OPTIONAL
1864 OUT VOID
**ConfigUtilityCodeHeader OPTIONAL
1868 LEGACY_BIOS_INSTANCE
*Private
;
1869 EFI_PCI_IO_PROTOCOL
*PciIo
;
1871 VOID
*LocalRomImage
;
1872 PCI_TYPE00 PciConfigHeader
;
1873 VOID
*LocalConfigUtilityCodeHeader
;
1875 LocalConfigUtilityCodeHeader
= NULL
;
1877 Status
= gBS
->HandleProtocol (
1879 &gEfiPciIoProtocolGuid
,
1882 if (EFI_ERROR (Status
)) {
1883 return EFI_UNSUPPORTED
;
1887 // See if the option ROM for PciHandle has already been executed
1889 Status
= IsLegacyRom (PciHandle
);
1890 if (!EFI_ERROR (Status
)) {
1891 *Flags
|= (UINTN
)(ROM_FOUND
| VALID_LEGACY_ROM
);
1895 // Check for PCI ROM Bar
1897 LocalRomSize
= (UINTN
) PciIo
->RomSize
;
1898 LocalRomImage
= PciIo
->RomImage
;
1899 if (LocalRomSize
!= 0) {
1900 *Flags
|= ROM_FOUND
;
1904 // PCI specification states you should check VendorId and Device Id.
1908 EfiPciIoWidthUint32
,
1910 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1914 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1915 Status
= GetPciLegacyRom (
1916 Private
->Csm16PciInterfaceVersion
,
1917 PciConfigHeader
.Hdr
.VendorId
,
1918 PciConfigHeader
.Hdr
.DeviceId
,
1923 &LocalConfigUtilityCodeHeader
1925 if (EFI_ERROR (Status
)) {
1926 return EFI_UNSUPPORTED
;
1929 *Flags
|= VALID_LEGACY_ROM
;
1932 // See if Configuration Utility Code Header valid
1934 if (LocalConfigUtilityCodeHeader
!= NULL
) {
1935 *Flags
|= ROM_WITH_CONFIG
;
1938 if (ConfigUtilityCodeHeader
!= NULL
) {
1939 *ConfigUtilityCodeHeader
= LocalConfigUtilityCodeHeader
;
1942 if (RomImage
!= NULL
) {
1943 *RomImage
= LocalRomImage
;
1946 if (RomSize
!= NULL
) {
1947 *RomSize
= LocalRomSize
;
1954 Load a legacy PC-AT OPROM on the PciHandle device. Return information
1955 about how many disks were added by the OPROM and the shadow address and
1956 size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
1958 @retval EFI_SUCCESS Legacy ROM loaded for this device
1959 @retval EFI_NOT_FOUND No PS2 Keyboard found
1968 EFI_HANDLE
*HandleBuffer
;
1970 EFI_ISA_IO_PROTOCOL
*IsaIo
;
1974 // Get SimpleTextIn and find PS2 controller
1976 Status
= gBS
->LocateHandleBuffer (
1978 &gEfiSimpleTextInProtocolGuid
,
1983 if (EFI_ERROR (Status
)) {
1984 return EFI_NOT_FOUND
;
1986 for (Index
= 0; Index
< HandleCount
; Index
++) {
1988 // Open the IO Abstraction(s) needed to perform the supported test
1990 Status
= gBS
->OpenProtocol (
1991 HandleBuffer
[Index
],
1992 &gEfiIsaIoProtocolGuid
,
1995 HandleBuffer
[Index
],
1996 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
1999 if (!EFI_ERROR (Status
)) {
2001 // Use the ISA I/O Protocol to see if Controller is the Keyboard
2004 if (IsaIo
->ResourceList
->Device
.HID
!= EISA_PNP_ID (0x303) || IsaIo
->ResourceList
->Device
.UID
!= 0) {
2005 Status
= EFI_UNSUPPORTED
;
2008 gBS
->CloseProtocol (
2009 HandleBuffer
[Index
],
2010 &gEfiIsaIoProtocolGuid
,
2016 if (!EFI_ERROR (Status
)) {
2017 gBS
->ConnectController (HandleBuffer
[Index
], NULL
, NULL
, FALSE
);
2020 FreePool (HandleBuffer
);
2026 Load a legacy PC-AT OpROM for VGA controller.
2028 @param Private Driver private data.
2030 @retval EFI_SUCCESS Legacy ROM successfully installed for this device.
2031 @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video
2032 driver cannot be successfully disconnected, or VGA
2033 thunk driver cannot be successfully connected.
2037 LegacyBiosInstallVgaRom (
2038 IN LEGACY_BIOS_INSTANCE
*Private
2042 EFI_HANDLE VgaHandle
;
2044 EFI_HANDLE
*HandleBuffer
;
2045 EFI_HANDLE
*ConnectHandleBuffer
;
2046 EFI_PCI_IO_PROTOCOL
*PciIo
;
2047 PCI_TYPE00 PciConfigHeader
;
2049 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
2055 // EfiLegacyBiosGuild attached to a device implies that there is a legacy
2056 // BIOS associated with that device.
2058 // There are 3 cases to consider.
2059 // Case 1: No EFI driver is controlling the video.
2060 // Action: Return EFI_SUCCESS from DisconnectController, search
2061 // video thunk driver, and connect it.
2062 // Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is
2063 // not on the image handle.
2064 // Action: Disconnect EFI driver.
2065 // ConnectController for video thunk
2066 // Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is
2067 // on the image handle.
2068 // Action: Do nothing and set Private->VgaInstalled = TRUE.
2069 // Then this routine is not called any more.
2072 // Get the VGA device.
2074 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
2075 Private
->LegacyBiosPlatform
,
2076 EfiGetPlatformVgaHandle
,
2082 if (EFI_ERROR (Status
)) {
2083 return EFI_DEVICE_ERROR
;
2086 VgaHandle
= HandleBuffer
[0];
2089 // Check whether video thunk driver already starts.
2091 Status
= gBS
->OpenProtocolInformation (
2093 &gEfiPciIoProtocolGuid
,
2097 if (EFI_ERROR (Status
)) {
2101 for (Index
= 0; Index
< EntryCount
; Index
++) {
2102 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) != 0) {
2103 Status
= gBS
->HandleProtocol (
2104 OpenInfoBuffer
[Index
].AgentHandle
,
2105 &gEfiLegacyBiosGuid
,
2106 (VOID
**) &Interface
2108 if (!EFI_ERROR (Status
)) {
2110 // This should be video thunk driver which is managing video device
2111 // So it need not start again
2113 DEBUG ((EFI_D_INFO
, "Video thunk driver already start! Return!\n"));
2114 Private
->VgaInstalled
= TRUE
;
2121 // Kick off the native EFI driver
2123 Status
= gBS
->DisconnectController (
2128 if (EFI_ERROR (Status
)) {
2129 if (Status
!= EFI_NOT_FOUND
) {
2130 return EFI_DEVICE_ERROR
;
2136 // Find all the Thunk Driver
2138 HandleBuffer
= NULL
;
2139 Status
= gBS
->LocateHandleBuffer (
2141 &gEfiLegacyBiosGuid
,
2146 ASSERT_EFI_ERROR (Status
);
2147 ConnectHandleBuffer
= (EFI_HANDLE
*) AllocatePool (sizeof (EFI_HANDLE
) * (HandleCount
+ 1));
2148 ASSERT (ConnectHandleBuffer
!= NULL
);
2151 ConnectHandleBuffer
,
2153 sizeof (EFI_HANDLE
) * HandleCount
2155 ConnectHandleBuffer
[HandleCount
] = NULL
;
2157 FreePool (HandleBuffer
);
2160 // Enable the device and make sure VGA cycles are being forwarded to this VGA device
2162 Status
= gBS
->HandleProtocol (
2164 &gEfiPciIoProtocolGuid
,
2167 ASSERT_EFI_ERROR (Status
);
2170 EfiPciIoWidthUint32
,
2172 sizeof (PciConfigHeader
) / sizeof (UINT32
),
2176 Status
= PciIo
->Attributes (
2178 EfiPciIoAttributeOperationSupported
,
2182 if (!EFI_ERROR (Status
)) {
2183 Supports
&= (UINT64
)(EFI_PCI_DEVICE_ENABLE
| EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
| \
2184 EFI_PCI_IO_ATTRIBUTE_VGA_IO
| EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
);
2185 Status
= PciIo
->Attributes (
2187 EfiPciIoAttributeOperationEnable
,
2193 if (Status
== EFI_SUCCESS
) {
2194 Private
->VgaInstalled
= TRUE
;
2197 // Attach the VGA thunk driver.
2198 // Assume the video is installed. This prevents potential of infinite recursion.
2200 Status
= gBS
->ConnectController (
2202 ConnectHandleBuffer
,
2208 FreePool (ConnectHandleBuffer
);
2210 if (EFI_ERROR (Status
)) {
2212 Private
->VgaInstalled
= FALSE
;
2215 // Reconnect the EFI VGA driver.
2217 gBS
->ConnectController (VgaHandle
, NULL
, NULL
, TRUE
);
2218 return EFI_DEVICE_ERROR
;
2226 Load a legacy PC-AT OpROM.
2228 @param This Protocol instance pointer.
2229 @param Private Driver's private data.
2230 @param PciHandle The EFI handle for the PCI device. It could be
2231 NULL if the OpROM image is not associated with
2233 @param OpromRevision The revision of PCI PC-AT ROM image.
2234 @param RomImage Pointer to PCI PC-AT ROM image header. It must not
2236 @param ImageSize Size of the PCI PC-AT ROM image.
2237 @param RuntimeImageLength On input is the max runtime image length indicated by the PCIR structure
2238 On output is the actual runtime image length
2239 @param DiskStart Disk number of first device hooked by the ROM. If
2240 DiskStart is the same as DiskEnd no disked were
2242 @param DiskEnd Disk number of the last device hooked by the ROM.
2243 @param RomShadowAddress Shadow address of PC-AT ROM
2245 @retval EFI_SUCCESS Legacy ROM loaded for this device
2246 @retval EFI_OUT_OF_RESOURCES No more space for this ROM
2251 LegacyBiosInstallRom (
2252 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
2253 IN LEGACY_BIOS_INSTANCE
*Private
,
2254 IN EFI_HANDLE PciHandle
,
2255 IN UINT8 OpromRevision
,
2258 IN OUT UINTN
*RuntimeImageLength
,
2259 OUT UINT8
*DiskStart
, OPTIONAL
2260 OUT UINT8
*DiskEnd
, OPTIONAL
2261 OUT VOID
**RomShadowAddress OPTIONAL
2265 EFI_STATUS PciEnableStatus
;
2266 EFI_PCI_IO_PROTOCOL
*PciIo
;
2267 UINT8 LocalDiskStart
;
2273 EFI_IA32_REGISTER_SET Regs
;
2279 UINT32 StartBbsIndex
;
2284 UINTN RuntimeAddress
;
2285 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
2297 PhysicalAddress
= 0;
2298 MaxRomAddr
= PcdGet32 (PcdEndOpromShadowAddress
);
2300 if ((Private
->Legacy16Table
->TableLength
>= OFFSET_OF(EFI_COMPATIBILITY16_TABLE
, HiPermanentMemoryAddress
)) &&
2301 (Private
->Legacy16Table
->UmaAddress
!= 0) &&
2302 (Private
->Legacy16Table
->UmaSize
!= 0) &&
2303 (MaxRomAddr
> (Private
->Legacy16Table
->UmaAddress
))) {
2304 MaxRomAddr
= Private
->Legacy16Table
->UmaAddress
;
2308 PciProgramAllInterruptLineRegisters (Private
);
2310 if ((OpromRevision
>= 3) && (Private
->Csm16PciInterfaceVersion
>= 0x0300)) {
2312 // CSM16 3.0 meets PCI 3.0 OpROM
2313 // first test if there is enough space for its INIT code
2315 PhysicalAddress
= CONVENTIONAL_MEMORY_TOP
;
2316 Status
= gBS
->AllocatePages (
2318 EfiBootServicesCode
,
2319 EFI_SIZE_TO_PAGES (ImageSize
),
2323 if (EFI_ERROR (Status
)) {
2324 DEBUG ((EFI_D_ERROR
, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__
));
2326 // Report Status Code to indicate that there is no enough space for OpROM
2328 REPORT_STATUS_CODE (
2329 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2330 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE
)
2332 return EFI_OUT_OF_RESOURCES
;
2334 InitAddress
= (UINTN
) PhysicalAddress
;
2336 // then test if there is enough space for its RT code
2338 RuntimeAddress
= Private
->OptionRom
;
2339 if (RuntimeAddress
+ *RuntimeImageLength
> MaxRomAddr
) {
2340 DEBUG ((EFI_D_ERROR
, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__
));
2341 gBS
->FreePages (PhysicalAddress
, EFI_SIZE_TO_PAGES (ImageSize
));
2343 // Report Status Code to indicate that there is no enough space for OpROM
2345 REPORT_STATUS_CODE (
2346 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2347 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE
)
2349 return EFI_OUT_OF_RESOURCES
;
2352 // CSM16 3.0 meets PCI 2.x OpROM
2353 // CSM16 2.x meets PCI 2.x/3.0 OpROM
2354 // test if there is enough space for its INIT code
2356 InitAddress
= PCI_START_ADDRESS (Private
->OptionRom
);
2357 if (InitAddress
+ ImageSize
> MaxRomAddr
) {
2358 DEBUG ((EFI_D_ERROR
, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__
));
2360 // Report Status Code to indicate that there is no enough space for OpROM
2362 REPORT_STATUS_CODE (
2363 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2364 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE
)
2366 return EFI_OUT_OF_RESOURCES
;
2369 RuntimeAddress
= InitAddress
;
2372 Private
->LegacyRegion
->UnLock (
2373 Private
->LegacyRegion
,
2379 Private
->LegacyRegion
->UnLock (
2380 Private
->LegacyRegion
,
2381 (UINT32
) RuntimeAddress
,
2386 DEBUG ((EFI_D_INFO
, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress
, RuntimeAddress
, ImageSize
));
2388 CopyMem ((VOID
*) InitAddress
, RomImage
, ImageSize
);
2391 // Read the highest disk number "installed: and assume a new disk will
2392 // show up on the first drive past the current value.
2393 // There are several considerations here:
2394 // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo
2395 // the change until boot selection time frame.
2396 // 2. BBS compliants drives will not change 40:75 until boot time.
2397 // 3. Onboard IDE controllers will change 40:75
2400 LocalDiskStart
= (UINT8
) ((*(UINT8
*) ((UINTN
) 0x475)) + 0x80);
2401 if ((Private
->Disk4075
+ 0x80) < LocalDiskStart
) {
2403 // Update table since onboard IDE drives found
2405 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciSegment
= 0xff;
2406 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciBus
= 0xff;
2407 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciDevice
= 0xff;
2408 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciFunction
= 0xff;
2409 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].StartDriveNumber
= (UINT8
) (Private
->Disk4075
+ 0x80);
2410 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].EndDriveNumber
= LocalDiskStart
;
2411 Private
->LegacyEfiHddTableIndex
++;
2412 Private
->Disk4075
= (UINT8
) (LocalDiskStart
& 0x7f);
2413 Private
->DiskEnd
= LocalDiskStart
;
2416 if (PciHandle
!= mVgaHandle
) {
2418 EnablePs2Keyboard ();
2421 // Store current mode settings since PrepareToScanRom may change mode.
2423 VideoMode
= *(UINT8
*) ((UINTN
) (0x400 + BDA_VIDEO_MODE
));
2428 // Notify the platform that we are about to scan the ROM
2430 Status
= Private
->LegacyBiosPlatform
->PlatformHooks (
2431 Private
->LegacyBiosPlatform
,
2432 EfiPlatformHookPrepareToScanRom
,
2441 // If Status returned is EFI_UNSUPPORTED then abort due to platform
2444 if (Status
== EFI_UNSUPPORTED
) {
2449 // Report corresponding status code
2451 REPORT_STATUS_CODE (
2453 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_CSM_LEGACY_ROM_INIT
)
2457 // Generate number of ticks since midnight for BDA. Some OPROMs require
2458 // this. Place result in 40:6C-6F
2460 gRT
->GetTime (&BootTime
, NULL
);
2461 LocalTime
= BootTime
.Hour
* 3600 + BootTime
.Minute
* 60 + BootTime
.Second
;
2464 // Multiply result by 18.2 for number of ticks since midnight.
2465 // Use 182/10 to avoid floating point math.
2468 LocalTime
= (LocalTime
* 182) / 10;
2469 BdaPtr
= (UINT32
*) ((UINTN
) 0x46C);
2470 *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 ACCESS_PAGE0_CODE ({
2568 OldVideoMode
= *(UINT8
*) ((UINTN
) (0x400 + BDA_VIDEO_MODE
));
2571 if (VideoMode
!= OldVideoMode
) {
2573 // The active video mode is changed, restore it to original mode.
2576 Regs
.H
.AL
= VideoMode
;
2577 Private
->LegacyBios
.Int86 (&Private
->LegacyBios
, 0x10, &Regs
);
2581 // Regs.X.AX from the adapter initializion is ignored since some adapters
2582 // do not follow the standard of setting AX = 0 on success.
2585 // The ROM could have updated it's size so we need to read again.
2587 if (((EFI_LEGACY_EXPANSION_ROM_HEADER
*) RuntimeAddress
)->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
2589 // Now we check the signature (0xaa55) to judge whether the run-time code is truly generated by INIT function.
2590 // If signature is not valid, that means the INIT function didn't copy the run-time code to RuntimeAddress.
2592 *RuntimeImageLength
= 0;
2594 *RuntimeImageLength
= ((EFI_LEGACY_EXPANSION_ROM_HEADER
*) RuntimeAddress
)->Size512
* 512;
2597 DEBUG ((EFI_D_INFO
, " fsize = %x\n", *RuntimeImageLength
));
2600 // If OpROM runs in 2.0 mode
2602 if (PhysicalAddress
== 0) {
2603 if (*RuntimeImageLength
< ImageSize
) {
2605 // Make area from end of shadowed rom to end of original rom all ffs
2607 gBS
->SetMem ((VOID
*) (InitAddress
+ *RuntimeImageLength
), ImageSize
- *RuntimeImageLength
, 0xff);
2612 LocalDiskEnd
= (UINT8
) ((*(UINT8
*) ((UINTN
) 0x475)) + 0x80);
2616 // Allow platform to perform any required actions after the
2617 // OPROM has been initialized.
2619 Status
= Private
->LegacyBiosPlatform
->PlatformHooks (
2620 Private
->LegacyBiosPlatform
,
2621 EfiPlatformHookAfterRomInit
,
2628 if (PciHandle
!= NULL
) {
2630 // If no PCI Handle then no header or Bevs.
2632 if ((*RuntimeImageLength
!= 0) && (!mIgnoreBbsUpdateFlag
)) {
2633 StartBbsIndex
= Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
;
2634 TempData
= RuntimeAddress
;
2637 (EFI_LEGACY_EXPANSION_ROM_HEADER
*) TempData
,
2640 EndBbsIndex
= Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
;
2641 LocalDiskEnd
= (UINT8
) (LocalDiskStart
+ (UINT8
) (EndBbsIndex
- StartBbsIndex
));
2642 if (LocalDiskEnd
!= LocalDiskStart
) {
2643 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciSegment
= (UINT8
) Segment
;
2644 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciBus
= (UINT8
) Bus
;
2645 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciDevice
= (UINT8
) Device
;
2646 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciFunction
= (UINT8
) Function
;
2647 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].StartDriveNumber
= Private
->DiskEnd
;
2648 Private
->DiskEnd
= LocalDiskEnd
;
2649 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].EndDriveNumber
= Private
->DiskEnd
;
2650 Private
->LegacyEfiHddTableIndex
+= 1;
2654 // Mark PCI device as having a legacy BIOS ROM loaded.
2658 (UINT32
) RuntimeAddress
,
2659 (UINT32
) *RuntimeImageLength
,
2666 // Stuff caller's OPTIONAL return parameters.
2668 if (RomShadowAddress
!= NULL
) {
2669 *RomShadowAddress
= (VOID
*) RuntimeAddress
;
2672 if (DiskStart
!= NULL
) {
2673 *DiskStart
= LocalDiskStart
;
2676 if (DiskEnd
!= NULL
) {
2677 *DiskEnd
= LocalDiskEnd
;
2680 Private
->OptionRom
= (UINT32
) (RuntimeAddress
+ *RuntimeImageLength
);
2682 Status
= EFI_SUCCESS
;
2685 if (PhysicalAddress
!= 0) {
2687 // Free pages when OpROM is 3.0
2689 gBS
->FreePages (PhysicalAddress
, EFI_SIZE_TO_PAGES (ImageSize
));
2693 // Insure all shadowed areas are locked
2695 Private
->LegacyRegion
->Lock (
2696 Private
->LegacyRegion
,
2706 Let IOMMU grant DMA access for the PCI device.
2708 @param PciHandle The EFI handle for the PCI device.
2709 @param HostAddress The system memory address to map to the PCI controller.
2710 @param NumberOfBytes The number of bytes to map.
2712 @retval EFI_SUCCESS The DMA access is granted.
2716 IN EFI_HANDLE PciHandle
,
2717 IN EFI_PHYSICAL_ADDRESS HostAddress
,
2718 IN UINTN NumberOfBytes
2721 EFI_PHYSICAL_ADDRESS DeviceAddress
;
2725 if (PciHandle
== NULL
) {
2726 return EFI_UNSUPPORTED
;
2729 Status
= EFI_SUCCESS
;
2730 if (mIoMmu
== NULL
) {
2731 gBS
->LocateProtocol (&gEdkiiIoMmuProtocolGuid
, NULL
, (VOID
**)&mIoMmu
);
2733 if (mIoMmu
!= NULL
) {
2734 Status
= mIoMmu
->Map (
2736 EdkiiIoMmuOperationBusMasterCommonBuffer
,
2737 (VOID
*)(UINTN
)HostAddress
,
2742 if (EFI_ERROR(Status
)) {
2743 DEBUG ((DEBUG_ERROR
, "LegacyPci - IoMmuMap - %r\n", Status
));
2745 ASSERT (DeviceAddress
== HostAddress
);
2746 Status
= mIoMmu
->SetAttribute (
2750 EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
2752 if (EFI_ERROR(Status
)) {
2753 DEBUG ((DEBUG_ERROR
, "LegacyPci - IoMmuSetAttribute - %r\n", Status
));
2761 Load a legacy PC-AT OPROM on the PciHandle device. Return information
2762 about how many disks were added by the OPROM and the shadow address and
2763 size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
2765 @param This Protocol instance pointer.
2766 @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
2767 be loaded. This value is NULL if RomImage is
2768 non-NULL. This is the normal case.
2769 @param RomImage A PCI PC-AT ROM image. This argument is non-NULL
2770 if there is no hardware associated with the ROM
2771 and thus no PciHandle, otherwise is must be NULL.
2772 Example is PXE base code.
2773 @param Flags Indicates if ROM found and if PC-AT.
2774 @param DiskStart Disk number of first device hooked by the ROM. If
2775 DiskStart is the same as DiskEnd no disked were
2777 @param DiskEnd Disk number of the last device hooked by the ROM.
2778 @param RomShadowAddress Shadow address of PC-AT ROM
2779 @param RomShadowedSize Size of RomShadowAddress in bytes
2781 @retval EFI_SUCCESS Legacy ROM loaded for this device
2782 @retval EFI_INVALID_PARAMETER PciHandle not found
2783 @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard
2789 LegacyBiosInstallPciRom (
2790 IN EFI_LEGACY_BIOS_PROTOCOL
* This
,
2791 IN EFI_HANDLE PciHandle
,
2794 OUT UINT8
*DiskStart
, OPTIONAL
2795 OUT UINT8
*DiskEnd
, OPTIONAL
2796 OUT VOID
**RomShadowAddress
, OPTIONAL
2797 OUT UINT32
*RomShadowedSize OPTIONAL
2801 LEGACY_BIOS_INSTANCE
*Private
;
2802 VOID
*LocalRomImage
;
2804 UINTN RuntimeImageLength
;
2805 EFI_PCI_IO_PROTOCOL
*PciIo
;
2806 PCI_TYPE01 PciConfigHeader
;
2808 EFI_HANDLE
*HandleBuffer
;
2815 UINT8 OpromRevision
;
2817 PCI_3_0_DATA_STRUCTURE
*Pcir
;
2821 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
2822 if (Private
->Legacy16Table
->LastPciBus
== 0) {
2824 // Get last bus number if not already found
2826 Status
= gBS
->LocateHandleBuffer (
2828 &gEfiPciIoProtocolGuid
,
2835 for (Index
= 0; Index
< HandleCount
; Index
++) {
2836 Status
= gBS
->HandleProtocol (
2837 HandleBuffer
[Index
],
2838 &gEfiPciIoProtocolGuid
,
2841 if (EFI_ERROR (Status
)) {
2845 Status
= PciIo
->GetLocation (
2852 if (PciBus
> LastBus
) {
2857 Private
->LegacyRegion
->UnLock (
2858 Private
->LegacyRegion
,
2863 Private
->Legacy16Table
->LastPciBus
= (UINT8
) LastBus
;
2864 Private
->LegacyRegion
->Lock (
2865 Private
->LegacyRegion
,
2873 if ((PciHandle
!= NULL
) && (RomImage
== NULL
)) {
2875 // If PciHandle has OpRom to Execute
2876 // and OpRom are all associated with Hardware
2878 Status
= gBS
->HandleProtocol (
2880 &gEfiPciIoProtocolGuid
,
2884 if (!EFI_ERROR (Status
)) {
2887 EfiPciIoWidthUint32
,
2889 sizeof (PciConfigHeader
) / sizeof (UINT32
),
2894 // if video installed & OPROM is video return
2898 ((PciConfigHeader
.Hdr
.ClassCode
[2] == PCI_CLASS_OLD
) &&
2899 (PciConfigHeader
.Hdr
.ClassCode
[1] == PCI_CLASS_OLD_VGA
))
2901 ((PciConfigHeader
.Hdr
.ClassCode
[2] == PCI_CLASS_DISPLAY
) &&
2902 (PciConfigHeader
.Hdr
.ClassCode
[1] == PCI_CLASS_DISPLAY_VGA
))
2905 (!Private
->VgaInstalled
)
2907 mVgaInstallationInProgress
= TRUE
;
2910 // return EFI_UNSUPPORTED;
2915 // To run any legacy image, the VGA needs to be installed first.
2916 // if installing the video, then don't need the thunk as already installed.
2918 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
2919 Private
->LegacyBiosPlatform
,
2920 EfiGetPlatformVgaHandle
,
2927 if (!EFI_ERROR (Status
)) {
2928 mVgaHandle
= HandleBuffer
[0];
2929 if ((!Private
->VgaInstalled
) && (PciHandle
!= mVgaHandle
)) {
2931 // A return status of EFI_NOT_FOUND is considered valid (No EFI
2932 // driver is controlling video.
2934 mVgaInstallationInProgress
= TRUE
;
2935 Status
= LegacyBiosInstallVgaRom (Private
);
2936 if (EFI_ERROR (Status
)) {
2937 if (Status
!= EFI_NOT_FOUND
) {
2938 mVgaInstallationInProgress
= FALSE
;
2942 mVgaInstallationInProgress
= FALSE
;
2947 // See if the option ROM for PciHandle has already been executed
2949 Status
= IsLegacyRom (PciHandle
);
2951 if (!EFI_ERROR (Status
)) {
2952 mVgaInstallationInProgress
= FALSE
;
2953 GetShadowedRomParameters (
2958 (UINTN
*) RomShadowedSize
2963 Status
= LegacyBiosCheckPciRomEx (
2964 &Private
->LegacyBios
,
2968 &RuntimeImageLength
,
2973 if (EFI_ERROR (Status
)) {
2975 // There is no PCI ROM in the ROM BAR or no onboard ROM
2977 mVgaInstallationInProgress
= FALSE
;
2978 return EFI_UNSUPPORTED
;
2981 if ((RomImage
== NULL
) || (*RomImage
== NULL
)) {
2983 // If PciHandle is NULL, and no OpRom is to be associated
2985 mVgaInstallationInProgress
= FALSE
;
2986 return EFI_UNSUPPORTED
;
2989 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
2990 Private
->LegacyBiosPlatform
,
2991 EfiGetPlatformVgaHandle
,
2997 if ((!EFI_ERROR (Status
)) && (!Private
->VgaInstalled
)) {
2999 // A return status of EFI_NOT_FOUND is considered valid (No EFI
3000 // driver is controlling video.
3002 mVgaInstallationInProgress
= TRUE
;
3003 Status
= LegacyBiosInstallVgaRom (Private
);
3004 if (EFI_ERROR (Status
)) {
3005 if (Status
!= EFI_NOT_FOUND
) {
3006 mVgaInstallationInProgress
= FALSE
;
3010 mVgaInstallationInProgress
= FALSE
;
3014 LocalRomImage
= *RomImage
;
3015 if (((PCI_EXPANSION_ROM_HEADER
*) LocalRomImage
)->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
||
3016 ((PCI_EXPANSION_ROM_HEADER
*) LocalRomImage
)->PcirOffset
== 0 ||
3017 (((PCI_EXPANSION_ROM_HEADER
*) LocalRomImage
)->PcirOffset
& 3 ) != 0) {
3018 mVgaInstallationInProgress
= FALSE
;
3019 return EFI_UNSUPPORTED
;
3022 Pcir
= (PCI_3_0_DATA_STRUCTURE
*)
3023 ((UINT8
*) LocalRomImage
+ ((PCI_EXPANSION_ROM_HEADER
*) LocalRomImage
)->PcirOffset
);
3025 if ((Pcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) || (Pcir
->CodeType
!= PCI_CODE_TYPE_PCAT_IMAGE
)) {
3026 mVgaInstallationInProgress
= FALSE
;
3027 return EFI_UNSUPPORTED
;
3030 ImageSize
= Pcir
->ImageLength
* 512;
3031 if (Pcir
->Length
>= 0x1C) {
3032 OpromRevision
= Pcir
->Revision
;
3036 if (Pcir
->Revision
< 3) {
3037 RuntimeImageLength
= 0;
3039 RuntimeImageLength
= Pcir
->MaxRuntimeImageLength
* 512;
3044 // Grant access for below 1M
3045 // BDA/EBDA/LowPMM and scratch memory for OPROM.
3047 IoMmuGrantAccess (PciHandle
, 0, SIZE_1MB
);
3049 // Grant access for HiPmm
3053 Private
->IntThunk
->EfiToLegacy16InitTable
.HiPmmMemory
,
3054 Private
->IntThunk
->EfiToLegacy16InitTable
.HiPmmMemorySizeInBytes
3058 // Shadow and initialize the OpROM.
3060 ASSERT (Private
->TraceIndex
< 0x200);
3061 Private
->Trace
[Private
->TraceIndex
] = LEGACY_PCI_TRACE_000
;
3062 Private
->TraceIndex
++;
3063 Private
->TraceIndex
= (UINT16
) (Private
->TraceIndex
% 0x200);
3064 Status
= LegacyBiosInstallRom (
3071 &RuntimeImageLength
,
3076 if (RomShadowedSize
!= NULL
) {
3077 *RomShadowedSize
= (UINT32
) RuntimeImageLength
;
3080 mVgaInstallationInProgress
= FALSE
;