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
))
102 if (Index
== mRomCount
) {
103 return EFI_NOT_FOUND
;
106 if (DiskStart
!= NULL
) {
107 *DiskStart
= mRomEntry
[Index
].DiskStart
;
110 if (DiskEnd
!= NULL
) {
111 *DiskEnd
= mRomEntry
[Index
].DiskEnd
;
114 if (RomShadowAddress
!= NULL
) {
115 *RomShadowAddress
= (VOID
*)(UINTN
)mRomEntry
[Index
].ShadowAddress
;
118 if (ShadowedSize
!= NULL
) {
119 *ShadowedSize
= mRomEntry
[Index
].ShadowedSize
;
126 Every legacy ROM that is shadowed by the Legacy BIOS driver will be
127 registered into this API so that the policy code can know what has
130 @param PciHandle PCI device whos ROM is being shadowed
131 @param ShadowAddress Address that ROM was shadowed
132 @param ShadowedSize Runtime size of ROM
133 @param DiskStart DiskStart value from
134 EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
135 @param DiskEnd DiskEnd value from
136 EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
138 @retval EFI_SUCCESS Logging successful.
139 @retval EFI_OUT_OF_RESOURCES No remaining room for registering another option
145 IN EFI_HANDLE PciHandle
,
146 IN UINT32 ShadowAddress
,
147 IN UINT32 ShadowedSize
,
153 EFI_PCI_IO_PROTOCOL
*PciIo
;
156 // See if there is room to register another option ROM
158 if (mRomCount
>= ROM_MAX_ENTRIES
) {
159 return EFI_OUT_OF_RESOURCES
;
163 // Get the PCI I/O Protocol on PciHandle
165 Status
= gBS
->HandleProtocol (
167 &gEfiPciIoProtocolGuid
,
170 if (EFI_ERROR (Status
)) {
175 // Get the location of the PCI device
179 &mRomEntry
[mRomCount
].PciSegment
,
180 &mRomEntry
[mRomCount
].PciBus
,
181 &mRomEntry
[mRomCount
].PciDevice
,
182 &mRomEntry
[mRomCount
].PciFunction
184 mRomEntry
[mRomCount
].ShadowAddress
= ShadowAddress
;
185 mRomEntry
[mRomCount
].ShadowedSize
= ShadowedSize
;
186 mRomEntry
[mRomCount
].DiskStart
= DiskStart
;
187 mRomEntry
[mRomCount
].DiskEnd
= DiskEnd
;
195 Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This
196 information represents every call to RomShadow ()
198 @param PciHandle PCI device to get status for
200 @retval EFI_SUCCESS Legacy ROM loaded for this device
201 @retval EFI_NOT_FOUND No Legacy ROM loaded for this device
206 IN EFI_HANDLE PciHandle
210 EFI_PCI_IO_PROTOCOL
*PciIo
;
218 // Get the PCI I/O Protocol on PciHandle
220 Status
= gBS
->HandleProtocol (
222 &gEfiPciIoProtocolGuid
,
225 if (EFI_ERROR (Status
)) {
230 // Get the location of the PCI device
241 // See if the option ROM from PciHandle has been previously posted
243 for (Index
= 0; Index
< mRomCount
; Index
++) {
244 if ((mRomEntry
[Index
].PciSegment
== Segment
) &&
245 (mRomEntry
[Index
].PciBus
== Bus
) &&
246 (mRomEntry
[Index
].PciDevice
== Device
) &&
247 (mRomEntry
[Index
].PciFunction
== Function
)
254 return EFI_NOT_FOUND
;
258 Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the
259 related information from the header.
261 @param Csm16Revision The PCI interface version of underlying CSM16
262 @param VendorId Vendor ID of the PCI device
263 @param DeviceId Device ID of the PCI device
264 @param Rom On input pointing to beginning of the raw PCI OpROM
265 On output pointing to the first legacy PCI OpROM
266 @param ImageSize On input is the size of Raw PCI Rom
267 On output is the size of the first legacy PCI ROM
268 @param MaxRuntimeImageLength The max runtime image length only valid if OpRomRevision >= 3
269 @param OpRomRevision Revision of the PCI Rom
270 @param ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header
272 @retval EFI_SUCCESS Successfully find the legacy PCI ROM
273 @retval EFI_NOT_FOUND Failed to find the legacy PCI ROM
278 IN UINT16 Csm16Revision
,
282 IN OUT UINTN
*ImageSize
,
283 OUT UINTN
*MaxRuntimeImageLength OPTIONAL
,
284 OUT UINT8
*OpRomRevision OPTIONAL
,
285 OUT VOID
**ConfigUtilityCodeHeader OPTIONAL
289 UINT16
*DeviceIdList
;
290 EFI_PCI_ROM_HEADER RomHeader
;
291 PCI_3_0_DATA_STRUCTURE
*Pcir
;
295 if (*ImageSize
< sizeof (EFI_PCI_ROM_HEADER
)) {
296 return EFI_NOT_FOUND
;
301 RomHeader
.Raw
= *Rom
;
302 while (RomHeader
.Generic
->Signature
== PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
303 if ((RomHeader
.Generic
->PcirOffset
== 0) ||
304 ((RomHeader
.Generic
->PcirOffset
& 3) != 0) ||
305 (*ImageSize
< RomHeader
.Raw
- (UINT8
*)*Rom
+ RomHeader
.Generic
->PcirOffset
+ sizeof (PCI_DATA_STRUCTURE
)))
310 Pcir
= (PCI_3_0_DATA_STRUCTURE
*)(RomHeader
.Raw
+ RomHeader
.Generic
->PcirOffset
);
312 // Check signature in the PCI Data Structure.
314 if (Pcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
318 if (((UINTN
)RomHeader
.Raw
- (UINTN
)*Rom
) + Pcir
->ImageLength
* 512 > *ImageSize
) {
322 if (Pcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
324 if (Pcir
->VendorId
== VendorId
) {
325 if (Pcir
->DeviceId
== DeviceId
) {
327 } else if ((Pcir
->Revision
>= 3) && (Pcir
->DeviceListOffset
!= 0)) {
328 DeviceIdList
= (UINT16
*)(((UINT8
*)Pcir
) + Pcir
->DeviceListOffset
);
330 // Checking the device list
332 while (*DeviceIdList
!= 0) {
333 if (*DeviceIdList
== DeviceId
) {
344 if (Csm16Revision
>= 0x0300) {
348 if (Pcir
->Revision
>= 3) {
350 // case 1.1: meets OpRom 3.0
353 BestImage
= RomHeader
.Raw
;
357 // case 1.2: meets OpRom 2.x
358 // Store it and try to find the OpRom 3.0
360 BackupImage
= RomHeader
.Raw
;
366 if (Pcir
->Revision
>= 3) {
368 // case 2.1: meets OpRom 3.0
369 // Store it and try to find the OpRom 2.x
371 BackupImage
= RomHeader
.Raw
;
374 // case 2.2: meets OpRom 2.x
377 BestImage
= RomHeader
.Raw
;
382 DEBUG ((DEBUG_ERROR
, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN
)VendorId
, (UINTN
)DeviceId
));
386 if ((Pcir
->Indicator
& 0x80) == 0x80) {
389 RomHeader
.Raw
+= 512 * Pcir
->ImageLength
;
393 if (BestImage
== NULL
) {
394 if (BackupImage
== NULL
) {
395 return EFI_NOT_FOUND
;
399 // The versions of CSM16 and OpRom don't match exactly
401 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
;
486 for (Index
= 0; Index
< HandleCount
; Index
++) {
487 Status
= gBS
->HandleProtocol (
489 &gEfiPciIoProtocolGuid
,
492 if (EFI_ERROR (Status
)) {
500 sizeof (PciConfigHeader
) / sizeof (UINT32
),
504 if (IS_PCI_P2P (&PciConfigHeader
) && (BridgeIndex
< MAX_BRIDGE_INDEX
)) {
507 &Bridges
[BridgeIndex
].PciSegment
,
508 &Bridges
[BridgeIndex
].PciBus
,
509 &Bridges
[BridgeIndex
].PciDevice
,
510 &Bridges
[BridgeIndex
].PciFunction
513 Bridges
[BridgeIndex
].PrimaryBus
= PciConfigHeader
.Bridge
.PrimaryBus
;
515 Bridges
[BridgeIndex
].SecondaryBus
= PciConfigHeader
.Bridge
.SecondaryBus
;
517 Bridges
[BridgeIndex
].SubordinateBus
= PciConfigHeader
.Bridge
.SubordinateBus
;
519 for (Index1
= 0; Index1
< RoutingTableEntries
; Index1
++) {
521 // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board
522 // Once we find one, store it in the SlotBridges[]
524 if ( (RoutingTable
[Index1
].Slot
!= 0) && (Bridges
[BridgeIndex
].PrimaryBus
== RoutingTable
[Index1
].Bus
)
525 && ((Bridges
[BridgeIndex
].PciDevice
<< 3) == RoutingTable
[Index1
].Device
))
527 CopyMem (&SlotBridges
[SlotBridgeIndex
], &Bridges
[BridgeIndex
], sizeof (BRIDGE_TABLE
));
539 // Pack up Bridges by removing those useless ones
541 for (Index
= 0; Index
< BridgeIndex
;) {
542 for (Index1
= 0; Index1
< SlotBridgeIndex
; Index1
++) {
543 if (((Bridges
[Index
].PciBus
== SlotBridges
[Index1
].PrimaryBus
) && (Bridges
[Index
].PciDevice
== SlotBridges
[Index1
].PciDevice
)) ||
544 ((Bridges
[Index
].PciBus
>= SlotBridges
[Index1
].SecondaryBus
) && (Bridges
[Index
].PciBus
<= SlotBridges
[Index1
].SubordinateBus
)))
547 // We have found one that meets our criteria
555 // This one doesn't meet criteria, pack it
557 if (Index1
>= SlotBridgeIndex
) {
558 for (Index1
= Index
; BridgeIndex
> 1 && Index1
< BridgeIndex
- 1; Index1
++) {
559 CopyMem (&Bridges
[Index1
], &Bridges
[Index1
+ 1], sizeof (BRIDGE_TABLE
));
566 NumberOfBridges
= BridgeIndex
;
569 // Sort bridges low to high by Secondary bus followed by subordinate bus
571 if (NumberOfBridges
> 1) {
574 SortedBridgeIndex
[Index
] = Index
;
576 } while (Index
< NumberOfBridges
);
578 for (Index
= 0; Index
< NumberOfBridges
- 1; Index
++) {
579 for (Index1
= Index
+ 1; Index1
< NumberOfBridges
; Index1
++) {
580 if (Bridges
[Index
].SecondaryBus
> Bridges
[Index1
].SecondaryBus
) {
581 SortedBridgeIndex
[Index
] = Index1
;
582 SortedBridgeIndex
[Index1
] = Index
;
585 if ((Bridges
[Index
].SecondaryBus
== Bridges
[Index1
].SecondaryBus
) &&
586 (Bridges
[Index
].SubordinateBus
> Bridges
[Index1
].SubordinateBus
)
589 SortedBridgeIndex
[Index
] = Index1
;
590 SortedBridgeIndex
[Index1
] = Index
;
596 FreePool (HandleBuffer
);
601 Find base Bridge for device.
603 @param Private Legacy BIOS Instance data
604 @param PciBus Input = Bus of device.
605 @param PciDevice Input = Device.
606 @param RoutingTable The platform specific routing table
607 @param RoutingTableEntries Number of entries in table
609 @retval EFI_SUCCESS At base bus.
610 @retval EFI_NOT_FOUND Behind a bridge.
615 IN LEGACY_BIOS_INSTANCE
*Private
,
618 IN EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
,
619 IN UINTN RoutingTableEntries
624 for (Index
= 0; Index
< RoutingTableEntries
; Index
++) {
625 if ((RoutingTable
[Index
].Bus
== PciBus
) && (RoutingTable
[Index
].Device
== (PciDevice
<< 3))) {
630 return EFI_NOT_FOUND
;
634 Translate PIRQ through busses
636 @param Private Legacy BIOS Instance data
637 @param PciBus Input = Bus of device. Output = Translated Bus
638 @param PciDevice Input = Device. Output = Translated Device
639 @param PciFunction Input = Function. Output = Translated Function
640 @param PirqIndex Input = Original PIRQ index. If single function
641 device then 0, otherwise 0-3.
642 Output = Translated Index
644 @retval EFI_SUCCESS Pirq successfully translated.
645 @retval EFI_NOT_FOUND The device is not behind any known bridge.
650 IN LEGACY_BIOS_INSTANCE
*Private
,
651 IN OUT UINTN
*PciBus
,
652 IN OUT UINTN
*PciDevice
,
653 IN OUT UINTN
*PciFunction
,
654 IN OUT UINT8
*PirqIndex
658 This routine traverses the PCI busses from base slot
659 and translates the PIRQ register to the appropriate one.
663 Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.
666 Subordinate bus # is highest bus # behind this bus
667 Bus 1, Device 0 is Slot 0 and is not a bridge.
668 Bus 1, Device 1 is Slot 1 and is a bridge.
669 Slot PIRQ routing is A,B,C,D.
672 Subordinate bus # = 5
673 Bus 2, Device 6 is a bridge. It has no bridges behind it.
676 Subordinate bus # = 3
677 Bridge PIRQ routing is C,D,A,B
678 Bus 2, Device 7 is a bridge. It has 1 bridge behind it.
680 Secondary bus = 4 Device 6 takes bus 2.
682 Bridge PIRQ routing is D,A,B,C
683 Bus 4, Device 2 is a bridge. It has no bridges behind it.
687 Bridge PIRQ routing is B,C,D,A
688 Bus 5, Device 1 is to be programmed.
689 Device PIRQ routing is C,D,A,B
692 Search busses starting from slot bus for final bus >= Secondary bus and
693 final bus <= Subordinate bus. Assumption is bus entries increase in bus
695 Starting PIRQ is A,B,C,D.
696 Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device
697 7 modulo 4 giving (D,A,B,C).
698 Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving
700 No other busses match criteria. Device to be programmed is Bus 5, Device 1.
701 Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.
709 UINT8 LocalPirqIndex
;
710 BOOLEAN BaseIndexFlag
;
714 BaseIndexFlag
= FALSE
;
717 LocalPirqIndex
= *PirqIndex
;
719 LocalDevice
= *PciDevice
;
721 BaseDevice
= *PciDevice
;
722 BaseFunction
= *PciFunction
;
725 // LocalPirqIndex list PIRQs in rotated fashion
732 for (BridgeIndex
= 0; BridgeIndex
< NumberOfBridges
; BridgeIndex
++) {
733 SBridgeIndex
= SortedBridgeIndex
[BridgeIndex
];
735 // Check if device behind this bridge
737 if ((LocalBus
>= Bridges
[SBridgeIndex
].SecondaryBus
) && (LocalBus
<= Bridges
[SBridgeIndex
].SubordinateBus
)) {
739 // If BaseIndexFlag = FALSE then have found base bridge, i.e
740 // bridge in slot. Save info for use by IRQ routing table.
742 if (!BaseIndexFlag
) {
743 BaseBus
= Bridges
[SBridgeIndex
].PciBus
;
744 BaseDevice
= Bridges
[SBridgeIndex
].PciDevice
;
745 BaseFunction
= Bridges
[SBridgeIndex
].PciFunction
;
746 BaseIndexFlag
= TRUE
;
748 LocalPirqIndex
= (UINT8
)((LocalPirqIndex
+ (UINT8
)Bridges
[SBridgeIndex
].PciDevice
)%4);
752 // Check if at device. If not get new PCI location & PIRQ
754 if (Bridges
[SBridgeIndex
].SecondaryBus
== (UINT8
)LocalBus
) {
758 LocalPirqIndex
= (UINT8
)((LocalPirqIndex
+ (UINT8
)(LocalDevice
)) % 4);
765 // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user
767 if (BridgeIndex
>= NumberOfBridges
) {
768 DEBUG ((DEBUG_ERROR
, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus
, *PciDevice
, *PciFunction
));
771 *PirqIndex
= LocalPirqIndex
;
773 *PciDevice
= BaseDevice
;
774 *PciFunction
= BaseFunction
;
780 Copy the $PIR table as required.
782 @param Private Legacy BIOS Instance data
783 @param RoutingTable Pointer to IRQ routing table
784 @param RoutingTableEntries IRQ routing table entries
785 @param PirqTable Pointer to $PIR table
786 @param PirqTableSize Length of table
791 IN LEGACY_BIOS_INSTANCE
*Private
,
792 IN EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
,
793 IN UINTN RoutingTableEntries
,
794 IN EFI_LEGACY_PIRQ_TABLE_HEADER
*PirqTable
,
795 IN UINTN PirqTableSize
798 EFI_IA32_REGISTER_SET Regs
;
802 // Copy $PIR table, if it exists.
804 if (PirqTable
!= NULL
) {
805 Private
->LegacyRegion
->UnLock (
806 Private
->LegacyRegion
,
812 Private
->InternalIrqRoutingTable
= RoutingTable
;
813 Private
->NumberIrqRoutingEntries
= (UINT16
)(RoutingTableEntries
);
814 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
816 Regs
.X
.AX
= Legacy16GetTableAddress
;
817 Regs
.X
.CX
= (UINT16
)PirqTableSize
;
819 // Allocate at F segment according to PCI IRQ Routing Table Specification
821 Regs
.X
.BX
= (UINT16
)0x1;
823 // 16-byte boundary alignment requirement according to
824 // PCI IRQ Routing Table Specification
827 Private
->LegacyBios
.FarCall86 (
828 &Private
->LegacyBios
,
829 Private
->Legacy16CallSegment
,
830 Private
->Legacy16CallOffset
,
836 Private
->Legacy16Table
->IrqRoutingTablePointer
= (UINT32
)(Regs
.X
.DS
* 16 + Regs
.X
.BX
);
837 if (Regs
.X
.AX
!= 0) {
838 DEBUG ((DEBUG_ERROR
, "PIRQ table length insufficient - %x\n", PirqTableSize
));
840 DEBUG ((DEBUG_INFO
, "PIRQ table in legacy region - %x\n", Private
->Legacy16Table
->IrqRoutingTablePointer
));
841 Private
->Legacy16Table
->IrqRoutingTableLength
= (UINT32
)PirqTableSize
;
843 (VOID
*)(UINTN
)Private
->Legacy16Table
->IrqRoutingTablePointer
,
849 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
850 Private
->LegacyRegion
->Lock (
851 Private
->LegacyRegion
,
858 Private
->PciInterruptLine
= TRUE
;
863 Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.
865 @param PciHandle The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
870 IN EFI_LEGACY_INSTALL_PCI_HANDLER
*PciHandle
873 DEBUG ((DEBUG_INFO
, "PciBus - %02x\n", (UINTN
)PciHandle
->PciBus
));
874 DEBUG ((DEBUG_INFO
, "PciDeviceFun - %02x\n", (UINTN
)PciHandle
->PciDeviceFun
));
875 DEBUG ((DEBUG_INFO
, "PciSegment - %02x\n", (UINTN
)PciHandle
->PciSegment
));
876 DEBUG ((DEBUG_INFO
, "PciClass - %02x\n", (UINTN
)PciHandle
->PciClass
));
877 DEBUG ((DEBUG_INFO
, "PciSubclass - %02x\n", (UINTN
)PciHandle
->PciSubclass
));
878 DEBUG ((DEBUG_INFO
, "PciInterface - %02x\n", (UINTN
)PciHandle
->PciInterface
));
880 DEBUG ((DEBUG_INFO
, "PrimaryIrq - %02x\n", (UINTN
)PciHandle
->PrimaryIrq
));
881 DEBUG ((DEBUG_INFO
, "PrimaryReserved - %02x\n", (UINTN
)PciHandle
->PrimaryReserved
));
882 DEBUG ((DEBUG_INFO
, "PrimaryControl - %04x\n", (UINTN
)PciHandle
->PrimaryControl
));
883 DEBUG ((DEBUG_INFO
, "PrimaryBase - %04x\n", (UINTN
)PciHandle
->PrimaryBase
));
884 DEBUG ((DEBUG_INFO
, "PrimaryBusMaster - %04x\n", (UINTN
)PciHandle
->PrimaryBusMaster
));
886 DEBUG ((DEBUG_INFO
, "SecondaryIrq - %02x\n", (UINTN
)PciHandle
->SecondaryIrq
));
887 DEBUG ((DEBUG_INFO
, "SecondaryReserved - %02x\n", (UINTN
)PciHandle
->SecondaryReserved
));
888 DEBUG ((DEBUG_INFO
, "SecondaryControl - %04x\n", (UINTN
)PciHandle
->SecondaryControl
));
889 DEBUG ((DEBUG_INFO
, "SecondaryBase - %04x\n", (UINTN
)PciHandle
->SecondaryBase
));
890 DEBUG ((DEBUG_INFO
, "SecondaryBusMaster - %04x\n", (UINTN
)PciHandle
->SecondaryBusMaster
));
895 Copy the $PIR table as required.
897 @param Private Legacy BIOS Instance data
898 @param PciIo Pointer to PCI_IO protocol
899 @param PciIrq Pci IRQ number
900 @param PciConfigHeader Type00 Pci configuration header
904 InstallLegacyIrqHandler (
905 IN LEGACY_BIOS_INSTANCE
*Private
,
906 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
908 IN PCI_TYPE00
*PciConfigHeader
911 EFI_IA32_REGISTER_SET Regs
;
917 EFI_LEGACY_8259_PROTOCOL
*Legacy8259
;
918 UINT16 PrimaryMaster
;
919 UINT16 SecondaryMaster
;
921 UINTN RegisterAddress
;
926 Legacy8259
= Private
->Legacy8259
;
928 // Disable interrupt in PIC, in case shared, to prevent an
929 // interrupt from occurring.
931 Legacy8259
->GetMask (
939 LegMask
= (UINT16
)(LegMask
| (UINT16
)(1 << PciIrq
));
941 Legacy8259
->SetMask (
956 Private
->IntThunk
->PciHandler
.PciBus
= (UINT8
)PciBus
;
957 Private
->IntThunk
->PciHandler
.PciDeviceFun
= (UINT8
)((PciDevice
<< 3) + PciFunction
);
958 Private
->IntThunk
->PciHandler
.PciSegment
= (UINT8
)PciSegment
;
959 Private
->IntThunk
->PciHandler
.PciClass
= PciConfigHeader
->Hdr
.ClassCode
[2];
960 Private
->IntThunk
->PciHandler
.PciSubclass
= PciConfigHeader
->Hdr
.ClassCode
[1];
961 Private
->IntThunk
->PciHandler
.PciInterface
= PciConfigHeader
->Hdr
.ClassCode
[0];
964 // Use native mode base address registers in two cases:
965 // 1. Programming Interface (PI) register indicates Primary Controller is
967 // 2. PCI device Sub Class Code is not IDE
969 Private
->IntThunk
->PciHandler
.PrimaryBusMaster
= (UINT16
)(PciConfigHeader
->Device
.Bar
[4] & 0xfffc);
970 if (((PciConfigHeader
->Hdr
.ClassCode
[0] & 0x01) != 0) || (PciConfigHeader
->Hdr
.ClassCode
[1] != PCI_CLASS_MASS_STORAGE_IDE
)) {
971 Private
->IntThunk
->PciHandler
.PrimaryIrq
= PciIrq
;
972 Private
->IntThunk
->PciHandler
.PrimaryBase
= (UINT16
)(PciConfigHeader
->Device
.Bar
[0] & 0xfffc);
973 Private
->IntThunk
->PciHandler
.PrimaryControl
= (UINT16
)((PciConfigHeader
->Device
.Bar
[1] & 0xfffc) + 2);
975 Private
->IntThunk
->PciHandler
.PrimaryIrq
= 14;
976 Private
->IntThunk
->PciHandler
.PrimaryBase
= 0x1f0;
977 Private
->IntThunk
->PciHandler
.PrimaryControl
= 0x3f6;
981 // Secondary controller data
983 if (Private
->IntThunk
->PciHandler
.PrimaryBusMaster
!= 0) {
984 Private
->IntThunk
->PciHandler
.SecondaryBusMaster
= (UINT16
)((PciConfigHeader
->Device
.Bar
[4] & 0xfffc) + 8);
985 PrimaryMaster
= (UINT16
)(Private
->IntThunk
->PciHandler
.PrimaryBusMaster
+ 2);
986 SecondaryMaster
= (UINT16
)(Private
->IntThunk
->PciHandler
.SecondaryBusMaster
+ 2);
989 // Clear pending interrupts in Bus Master registers
991 IoWrite16 (PrimaryMaster
, 0x04);
992 IoWrite16 (SecondaryMaster
, 0x04);
996 // Use native mode base address registers in two cases:
997 // 1. Programming Interface (PI) register indicates Secondary Controller is
999 // 2. PCI device Sub Class Code is not IDE
1001 if (((PciConfigHeader
->Hdr
.ClassCode
[0] & 0x04) != 0) || (PciConfigHeader
->Hdr
.ClassCode
[1] != PCI_CLASS_MASS_STORAGE_IDE
)) {
1002 Private
->IntThunk
->PciHandler
.SecondaryIrq
= PciIrq
;
1003 Private
->IntThunk
->PciHandler
.SecondaryBase
= (UINT16
)(PciConfigHeader
->Device
.Bar
[2] & 0xfffc);
1004 Private
->IntThunk
->PciHandler
.SecondaryControl
= (UINT16
)((PciConfigHeader
->Device
.Bar
[3] & 0xfffc) + 2);
1006 Private
->IntThunk
->PciHandler
.SecondaryIrq
= 15;
1007 Private
->IntThunk
->PciHandler
.SecondaryBase
= 0x170;
1008 Private
->IntThunk
->PciHandler
.SecondaryControl
= 0x376;
1012 // Clear pending interrupts in IDE Command Block Status reg before we
1013 // Thunk to CSM16 below. Don't want a pending Interrupt before we
1014 // install the handlers as wierd corruption would occur and hang system.
1017 // Read IDE CMD blk status reg to clear out any pending interrupts.
1018 // Do here for Primary and Secondary IDE channels
1020 RegisterAddress
= (UINT16
)Private
->IntThunk
->PciHandler
.PrimaryBase
+ 0x07;
1021 IoRead8 (RegisterAddress
);
1022 RegisterAddress
= (UINT16
)Private
->IntThunk
->PciHandler
.SecondaryBase
+ 0x07;
1023 IoRead8 (RegisterAddress
);
1025 Private
->IntThunk
->PciHandler
.PrimaryReserved
= 0;
1026 Private
->IntThunk
->PciHandler
.SecondaryReserved
= 0;
1027 Private
->LegacyRegion
->UnLock (
1028 Private
->LegacyRegion
,
1034 Regs
.X
.AX
= Legacy16InstallPciHandler
;
1035 TempData
= (UINTN
)&Private
->IntThunk
->PciHandler
;
1036 Regs
.X
.ES
= EFI_SEGMENT ((UINT32
)TempData
);
1037 Regs
.X
.BX
= EFI_OFFSET ((UINT32
)TempData
);
1039 DumpPciHandle (&Private
->IntThunk
->PciHandler
);
1041 Private
->LegacyBios
.FarCall86 (
1042 &Private
->LegacyBios
,
1043 Private
->Legacy16CallSegment
,
1044 Private
->Legacy16CallOffset
,
1050 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
1051 Private
->LegacyRegion
->Lock (
1052 Private
->LegacyRegion
,
1060 Program the interrupt routing register in all the PCI devices. On a PC AT system
1061 this register contains the 8259 IRQ vector that matches its PCI interrupt.
1063 @param Private Legacy BIOS Instance data
1065 @retval EFI_SUCCESS Succeed.
1066 @retval EFI_ALREADY_STARTED All PCI devices have been processed.
1070 PciProgramAllInterruptLineRegisters (
1071 IN LEGACY_BIOS_INSTANCE
*Private
1075 EFI_PCI_IO_PROTOCOL
*PciIo
;
1076 EFI_LEGACY_8259_PROTOCOL
*Legacy8259
;
1077 EFI_LEGACY_INTERRUPT_PROTOCOL
*LegacyInterrupt
;
1078 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
1082 EFI_HANDLE
*HandleBuffer
;
1083 UINTN MassStorageHandleCount
;
1084 EFI_HANDLE
*MassStorageHandleBuffer
;
1085 UINTN MassStorageHandleIndex
;
1092 EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
;
1093 UINTN RoutingTableEntries
;
1095 UINT16 LegEdgeLevel
;
1096 PCI_TYPE00 PciConfigHeader
;
1097 EFI_LEGACY_PIRQ_TABLE_HEADER
*PirqTable
;
1098 UINTN PirqTableSize
;
1104 // Note - This routine use to return immediately if Private->PciInterruptLine
1105 // was true. Routine changed since resets etc can cause not all
1106 // PciIo protocols to be registered the first time through.
1107 // New algorithm is to do the copy $PIR table on first pass and save
1108 // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives
1109 // a larger handle count then proceed with body of function else return
1110 // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.
1111 // If zero then function unprogrammed else skip function.
1113 Legacy8259
= Private
->Legacy8259
;
1114 LegacyInterrupt
= Private
->LegacyInterrupt
;
1115 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
1117 LegacyBiosPlatform
->GetRoutingTable (
1118 Private
->LegacyBiosPlatform
,
1119 (VOID
*)&RoutingTable
,
1120 &RoutingTableEntries
,
1126 CreateBridgeTable (RoutingTable
, RoutingTableEntries
);
1128 if (!Private
->PciInterruptLine
) {
1132 RoutingTableEntries
,
1138 Status
= gBS
->LocateHandleBuffer (
1140 &gEfiPciIoProtocolGuid
,
1145 if (EFI_ERROR (Status
)) {
1146 return EFI_NOT_FOUND
;
1149 if (HandleCount
== mHandleCount
) {
1150 FreePool (HandleBuffer
);
1151 return EFI_ALREADY_STARTED
;
1154 if (mHandleCount
== 0x00) {
1155 mHandleCount
= HandleCount
;
1158 for (Index
= 0; Index
< HandleCount
; Index
++) {
1160 // If VGA then only do VGA to allow drives fore time to spin up
1161 // otherwise assign PCI IRQs to all potential devices.
1163 if ((mVgaInstallationInProgress
) && (HandleBuffer
[Index
] != mVgaHandle
)) {
1167 // Force code to go through all handles next time called if video.
1168 // This will catch case where HandleCount doesn't change but want
1169 // to get drive info etc.
1171 mHandleCount
= 0x00;
1174 Status
= gBS
->HandleProtocol (
1175 HandleBuffer
[Index
],
1176 &gEfiPciIoProtocolGuid
,
1179 ASSERT_EFI_ERROR (Status
);
1182 // Test whether the device can be enabled or not.
1183 // If it can't be enabled, then just skip it to avoid further operation.
1187 EfiPciIoWidthUint32
,
1189 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1192 Command
= PciConfigHeader
.Hdr
.Command
;
1195 // Note PciIo->Attributes does not program the PCI command register
1197 Status
= PciIo
->Attributes (
1199 EfiPciIoAttributeOperationSupported
,
1203 if (!EFI_ERROR (Status
)) {
1204 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
1205 Status
= PciIo
->Attributes (
1207 EfiPciIoAttributeOperationEnable
,
1213 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint16
, 0x04, 1, &Command
);
1215 if (EFI_ERROR (Status
)) {
1219 InterruptPin
= PciConfigHeader
.Device
.InterruptPin
;
1221 if ((InterruptPin
!= 0) && (PciConfigHeader
.Device
.InterruptLine
== PCI_INT_LINE_UNKNOWN
)) {
1222 PciIo
->GetLocation (
1230 // Translate PIRQ index back thru busses to slot bus with InterruptPin
1235 Status
= GetBaseBus (
1243 if (Status
== EFI_NOT_FOUND
) {
1254 // Translate InterruptPin(0-3) into PIRQ
1256 Status
= LegacyBiosPlatform
->TranslatePirq (
1265 // TranslatePirq() should never fail or we are in trouble
1266 // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect
1268 if (EFI_ERROR (Status
)) {
1269 DEBUG ((DEBUG_ERROR
, "Translate Pirq Failed - Status = %r\n ", Status
));
1273 LegacyInterrupt
->WritePirq (
1280 // Check if device has an OPROM associated with it.
1281 // If not invoke special 16-bit function, to allow 16-bit
1282 // code to install an interrupt handler.
1284 Status
= LegacyBiosCheckPciRom (
1285 &Private
->LegacyBios
,
1286 HandleBuffer
[Index
],
1291 if ((EFI_ERROR (Status
)) && (PciConfigHeader
.Hdr
.ClassCode
[2] == PCI_CLASS_MASS_STORAGE
)) {
1293 // Device has no OPROM associated with it and is a mass storage
1294 // device. It needs to have an PCI IRQ handler installed. To
1295 // correctly install the handler we need to insure device is
1296 // connected. The device may just have register itself but not
1297 // been connected. Re-read PCI config space after as it can
1301 // Get IDE Handle. If matches handle then skip ConnectController
1302 // since ConnectController may force native mode and we don't
1303 // want that for primary IDE controller
1305 MassStorageHandleCount
= 0;
1306 MassStorageHandleBuffer
= NULL
;
1307 LegacyBiosPlatform
->GetPlatformHandle (
1308 Private
->LegacyBiosPlatform
,
1309 EfiGetPlatformIdeHandle
,
1311 &MassStorageHandleBuffer
,
1312 &MassStorageHandleCount
,
1316 HddInfo
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
[0];
1318 LegacyBiosBuildIdeData (Private
, &HddInfo
, 0);
1321 EfiPciIoWidthUint32
,
1323 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1327 for (MassStorageHandleIndex
= 0; MassStorageHandleIndex
< MassStorageHandleCount
; MassStorageHandleIndex
++) {
1328 if (MassStorageHandleBuffer
[MassStorageHandleIndex
] == HandleBuffer
[Index
]) {
1330 // InstallLegacyIrqHandler according to Platform requirement
1332 InstallLegacyIrqHandler (
1344 // Write InterruptPin and enable 8259.
1353 Private
->IntThunk
->EfiToLegacy16BootTable
.PciIrqMask
= (UINT16
)(Private
->IntThunk
->EfiToLegacy16BootTable
.PciIrqMask
| (UINT16
)(1 << PciIrq
));
1355 Legacy8259
->GetMask (
1363 LegMask
= (UINT16
)(LegMask
& (UINT16
) ~(1 << PciIrq
));
1364 LegEdgeLevel
= (UINT16
)(LegEdgeLevel
| (UINT16
)(1 << PciIrq
));
1365 Legacy8259
->SetMask (
1375 FreePool (HandleBuffer
);
1380 Find & verify PnP Expansion header in ROM image
1382 @param Private Protocol instance pointer.
1383 @param FirstHeader 1 = Find first header, 0 = Find successive headers
1384 @param PnpPtr Input Rom start if FirstHeader =1, Current Header
1385 otherwise Output Next header, if it exists
1387 @retval EFI_SUCCESS Next Header found at BasePnpPtr
1388 @retval EFI_NOT_FOUND No more headers
1392 FindNextPnpExpansionHeader (
1393 IN LEGACY_BIOS_INSTANCE
*Private
,
1394 IN BOOLEAN FirstHeader
,
1395 IN OUT LEGACY_PNP_EXPANSION_HEADER
**PnpPtr
1400 LEGACY_PNP_EXPANSION_HEADER
*LocalPnpPtr
;
1402 LocalPnpPtr
= *PnpPtr
;
1403 if (FirstHeader
== FIRST_INSTANCE
) {
1404 mBasePnpPtr
= LocalPnpPtr
;
1405 mBbsRomSegment
= (UINT16
)((UINTN
)mBasePnpPtr
>> 4);
1407 // Offset 0x1a gives offset to PnP expansion header for the first
1408 // instance, there after the structure gives the offset to the next
1411 LocalPnpPtr
= (LEGACY_PNP_EXPANSION_HEADER
*)((UINT8
*)LocalPnpPtr
+ 0x1a);
1412 TempData
= (*((UINT16
*)LocalPnpPtr
));
1414 TempData
= (UINT16
)LocalPnpPtr
->NextHeader
;
1417 LocalPnpPtr
= (LEGACY_PNP_EXPANSION_HEADER
*)(((UINT8
*)mBasePnpPtr
+ TempData
));
1420 // Search for PnP table in Shadowed ROM
1422 *PnpPtr
= LocalPnpPtr
;
1423 if (*(UINT32
*)LocalPnpPtr
== SIGNATURE_32 ('$', 'P', 'n', 'P')) {
1426 return EFI_NOT_FOUND
;
1431 Update list of Bev or BCV table entries.
1433 @param Private Protocol instance pointer.
1434 @param RomStart Table of ROM start address in RAM/ROM. PciIo _
1435 Handle to PCI IO for this device
1436 @param PciIo Instance of PCI I/O Protocol
1438 @retval EFI_SUCCESS Always should succeed.
1443 IN LEGACY_BIOS_INSTANCE
*Private
,
1444 IN EFI_LEGACY_EXPANSION_ROM_HEADER
*RomStart
,
1445 IN EFI_PCI_IO_PROTOCOL
*PciIo
1449 BBS_TABLE
*BbsTable
;
1451 EFI_LEGACY_EXPANSION_ROM_HEADER
*PciPtr
;
1452 LEGACY_PNP_EXPANSION_HEADER
*PnpPtr
;
1467 DeviceType
= BBS_UNKNOWN
;
1470 // Skip floppy and 2*onboard IDE controller entries(Master/Slave per
1473 BbsIndex
= Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
;
1475 BbsTable
= (BBS_TABLE
*)(UINTN
)Private
->IntThunk
->EfiToLegacy16BootTable
.BbsTable
;
1476 PnpPtr
= (LEGACY_PNP_EXPANSION_HEADER
*)RomStart
;
1477 PciPtr
= (EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomStart
;
1479 RomEnd
= (VOID
*)(PciPtr
->Size512
* 512 + (UINTN
)PciPtr
);
1480 Instance
= FIRST_INSTANCE
;
1482 // OPROMs like PXE may not be tied to a piece of hardware and thus
1483 // don't have a PciIo associated with them
1485 if (PciIo
!= NULL
) {
1486 PciIo
->GetLocation (
1501 if (Class
== PCI_CLASS_MASS_STORAGE
) {
1502 DeviceType
= BBS_HARDDISK
;
1504 if (Class
== PCI_CLASS_NETWORK
) {
1505 DeviceType
= BBS_EMBED_NETWORK
;
1511 Status
= FindNextPnpExpansionHeader (Private
, Instance
, &PnpPtr
);
1512 Instance
= NOT_FIRST_INSTANCE
;
1513 if (EFI_ERROR (Status
)) {
1518 // There can be additional $PnP headers within the OPROM.
1519 // Example: SCSI can have one per drive.
1521 BbsTable
[BbsIndex
].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1522 BbsTable
[BbsIndex
].DeviceType
= DeviceType
;
1523 BbsTable
[BbsIndex
].Bus
= (UINT32
)Bus
;
1524 BbsTable
[BbsIndex
].Device
= (UINT32
)Device
;
1525 BbsTable
[BbsIndex
].Function
= (UINT32
)Function
;
1526 BbsTable
[BbsIndex
].StatusFlags
.OldPosition
= 0;
1527 BbsTable
[BbsIndex
].StatusFlags
.Reserved1
= 0;
1528 BbsTable
[BbsIndex
].StatusFlags
.Enabled
= 0;
1529 BbsTable
[BbsIndex
].StatusFlags
.Failed
= 0;
1530 BbsTable
[BbsIndex
].StatusFlags
.MediaPresent
= 0;
1531 BbsTable
[BbsIndex
].StatusFlags
.Reserved2
= 0;
1532 BbsTable
[BbsIndex
].Class
= PnpPtr
->Class
;
1533 BbsTable
[BbsIndex
].SubClass
= PnpPtr
->SubClass
;
1534 BbsTable
[BbsIndex
].DescStringOffset
= PnpPtr
->ProductNamePointer
;
1535 BbsTable
[BbsIndex
].DescStringSegment
= mBbsRomSegment
;
1536 BbsTable
[BbsIndex
].MfgStringOffset
= PnpPtr
->MfgPointer
;
1537 BbsTable
[BbsIndex
].MfgStringSegment
= mBbsRomSegment
;
1538 BbsTable
[BbsIndex
].BootHandlerSegment
= mBbsRomSegment
;
1541 // Have seen case where PXE base code have PnP expansion ROM
1542 // header but no Bcv or Bev vectors.
1544 if (PnpPtr
->Bcv
!= 0) {
1545 BbsTable
[BbsIndex
].BootHandlerOffset
= PnpPtr
->Bcv
;
1549 if (PnpPtr
->Bev
!= 0) {
1550 BbsTable
[BbsIndex
].BootHandlerOffset
= PnpPtr
->Bev
;
1551 BbsTable
[BbsIndex
].DeviceType
= BBS_BEV_DEVICE
;
1555 if ((PnpPtr
== (LEGACY_PNP_EXPANSION_HEADER
*)PciPtr
) || (PnpPtr
> (LEGACY_PNP_EXPANSION_HEADER
*)RomEnd
)) {
1560 BbsTable
[BbsIndex
].BootPriority
= BBS_IGNORE_ENTRY
;
1561 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
= (UINT32
)BbsIndex
;
1566 Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
1567 to chose the order. Skip any devices that have already have legacy
1570 @param Private Protocol instance pointer.
1572 @retval EFI_SUCCESS Succeed.
1573 @retval EFI_UNSUPPORTED Cannot get VGA device handle.
1578 IN LEGACY_BIOS_INSTANCE
*Private
1582 EFI_PCI_IO_PROTOCOL
*PciIo
;
1586 EFI_HANDLE
*HandleBuffer
;
1587 EFI_HANDLE VgaHandle
;
1588 EFI_HANDLE FirstHandle
;
1591 PCI_TYPE00 PciConfigHeader
;
1596 // Make the VGA device first
1598 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
1599 Private
->LegacyBiosPlatform
,
1600 EfiGetPlatformVgaHandle
,
1606 if (EFI_ERROR (Status
)) {
1607 return EFI_UNSUPPORTED
;
1610 VgaHandle
= HandleBuffer
[0];
1612 Status
= gBS
->LocateHandleBuffer (
1614 &gEfiPciIoProtocolGuid
,
1620 if (EFI_ERROR (Status
)) {
1625 // Place the VGA handle as first.
1627 for (Index
= 0; Index
< HandleCount
; Index
++) {
1628 if (HandleBuffer
[Index
] == VgaHandle
) {
1629 FirstHandle
= HandleBuffer
[0];
1630 HandleBuffer
[0] = HandleBuffer
[Index
];
1631 HandleBuffer
[Index
] = FirstHandle
;
1637 // Allocate memory to save Command WORD from each device. We do this
1638 // to restore devices to same state as EFI after switching to legacy.
1640 Command
= (UINT16
*)AllocatePool (
1641 sizeof (UINT16
) * (HandleCount
+ 1)
1643 if (NULL
== Command
) {
1644 FreePool (HandleBuffer
);
1645 return EFI_OUT_OF_RESOURCES
;
1649 // Disconnect all EFI devices first. This covers cases where alegacy BIOS
1650 // may control multiple PCI devices.
1652 for (Index
= 0; Index
< HandleCount
; Index
++) {
1653 Status
= gBS
->HandleProtocol (
1654 HandleBuffer
[Index
],
1655 &gEfiPciIoProtocolGuid
,
1658 ASSERT_EFI_ERROR (Status
);
1661 // Save command register for "connect" loop
1665 EfiPciIoWidthUint32
,
1667 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1670 Command
[Index
] = PciConfigHeader
.Hdr
.Command
;
1672 // Skip any device that already has a legacy ROM run
1674 Status
= IsLegacyRom (HandleBuffer
[Index
]);
1675 if (!EFI_ERROR (Status
)) {
1680 // Stop EFI Drivers with oprom.
1682 gBS
->DisconnectController (
1683 HandleBuffer
[Index
],
1690 // For every device that has not had a legacy ROM started. Start a legacy ROM.
1692 for (Index
= 0; Index
< HandleCount
; Index
++) {
1693 Status
= gBS
->HandleProtocol (
1694 HandleBuffer
[Index
],
1695 &gEfiPciIoProtocolGuid
,
1699 ASSERT_EFI_ERROR (Status
);
1702 // Here make sure if one VGA have been shadowed,
1703 // then wil not shadowed another one.
1707 EfiPciIoWidthUint32
,
1709 sizeof (Pci
) / sizeof (UINT32
),
1714 // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices,
1715 // one will work in legacy mode (OPROM will be given control) and
1716 // other Video devices will work in native mode (OS driver will handle these devices).
1718 if (IS_PCI_DISPLAY (&Pci
) && (Index
!= 0)) {
1723 // Skip any device that already has a legacy ROM run
1725 Status
= IsLegacyRom (HandleBuffer
[Index
]);
1726 if (!EFI_ERROR (Status
)) {
1731 // If legacy VBIOS Oprom has not been dispatched before, install legacy VBIOS here.
1733 if (IS_PCI_DISPLAY (&Pci
) && (Index
== 0)) {
1734 Status
= LegacyBiosInstallVgaRom (Private
);
1736 // A return status of EFI_NOT_FOUND is considered valid (No EFI
1737 // driver is controlling video).
1739 ASSERT ((Status
== EFI_SUCCESS
) || (Status
== EFI_NOT_FOUND
));
1744 // Install legacy ROM
1746 Status
= LegacyBiosInstallPciRom (
1747 &Private
->LegacyBios
,
1748 HandleBuffer
[Index
],
1756 if (EFI_ERROR (Status
)) {
1757 if (!((Status
== EFI_UNSUPPORTED
) && (Flags
== NO_ROM
))) {
1763 // Restore Command register so legacy has same devices enabled or disabled
1765 // If Flags = NO_ROM use command register as is. This covers the
1767 // Device has no ROMs associated with it.
1768 // Device has ROM associated with it but was already
1770 // = ROM_FOUND but not VALID_LEGACY_ROM, disable it.
1771 // = ROM_FOUND and VALID_LEGACY_ROM, enable it.
1773 if ((Flags
& ROM_FOUND
) == ROM_FOUND
) {
1774 if ((Flags
& VALID_LEGACY_ROM
) == 0) {
1778 // For several VGAs, only one of them can be enabled.
1780 Status
= PciIo
->Attributes (
1782 EfiPciIoAttributeOperationSupported
,
1786 if (!EFI_ERROR (Status
)) {
1787 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
1788 Status
= PciIo
->Attributes (
1790 EfiPciIoAttributeOperationEnable
,
1796 if (!EFI_ERROR (Status
)) {
1797 Command
[Index
] = 0x1f;
1804 EfiPciIoWidthUint16
,
1812 FreePool (HandleBuffer
);
1817 Test to see if a legacy PCI ROM exists for this device. Optionally return
1818 the Legacy ROM instance for this PCI device.
1820 @param This Protocol instance pointer.
1821 @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
1823 @param RomImage Return the legacy PCI ROM for this device
1824 @param RomSize Size of ROM Image
1825 @param Flags Indicates if ROM found and if PC-AT.
1827 @retval EFI_SUCCESS Legacy Option ROM available for this device
1828 @retval EFI_UNSUPPORTED Legacy Option ROM not supported.
1833 LegacyBiosCheckPciRom (
1834 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1835 IN EFI_HANDLE PciHandle
,
1836 OUT VOID
**RomImage OPTIONAL
,
1837 OUT UINTN
*RomSize OPTIONAL
,
1841 return LegacyBiosCheckPciRomEx (
1855 Routine Description:
1856 Test to see if a legacy PCI ROM exists for this device. Optionally return
1857 the Legacy ROM instance for this PCI device.
1859 @param[in] This Protocol instance pointer.
1860 @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded
1861 @param[out] RomImage Return the legacy PCI ROM for this device
1862 @param[out] RomSize Size of ROM Image
1863 @param[out] RuntimeImageLength Runtime size of ROM Image
1864 @param[out] Flags Indicates if ROM found and if PC-AT.
1865 @param[out] OpromRevision Revision of the PCI Rom
1866 @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
1868 @return EFI_SUCCESS Legacy Option ROM available for this device
1869 @return EFI_ALREADY_STARTED This device is already managed by its Oprom
1870 @return EFI_UNSUPPORTED Legacy Option ROM not supported.
1874 LegacyBiosCheckPciRomEx (
1875 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1876 IN EFI_HANDLE PciHandle
,
1877 OUT VOID
**RomImage OPTIONAL
,
1878 OUT UINTN
*RomSize OPTIONAL
,
1879 OUT UINTN
*RuntimeImageLength OPTIONAL
,
1880 OUT UINTN
*Flags OPTIONAL
,
1881 OUT UINT8
*OpromRevision OPTIONAL
,
1882 OUT VOID
**ConfigUtilityCodeHeader OPTIONAL
1886 LEGACY_BIOS_INSTANCE
*Private
;
1887 EFI_PCI_IO_PROTOCOL
*PciIo
;
1889 VOID
*LocalRomImage
;
1890 PCI_TYPE00 PciConfigHeader
;
1891 VOID
*LocalConfigUtilityCodeHeader
;
1893 LocalConfigUtilityCodeHeader
= NULL
;
1895 Status
= gBS
->HandleProtocol (
1897 &gEfiPciIoProtocolGuid
,
1900 if (EFI_ERROR (Status
)) {
1901 return EFI_UNSUPPORTED
;
1905 // See if the option ROM for PciHandle has already been executed
1907 Status
= IsLegacyRom (PciHandle
);
1908 if (!EFI_ERROR (Status
)) {
1909 *Flags
|= (UINTN
)(ROM_FOUND
| VALID_LEGACY_ROM
);
1914 // Check for PCI ROM Bar
1916 LocalRomSize
= (UINTN
)PciIo
->RomSize
;
1917 LocalRomImage
= PciIo
->RomImage
;
1918 if (LocalRomSize
!= 0) {
1919 *Flags
|= ROM_FOUND
;
1923 // PCI specification states you should check VendorId and Device Id.
1927 EfiPciIoWidthUint32
,
1929 sizeof (PciConfigHeader
) / sizeof (UINT32
),
1933 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1934 Status
= GetPciLegacyRom (
1935 Private
->Csm16PciInterfaceVersion
,
1936 PciConfigHeader
.Hdr
.VendorId
,
1937 PciConfigHeader
.Hdr
.DeviceId
,
1942 &LocalConfigUtilityCodeHeader
1944 if (EFI_ERROR (Status
)) {
1945 return EFI_UNSUPPORTED
;
1948 *Flags
|= VALID_LEGACY_ROM
;
1951 // See if Configuration Utility Code Header valid
1953 if (LocalConfigUtilityCodeHeader
!= NULL
) {
1954 *Flags
|= ROM_WITH_CONFIG
;
1957 if (ConfigUtilityCodeHeader
!= NULL
) {
1958 *ConfigUtilityCodeHeader
= LocalConfigUtilityCodeHeader
;
1961 if (RomImage
!= NULL
) {
1962 *RomImage
= LocalRomImage
;
1965 if (RomSize
!= NULL
) {
1966 *RomSize
= LocalRomSize
;
1973 Load a legacy PC-AT OPROM on the PciHandle device. Return information
1974 about how many disks were added by the OPROM and the shadow address and
1975 size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
1977 @retval EFI_SUCCESS Legacy ROM loaded for this device
1978 @retval EFI_NOT_FOUND No PS2 Keyboard found
1987 EFI_HANDLE
*HandleBuffer
;
1989 EFI_ISA_IO_PROTOCOL
*IsaIo
;
1993 // Get SimpleTextIn and find PS2 controller
1995 Status
= gBS
->LocateHandleBuffer (
1997 &gEfiSimpleTextInProtocolGuid
,
2002 if (EFI_ERROR (Status
)) {
2003 return EFI_NOT_FOUND
;
2006 for (Index
= 0; Index
< HandleCount
; Index
++) {
2008 // Open the IO Abstraction(s) needed to perform the supported test
2010 Status
= gBS
->OpenProtocol (
2011 HandleBuffer
[Index
],
2012 &gEfiIsaIoProtocolGuid
,
2015 HandleBuffer
[Index
],
2016 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
2019 if (!EFI_ERROR (Status
)) {
2021 // Use the ISA I/O Protocol to see if Controller is the Keyboard
2024 if ((IsaIo
->ResourceList
->Device
.HID
!= EISA_PNP_ID (0x303)) || (IsaIo
->ResourceList
->Device
.UID
!= 0)) {
2025 Status
= EFI_UNSUPPORTED
;
2028 gBS
->CloseProtocol (
2029 HandleBuffer
[Index
],
2030 &gEfiIsaIoProtocolGuid
,
2036 if (!EFI_ERROR (Status
)) {
2037 gBS
->ConnectController (HandleBuffer
[Index
], NULL
, NULL
, FALSE
);
2041 FreePool (HandleBuffer
);
2046 Load a legacy PC-AT OpROM for VGA controller.
2048 @param Private Driver private data.
2050 @retval EFI_SUCCESS Legacy ROM successfully installed for this device.
2051 @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video
2052 driver cannot be successfully disconnected, or VGA
2053 thunk driver cannot be successfully connected.
2057 LegacyBiosInstallVgaRom (
2058 IN LEGACY_BIOS_INSTANCE
*Private
2062 EFI_HANDLE VgaHandle
;
2064 EFI_HANDLE
*HandleBuffer
;
2065 EFI_HANDLE
*ConnectHandleBuffer
;
2066 EFI_PCI_IO_PROTOCOL
*PciIo
;
2067 PCI_TYPE00 PciConfigHeader
;
2069 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
2075 // EfiLegacyBiosGuild attached to a device implies that there is a legacy
2076 // BIOS associated with that device.
2078 // There are 3 cases to consider.
2079 // Case 1: No EFI driver is controlling the video.
2080 // Action: Return EFI_SUCCESS from DisconnectController, search
2081 // video thunk driver, and connect it.
2082 // Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is
2083 // not on the image handle.
2084 // Action: Disconnect EFI driver.
2085 // ConnectController for video thunk
2086 // Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is
2087 // on the image handle.
2088 // Action: Do nothing and set Private->VgaInstalled = TRUE.
2089 // Then this routine is not called any more.
2092 // Get the VGA device.
2094 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
2095 Private
->LegacyBiosPlatform
,
2096 EfiGetPlatformVgaHandle
,
2102 if (EFI_ERROR (Status
)) {
2103 return EFI_DEVICE_ERROR
;
2106 VgaHandle
= HandleBuffer
[0];
2109 // Check whether video thunk driver already starts.
2111 Status
= gBS
->OpenProtocolInformation (
2113 &gEfiPciIoProtocolGuid
,
2117 if (EFI_ERROR (Status
)) {
2121 for (Index
= 0; Index
< EntryCount
; Index
++) {
2122 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) != 0) {
2123 Status
= gBS
->HandleProtocol (
2124 OpenInfoBuffer
[Index
].AgentHandle
,
2125 &gEfiLegacyBiosGuid
,
2128 if (!EFI_ERROR (Status
)) {
2130 // This should be video thunk driver which is managing video device
2131 // So it need not start again
2133 DEBUG ((DEBUG_INFO
, "Video thunk driver already start! Return!\n"));
2134 Private
->VgaInstalled
= TRUE
;
2141 // Kick off the native EFI driver
2143 Status
= gBS
->DisconnectController (
2148 if (EFI_ERROR (Status
)) {
2149 if (Status
!= EFI_NOT_FOUND
) {
2150 return EFI_DEVICE_ERROR
;
2157 // Find all the Thunk Driver
2159 HandleBuffer
= NULL
;
2160 Status
= gBS
->LocateHandleBuffer (
2162 &gEfiLegacyBiosGuid
,
2167 ASSERT_EFI_ERROR (Status
);
2168 ConnectHandleBuffer
= (EFI_HANDLE
*)AllocatePool (sizeof (EFI_HANDLE
) * (HandleCount
+ 1));
2169 ASSERT (ConnectHandleBuffer
!= NULL
);
2172 ConnectHandleBuffer
,
2174 sizeof (EFI_HANDLE
) * HandleCount
2176 ConnectHandleBuffer
[HandleCount
] = NULL
;
2178 FreePool (HandleBuffer
);
2181 // Enable the device and make sure VGA cycles are being forwarded to this VGA device
2183 Status
= gBS
->HandleProtocol (
2185 &gEfiPciIoProtocolGuid
,
2188 ASSERT_EFI_ERROR (Status
);
2191 EfiPciIoWidthUint32
,
2193 sizeof (PciConfigHeader
) / sizeof (UINT32
),
2197 Status
= PciIo
->Attributes (
2199 EfiPciIoAttributeOperationSupported
,
2203 if (!EFI_ERROR (Status
)) {
2204 Supports
&= (UINT64
)(EFI_PCI_DEVICE_ENABLE
| EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
| \
2205 EFI_PCI_IO_ATTRIBUTE_VGA_IO
| EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
);
2206 Status
= PciIo
->Attributes (
2208 EfiPciIoAttributeOperationEnable
,
2214 if (Status
== EFI_SUCCESS
) {
2215 Private
->VgaInstalled
= TRUE
;
2218 // Attach the VGA thunk driver.
2219 // Assume the video is installed. This prevents potential of infinite recursion.
2221 Status
= gBS
->ConnectController (
2223 ConnectHandleBuffer
,
2229 FreePool (ConnectHandleBuffer
);
2231 if (EFI_ERROR (Status
)) {
2232 Private
->VgaInstalled
= FALSE
;
2235 // Reconnect the EFI VGA driver.
2237 gBS
->ConnectController (VgaHandle
, NULL
, NULL
, TRUE
);
2238 return EFI_DEVICE_ERROR
;
2245 Load a legacy PC-AT OpROM.
2247 @param This Protocol instance pointer.
2248 @param Private Driver's private data.
2249 @param PciHandle The EFI handle for the PCI device. It could be
2250 NULL if the OpROM image is not associated with
2252 @param OpromRevision The revision of PCI PC-AT ROM image.
2253 @param RomImage Pointer to PCI PC-AT ROM image header. It must not
2255 @param ImageSize Size of the PCI PC-AT ROM image.
2256 @param RuntimeImageLength On input is the max runtime image length indicated by the PCIR structure
2257 On output is the actual runtime image length
2258 @param DiskStart Disk number of first device hooked by the ROM. If
2259 DiskStart is the same as DiskEnd no disked were
2261 @param DiskEnd Disk number of the last device hooked by the ROM.
2262 @param RomShadowAddress Shadow address of PC-AT ROM
2264 @retval EFI_SUCCESS Legacy ROM loaded for this device
2265 @retval EFI_OUT_OF_RESOURCES No more space for this ROM
2270 LegacyBiosInstallRom (
2271 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
2272 IN LEGACY_BIOS_INSTANCE
*Private
,
2273 IN EFI_HANDLE PciHandle
,
2274 IN UINT8 OpromRevision
,
2277 IN OUT UINTN
*RuntimeImageLength
,
2278 OUT UINT8
*DiskStart OPTIONAL
,
2279 OUT UINT8
*DiskEnd OPTIONAL
,
2280 OUT VOID
**RomShadowAddress OPTIONAL
2284 EFI_STATUS PciEnableStatus
;
2285 EFI_PCI_IO_PROTOCOL
*PciIo
;
2286 UINT8 LocalDiskStart
;
2292 EFI_IA32_REGISTER_SET Regs
;
2298 UINT32 StartBbsIndex
;
2303 UINTN RuntimeAddress
;
2304 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
2316 PhysicalAddress
= 0;
2317 MaxRomAddr
= PcdGet32 (PcdEndOpromShadowAddress
);
2319 if ((Private
->Legacy16Table
->TableLength
>= OFFSET_OF (EFI_COMPATIBILITY16_TABLE
, HiPermanentMemoryAddress
)) &&
2320 (Private
->Legacy16Table
->UmaAddress
!= 0) &&
2321 (Private
->Legacy16Table
->UmaSize
!= 0) &&
2322 (MaxRomAddr
> (Private
->Legacy16Table
->UmaAddress
)))
2324 MaxRomAddr
= Private
->Legacy16Table
->UmaAddress
;
2327 PciProgramAllInterruptLineRegisters (Private
);
2329 if ((OpromRevision
>= 3) && (Private
->Csm16PciInterfaceVersion
>= 0x0300)) {
2331 // CSM16 3.0 meets PCI 3.0 OpROM
2332 // first test if there is enough space for its INIT code
2334 PhysicalAddress
= CONVENTIONAL_MEMORY_TOP
;
2335 Status
= gBS
->AllocatePages (
2337 EfiBootServicesCode
,
2338 EFI_SIZE_TO_PAGES (ImageSize
),
2342 if (EFI_ERROR (Status
)) {
2343 DEBUG ((DEBUG_ERROR
, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", DEBUG_LINE_NUMBER
));
2345 // Report Status Code to indicate that there is no enough space for OpROM
2347 REPORT_STATUS_CODE (
2348 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2349 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE
)
2351 return EFI_OUT_OF_RESOURCES
;
2354 InitAddress
= (UINTN
)PhysicalAddress
;
2356 // then test if there is enough space for its RT code
2358 RuntimeAddress
= Private
->OptionRom
;
2359 if (RuntimeAddress
+ *RuntimeImageLength
> MaxRomAddr
) {
2360 DEBUG ((DEBUG_ERROR
, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", DEBUG_LINE_NUMBER
));
2361 gBS
->FreePages (PhysicalAddress
, EFI_SIZE_TO_PAGES (ImageSize
));
2363 // Report Status Code to indicate that there is no enough space for OpROM
2365 REPORT_STATUS_CODE (
2366 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2367 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE
)
2369 return EFI_OUT_OF_RESOURCES
;
2372 // CSM16 3.0 meets PCI 2.x OpROM
2373 // CSM16 2.x meets PCI 2.x/3.0 OpROM
2374 // test if there is enough space for its INIT code
2376 InitAddress
= PCI_START_ADDRESS (Private
->OptionRom
);
2377 if (InitAddress
+ ImageSize
> MaxRomAddr
) {
2378 DEBUG ((DEBUG_ERROR
, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", DEBUG_LINE_NUMBER
));
2380 // Report Status Code to indicate that there is no enough space for OpROM
2382 REPORT_STATUS_CODE (
2383 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2384 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE
)
2386 return EFI_OUT_OF_RESOURCES
;
2389 RuntimeAddress
= InitAddress
;
2392 Private
->LegacyRegion
->UnLock (
2393 Private
->LegacyRegion
,
2399 Private
->LegacyRegion
->UnLock (
2400 Private
->LegacyRegion
,
2401 (UINT32
)RuntimeAddress
,
2406 DEBUG ((DEBUG_INFO
, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress
, RuntimeAddress
, ImageSize
));
2408 CopyMem ((VOID
*)InitAddress
, RomImage
, ImageSize
);
2411 // Read the highest disk number "installed: and assume a new disk will
2412 // show up on the first drive past the current value.
2413 // There are several considerations here:
2414 // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo
2415 // the change until boot selection time frame.
2416 // 2. BBS compliants drives will not change 40:75 until boot time.
2417 // 3. Onboard IDE controllers will change 40:75
2420 LocalDiskStart
= (UINT8
)((*(UINT8
*)((UINTN
)0x475)) + 0x80);
2421 if ((Private
->Disk4075
+ 0x80) < LocalDiskStart
) {
2423 // Update table since onboard IDE drives found
2425 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciSegment
= 0xff;
2426 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciBus
= 0xff;
2427 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciDevice
= 0xff;
2428 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciFunction
= 0xff;
2429 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].StartDriveNumber
= (UINT8
)(Private
->Disk4075
+ 0x80);
2430 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].EndDriveNumber
= LocalDiskStart
;
2431 Private
->LegacyEfiHddTableIndex
++;
2432 Private
->Disk4075
= (UINT8
)(LocalDiskStart
& 0x7f);
2433 Private
->DiskEnd
= LocalDiskStart
;
2436 if (PciHandle
!= mVgaHandle
) {
2437 EnablePs2Keyboard ();
2440 // Store current mode settings since PrepareToScanRom may change mode.
2442 VideoMode
= *(UINT8
*)((UINTN
)(0x400 + BDA_VIDEO_MODE
));
2448 // Notify the platform that we are about to scan the ROM
2450 Status
= Private
->LegacyBiosPlatform
->PlatformHooks (
2451 Private
->LegacyBiosPlatform
,
2452 EfiPlatformHookPrepareToScanRom
,
2461 // If Status returned is EFI_UNSUPPORTED then abort due to platform
2464 if (Status
== EFI_UNSUPPORTED
) {
2469 // Report corresponding status code
2471 REPORT_STATUS_CODE (
2473 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_CSM_LEGACY_ROM_INIT
)
2477 // Generate number of ticks since midnight for BDA. Some OPROMs require
2478 // this. Place result in 40:6C-6F
2480 gRT
->GetTime (&BootTime
, NULL
);
2481 LocalTime
= BootTime
.Hour
* 3600 + BootTime
.Minute
* 60 + BootTime
.Second
;
2484 // Multiply result by 18.2 for number of ticks since midnight.
2485 // Use 182/10 to avoid floating point math.
2488 LocalTime
= (LocalTime
* 182) / 10;
2489 BdaPtr
= (UINT32
*)((UINTN
)0x46C);
2490 *BdaPtr
= LocalTime
;
2494 // Pass in handoff data
2496 PciEnableStatus
= EFI_UNSUPPORTED
;
2497 ZeroMem (&Regs
, sizeof (Regs
));
2498 if (PciHandle
!= NULL
) {
2499 Status
= gBS
->HandleProtocol (
2501 &gEfiPciIoProtocolGuid
,
2504 ASSERT_EFI_ERROR (Status
);
2507 // Enable command register.
2509 PciEnableStatus
= PciIo
->Attributes (
2511 EfiPciIoAttributeOperationEnable
,
2512 EFI_PCI_DEVICE_ENABLE
,
2516 PciIo
->GetLocation (
2523 DEBUG ((DEBUG_INFO
, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus
, Device
, Function
));
2526 mIgnoreBbsUpdateFlag
= FALSE
;
2527 Regs
.X
.AX
= Legacy16DispatchOprom
;
2530 // Generate DispatchOpRomTable data
2532 Private
->IntThunk
->DispatchOpromTable
.PnPInstallationCheckSegment
= Private
->Legacy16Table
->PnPInstallationCheckSegment
;
2533 Private
->IntThunk
->DispatchOpromTable
.PnPInstallationCheckOffset
= Private
->Legacy16Table
->PnPInstallationCheckOffset
;
2534 Private
->IntThunk
->DispatchOpromTable
.OpromSegment
= (UINT16
)(InitAddress
>> 4);
2535 Private
->IntThunk
->DispatchOpromTable
.PciBus
= (UINT8
)Bus
;
2536 Private
->IntThunk
->DispatchOpromTable
.PciDeviceFunction
= (UINT8
)((Device
<< 3) | Function
);
2537 Private
->IntThunk
->DispatchOpromTable
.NumberBbsEntries
= (UINT8
)Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
;
2538 Private
->IntThunk
->DispatchOpromTable
.BbsTablePointer
= (UINT32
)(UINTN
)Private
->BbsTablePtr
;
2539 Private
->IntThunk
->DispatchOpromTable
.RuntimeSegment
= (UINT16
)((OpromRevision
< 3) ? 0xffff : (RuntimeAddress
>> 4));
2540 TempData
= (UINTN
)&Private
->IntThunk
->DispatchOpromTable
;
2541 Regs
.X
.ES
= EFI_SEGMENT ((UINT32
)TempData
);
2542 Regs
.X
.BX
= EFI_OFFSET ((UINT32
)TempData
);
2544 // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes
2545 // Otherwise, it may cause the system to hang in some cases
2547 if (!EFI_ERROR (PciEnableStatus
)) {
2548 DEBUG ((DEBUG_INFO
, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus
, Device
, Function
));
2549 Private
->LegacyBios
.FarCall86 (
2550 &Private
->LegacyBios
,
2551 Private
->Legacy16CallSegment
,
2552 Private
->Legacy16CallOffset
,
2561 if (Private
->IntThunk
->DispatchOpromTable
.NumberBbsEntries
!= (UINT8
)Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
) {
2562 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
= (UINT8
)Private
->IntThunk
->DispatchOpromTable
.NumberBbsEntries
;
2563 mIgnoreBbsUpdateFlag
= TRUE
;
2567 // Check if non-BBS compliant drives found
2569 if (Regs
.X
.BX
!= 0) {
2570 LocalDiskEnd
= (UINT8
)(LocalDiskStart
+ Regs
.H
.BL
);
2571 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciSegment
= (UINT8
)Segment
;
2572 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciBus
= (UINT8
)Bus
;
2573 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciDevice
= (UINT8
)Device
;
2574 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciFunction
= (UINT8
)Function
;
2575 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].StartDriveNumber
= Private
->DiskEnd
;
2576 Private
->DiskEnd
= LocalDiskEnd
;
2577 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].EndDriveNumber
= Private
->DiskEnd
;
2578 Private
->LegacyEfiHddTableIndex
+= 1;
2582 // Skip video mode set, if installing VGA
2584 if (PciHandle
!= mVgaHandle
) {
2586 // Set mode settings since PrepareToScanRom may change mode
2590 OldVideoMode
= *(UINT8
*)((UINTN
)(0x400 + BDA_VIDEO_MODE
));
2594 if (VideoMode
!= OldVideoMode
) {
2596 // The active video mode is changed, restore it to original mode.
2599 Regs
.H
.AL
= VideoMode
;
2600 Private
->LegacyBios
.Int86 (&Private
->LegacyBios
, 0x10, &Regs
);
2605 // Regs.X.AX from the adapter initializion is ignored since some adapters
2606 // do not follow the standard of setting AX = 0 on success.
2609 // The ROM could have updated its size so we need to read again.
2611 if (((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RuntimeAddress
)->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
2613 // Now we check the signature (0xaa55) to judge whether the run-time code is truly generated by INIT function.
2614 // If signature is not valid, that means the INIT function didn't copy the run-time code to RuntimeAddress.
2616 *RuntimeImageLength
= 0;
2618 *RuntimeImageLength
= ((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RuntimeAddress
)->Size512
* 512;
2621 DEBUG ((DEBUG_INFO
, " fsize = %x\n", *RuntimeImageLength
));
2624 // If OpROM runs in 2.0 mode
2626 if (PhysicalAddress
== 0) {
2627 if (*RuntimeImageLength
< ImageSize
) {
2629 // Make area from end of shadowed rom to end of original rom all ffs
2631 gBS
->SetMem ((VOID
*)(InitAddress
+ *RuntimeImageLength
), ImageSize
- *RuntimeImageLength
, 0xff);
2636 LocalDiskEnd
= (UINT8
)((*(UINT8
*)((UINTN
)0x475)) + 0x80);
2640 // Allow platform to perform any required actions after the
2641 // OPROM has been initialized.
2643 Status
= Private
->LegacyBiosPlatform
->PlatformHooks (
2644 Private
->LegacyBiosPlatform
,
2645 EfiPlatformHookAfterRomInit
,
2652 if (PciHandle
!= NULL
) {
2654 // If no PCI Handle then no header or Bevs.
2656 if ((*RuntimeImageLength
!= 0) && (!mIgnoreBbsUpdateFlag
)) {
2657 StartBbsIndex
= Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
;
2658 TempData
= RuntimeAddress
;
2661 (EFI_LEGACY_EXPANSION_ROM_HEADER
*)TempData
,
2664 EndBbsIndex
= Private
->IntThunk
->EfiToLegacy16BootTable
.NumberBbsEntries
;
2665 LocalDiskEnd
= (UINT8
)(LocalDiskStart
+ (UINT8
)(EndBbsIndex
- StartBbsIndex
));
2666 if (LocalDiskEnd
!= LocalDiskStart
) {
2667 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciSegment
= (UINT8
)Segment
;
2668 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciBus
= (UINT8
)Bus
;
2669 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciDevice
= (UINT8
)Device
;
2670 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].PciFunction
= (UINT8
)Function
;
2671 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].StartDriveNumber
= Private
->DiskEnd
;
2672 Private
->DiskEnd
= LocalDiskEnd
;
2673 Private
->LegacyEfiHddTable
[Private
->LegacyEfiHddTableIndex
].EndDriveNumber
= Private
->DiskEnd
;
2674 Private
->LegacyEfiHddTableIndex
+= 1;
2679 // Mark PCI device as having a legacy BIOS ROM loaded.
2683 (UINT32
)RuntimeAddress
,
2684 (UINT32
)*RuntimeImageLength
,
2691 // Stuff caller's OPTIONAL return parameters.
2693 if (RomShadowAddress
!= NULL
) {
2694 *RomShadowAddress
= (VOID
*)RuntimeAddress
;
2697 if (DiskStart
!= NULL
) {
2698 *DiskStart
= LocalDiskStart
;
2701 if (DiskEnd
!= NULL
) {
2702 *DiskEnd
= LocalDiskEnd
;
2705 Private
->OptionRom
= (UINT32
)(RuntimeAddress
+ *RuntimeImageLength
);
2707 Status
= EFI_SUCCESS
;
2710 if (PhysicalAddress
!= 0) {
2712 // Free pages when OpROM is 3.0
2714 gBS
->FreePages (PhysicalAddress
, EFI_SIZE_TO_PAGES (ImageSize
));
2718 // Insure all shadowed areas are locked
2720 Private
->LegacyRegion
->Lock (
2721 Private
->LegacyRegion
,
2731 Let IOMMU grant DMA access for the PCI device.
2733 @param PciHandle The EFI handle for the PCI device.
2734 @param HostAddress The system memory address to map to the PCI controller.
2735 @param NumberOfBytes The number of bytes to map.
2737 @retval EFI_SUCCESS The DMA access is granted.
2741 IN EFI_HANDLE PciHandle
,
2742 IN EFI_PHYSICAL_ADDRESS HostAddress
,
2743 IN UINTN NumberOfBytes
2746 EFI_PHYSICAL_ADDRESS DeviceAddress
;
2750 if (PciHandle
== NULL
) {
2751 return EFI_UNSUPPORTED
;
2754 Status
= EFI_SUCCESS
;
2755 if (mIoMmu
== NULL
) {
2756 gBS
->LocateProtocol (&gEdkiiIoMmuProtocolGuid
, NULL
, (VOID
**)&mIoMmu
);
2759 if (mIoMmu
!= NULL
) {
2760 Status
= mIoMmu
->Map (
2762 EdkiiIoMmuOperationBusMasterCommonBuffer
,
2763 (VOID
*)(UINTN
)HostAddress
,
2768 if (EFI_ERROR (Status
)) {
2769 DEBUG ((DEBUG_ERROR
, "LegacyPci - IoMmuMap - %r\n", Status
));
2771 ASSERT (DeviceAddress
== HostAddress
);
2772 Status
= mIoMmu
->SetAttribute (
2776 EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
2778 if (EFI_ERROR (Status
)) {
2779 DEBUG ((DEBUG_ERROR
, "LegacyPci - IoMmuSetAttribute - %r\n", Status
));
2788 Load a legacy PC-AT OPROM on the PciHandle device. Return information
2789 about how many disks were added by the OPROM and the shadow address and
2790 size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
2792 @param This Protocol instance pointer.
2793 @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
2794 be loaded. This value is NULL if RomImage is
2795 non-NULL. This is the normal case.
2796 @param RomImage A PCI PC-AT ROM image. This argument is non-NULL
2797 if there is no hardware associated with the ROM
2798 and thus no PciHandle, otherwise is must be NULL.
2799 Example is PXE base code.
2800 @param Flags Indicates if ROM found and if PC-AT.
2801 @param DiskStart Disk number of first device hooked by the ROM. If
2802 DiskStart is the same as DiskEnd no disked were
2804 @param DiskEnd Disk number of the last device hooked by the ROM.
2805 @param RomShadowAddress Shadow address of PC-AT ROM
2806 @param RomShadowedSize Size of RomShadowAddress in bytes
2808 @retval EFI_SUCCESS Legacy ROM loaded for this device
2809 @retval EFI_INVALID_PARAMETER PciHandle not found
2810 @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard
2816 LegacyBiosInstallPciRom (
2817 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
2818 IN EFI_HANDLE PciHandle
,
2821 OUT UINT8
*DiskStart OPTIONAL
,
2822 OUT UINT8
*DiskEnd OPTIONAL
,
2823 OUT VOID
**RomShadowAddress OPTIONAL
,
2824 OUT UINT32
*RomShadowedSize OPTIONAL
2828 LEGACY_BIOS_INSTANCE
*Private
;
2829 VOID
*LocalRomImage
;
2831 UINTN RuntimeImageLength
;
2832 EFI_PCI_IO_PROTOCOL
*PciIo
;
2833 PCI_TYPE01 PciConfigHeader
;
2835 EFI_HANDLE
*HandleBuffer
;
2842 UINT8 OpromRevision
;
2844 PCI_3_0_DATA_STRUCTURE
*Pcir
;
2848 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
2849 if (Private
->Legacy16Table
->LastPciBus
== 0) {
2851 // Get last bus number if not already found
2853 Status
= gBS
->LocateHandleBuffer (
2855 &gEfiPciIoProtocolGuid
,
2862 for (Index
= 0; Index
< HandleCount
; Index
++) {
2863 Status
= gBS
->HandleProtocol (
2864 HandleBuffer
[Index
],
2865 &gEfiPciIoProtocolGuid
,
2868 if (EFI_ERROR (Status
)) {
2872 Status
= PciIo
->GetLocation (
2879 if (PciBus
> LastBus
) {
2884 Private
->LegacyRegion
->UnLock (
2885 Private
->LegacyRegion
,
2890 Private
->Legacy16Table
->LastPciBus
= (UINT8
)LastBus
;
2891 Private
->LegacyRegion
->Lock (
2892 Private
->LegacyRegion
,
2900 if ((PciHandle
!= NULL
) && (RomImage
== NULL
)) {
2902 // If PciHandle has OpRom to Execute
2903 // and OpRom are all associated with Hardware
2905 Status
= gBS
->HandleProtocol (
2907 &gEfiPciIoProtocolGuid
,
2911 if (!EFI_ERROR (Status
)) {
2914 EfiPciIoWidthUint32
,
2916 sizeof (PciConfigHeader
) / sizeof (UINT32
),
2921 // if video installed & OPROM is video return
2925 ((PciConfigHeader
.Hdr
.ClassCode
[2] == PCI_CLASS_OLD
) &&
2926 (PciConfigHeader
.Hdr
.ClassCode
[1] == PCI_CLASS_OLD_VGA
))
2928 ((PciConfigHeader
.Hdr
.ClassCode
[2] == PCI_CLASS_DISPLAY
) &&
2929 (PciConfigHeader
.Hdr
.ClassCode
[1] == PCI_CLASS_DISPLAY_VGA
))
2932 (!Private
->VgaInstalled
)
2935 mVgaInstallationInProgress
= TRUE
;
2938 // return EFI_UNSUPPORTED;
2944 // To run any legacy image, the VGA needs to be installed first.
2945 // if installing the video, then don't need the thunk as already installed.
2947 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
2948 Private
->LegacyBiosPlatform
,
2949 EfiGetPlatformVgaHandle
,
2956 if (!EFI_ERROR (Status
)) {
2957 mVgaHandle
= HandleBuffer
[0];
2958 if ((!Private
->VgaInstalled
) && (PciHandle
!= mVgaHandle
)) {
2960 // A return status of EFI_NOT_FOUND is considered valid (No EFI
2961 // driver is controlling video.
2963 mVgaInstallationInProgress
= TRUE
;
2964 Status
= LegacyBiosInstallVgaRom (Private
);
2965 if (EFI_ERROR (Status
)) {
2966 if (Status
!= EFI_NOT_FOUND
) {
2967 mVgaInstallationInProgress
= FALSE
;
2971 mVgaInstallationInProgress
= FALSE
;
2977 // See if the option ROM for PciHandle has already been executed
2979 Status
= IsLegacyRom (PciHandle
);
2981 if (!EFI_ERROR (Status
)) {
2982 mVgaInstallationInProgress
= FALSE
;
2983 GetShadowedRomParameters (
2988 (UINTN
*)RomShadowedSize
2993 Status
= LegacyBiosCheckPciRomEx (
2994 &Private
->LegacyBios
,
2998 &RuntimeImageLength
,
3003 if (EFI_ERROR (Status
)) {
3005 // There is no PCI ROM in the ROM BAR or no onboard ROM
3007 mVgaInstallationInProgress
= FALSE
;
3008 return EFI_UNSUPPORTED
;
3011 if ((RomImage
== NULL
) || (*RomImage
== NULL
)) {
3013 // If PciHandle is NULL, and no OpRom is to be associated
3015 mVgaInstallationInProgress
= FALSE
;
3016 return EFI_UNSUPPORTED
;
3019 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
3020 Private
->LegacyBiosPlatform
,
3021 EfiGetPlatformVgaHandle
,
3027 if ((!EFI_ERROR (Status
)) && (!Private
->VgaInstalled
)) {
3029 // A return status of EFI_NOT_FOUND is considered valid (No EFI
3030 // driver is controlling video.
3032 mVgaInstallationInProgress
= TRUE
;
3033 Status
= LegacyBiosInstallVgaRom (Private
);
3034 if (EFI_ERROR (Status
)) {
3035 if (Status
!= EFI_NOT_FOUND
) {
3036 mVgaInstallationInProgress
= FALSE
;
3040 mVgaInstallationInProgress
= FALSE
;
3044 LocalRomImage
= *RomImage
;
3045 if ((((PCI_EXPANSION_ROM_HEADER
*)LocalRomImage
)->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) ||
3046 (((PCI_EXPANSION_ROM_HEADER
*)LocalRomImage
)->PcirOffset
== 0) ||
3047 ((((PCI_EXPANSION_ROM_HEADER
*)LocalRomImage
)->PcirOffset
& 3) != 0))
3049 mVgaInstallationInProgress
= FALSE
;
3050 return EFI_UNSUPPORTED
;
3053 Pcir
= (PCI_3_0_DATA_STRUCTURE
*)
3054 ((UINT8
*)LocalRomImage
+ ((PCI_EXPANSION_ROM_HEADER
*)LocalRomImage
)->PcirOffset
);
3056 if ((Pcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) || (Pcir
->CodeType
!= PCI_CODE_TYPE_PCAT_IMAGE
)) {
3057 mVgaInstallationInProgress
= FALSE
;
3058 return EFI_UNSUPPORTED
;
3061 ImageSize
= Pcir
->ImageLength
* 512;
3062 if (Pcir
->Length
>= 0x1C) {
3063 OpromRevision
= Pcir
->Revision
;
3068 if (Pcir
->Revision
< 3) {
3069 RuntimeImageLength
= 0;
3071 RuntimeImageLength
= Pcir
->MaxRuntimeImageLength
* 512;
3076 // Grant access for below 1M
3077 // BDA/EBDA/LowPMM and scratch memory for OPROM.
3079 IoMmuGrantAccess (PciHandle
, 0, SIZE_1MB
);
3081 // Grant access for HiPmm
3085 Private
->IntThunk
->EfiToLegacy16InitTable
.HiPmmMemory
,
3086 Private
->IntThunk
->EfiToLegacy16InitTable
.HiPmmMemorySizeInBytes
3090 // Shadow and initialize the OpROM.
3092 ASSERT (Private
->TraceIndex
< 0x200);
3093 Private
->Trace
[Private
->TraceIndex
] = LEGACY_PCI_TRACE_000
;
3094 Private
->TraceIndex
++;
3095 Private
->TraceIndex
= (UINT16
)(Private
->TraceIndex
% 0x200);
3096 Status
= LegacyBiosInstallRom (
3103 &RuntimeImageLength
,
3108 if (RomShadowedSize
!= NULL
) {
3109 *RomShadowedSize
= (UINT32
)RuntimeImageLength
;
3112 mVgaInstallationInProgress
= FALSE
;