+++ /dev/null
-/** @file\r
-\r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "LegacyBiosInterface.h"\r
-#include <IndustryStandard/Pci30.h>\r
-\r
-#define PCI_START_ADDRESS(x) (((x) + 0x7ff) & ~0x7ff)\r
-\r
-#define MAX_BRIDGE_INDEX 0x20\r
-typedef struct {\r
- UINTN PciSegment;\r
- UINTN PciBus;\r
- UINTN PciDevice;\r
- UINTN PciFunction;\r
- UINT8 PrimaryBus;\r
- UINT8 SecondaryBus;\r
- UINT8 SubordinateBus;\r
-} BRIDGE_TABLE;\r
-\r
-#define ROM_MAX_ENTRIES 24\r
-BRIDGE_TABLE Bridges[MAX_BRIDGE_INDEX];\r
-UINTN SortedBridgeIndex[MAX_BRIDGE_INDEX];\r
-UINTN NumberOfBridges;\r
-LEGACY_PNP_EXPANSION_HEADER *mBasePnpPtr;\r
-UINT16 mBbsRomSegment;\r
-UINTN mHandleCount;\r
-EFI_HANDLE mVgaHandle;\r
-BOOLEAN mIgnoreBbsUpdateFlag;\r
-BOOLEAN mVgaInstallationInProgress = FALSE;\r
-UINT32 mRomCount = 0x00;\r
-ROM_INSTANCE_ENTRY mRomEntry[ROM_MAX_ENTRIES];\r
-EDKII_IOMMU_PROTOCOL *mIoMmu;\r
-\r
-/**\r
- Query shadowed legacy ROM parameters registered by RomShadow() previously.\r
-\r
- @param PciHandle PCI device whos ROM has been shadowed\r
- @param DiskStart DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
- @param DiskEnd DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
- @param RomShadowAddress Address where ROM was shadowed\r
- @param ShadowedSize Runtime size of ROM\r
-\r
- @retval EFI_SUCCESS Query Logging successful.\r
- @retval EFI_NOT_FOUND No logged data found about PciHandle.\r
-\r
-**/\r
-EFI_STATUS\r
-GetShadowedRomParameters (\r
- IN EFI_HANDLE PciHandle,\r
- OUT UINT8 *DiskStart, OPTIONAL\r
- OUT UINT8 *DiskEnd, OPTIONAL\r
- OUT VOID **RomShadowAddress, OPTIONAL\r
- OUT UINTN *ShadowedSize OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- UINTN Index;\r
- UINTN PciSegment;\r
- UINTN PciBus;\r
- UINTN PciDevice;\r
- UINTN PciFunction;\r
-\r
- //\r
- // Get the PCI I/O Protocol on PciHandle\r
- //\r
- Status = gBS->HandleProtocol (\r
- PciHandle,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Get the location of the PCI device\r
- //\r
- PciIo->GetLocation (\r
- PciIo,\r
- &PciSegment,\r
- &PciBus,\r
- &PciDevice,\r
- &PciFunction\r
- );\r
-\r
- for(Index = 0; Index < mRomCount; Index++) {\r
- if ((mRomEntry[Index].PciSegment == PciSegment) &&\r
- (mRomEntry[Index].PciBus == PciBus) &&\r
- (mRomEntry[Index].PciDevice == PciDevice) &&\r
- (mRomEntry[Index].PciFunction == PciFunction)) {\r
- break;\r
- }\r
- }\r
-\r
- if (Index == mRomCount) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- if (DiskStart != NULL) {\r
- *DiskStart = mRomEntry[Index].DiskStart;\r
- }\r
-\r
- if (DiskEnd != NULL) {\r
- *DiskEnd = mRomEntry[Index].DiskEnd;\r
- }\r
-\r
- if (RomShadowAddress != NULL) {\r
- *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress;\r
- }\r
-\r
- if (ShadowedSize != NULL) {\r
- *ShadowedSize = mRomEntry[Index].ShadowedSize;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Every legacy ROM that is shadowed by the Legacy BIOS driver will be\r
- registered into this API so that the policy code can know what has\r
- happend\r
-\r
- @param PciHandle PCI device whos ROM is being shadowed\r
- @param ShadowAddress Address that ROM was shadowed\r
- @param ShadowedSize Runtime size of ROM\r
- @param DiskStart DiskStart value from\r
- EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
- @param DiskEnd DiskEnd value from\r
- EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
-\r
- @retval EFI_SUCCESS Logging successful.\r
- @retval EFI_OUT_OF_RESOURCES No remaining room for registering another option\r
- ROM.\r
-\r
-**/\r
-EFI_STATUS\r
-RomShadow (\r
- IN EFI_HANDLE PciHandle,\r
- IN UINT32 ShadowAddress,\r
- IN UINT32 ShadowedSize,\r
- IN UINT8 DiskStart,\r
- IN UINT8 DiskEnd\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
-\r
- //\r
- // See if there is room to register another option ROM\r
- //\r
- if (mRomCount >= ROM_MAX_ENTRIES) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- //\r
- // Get the PCI I/O Protocol on PciHandle\r
- //\r
- Status = gBS->HandleProtocol (\r
- PciHandle,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Get the location of the PCI device\r
- //\r
- PciIo->GetLocation (\r
- PciIo,\r
- &mRomEntry[mRomCount].PciSegment,\r
- &mRomEntry[mRomCount].PciBus,\r
- &mRomEntry[mRomCount].PciDevice,\r
- &mRomEntry[mRomCount].PciFunction\r
- );\r
- mRomEntry[mRomCount].ShadowAddress = ShadowAddress;\r
- mRomEntry[mRomCount].ShadowedSize = ShadowedSize;\r
- mRomEntry[mRomCount].DiskStart = DiskStart;\r
- mRomEntry[mRomCount].DiskEnd = DiskEnd;\r
-\r
- mRomCount++;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This\r
- information represents every call to RomShadow ()\r
-\r
- @param PciHandle PCI device to get status for\r
-\r
- @retval EFI_SUCCESS Legacy ROM loaded for this device\r
- @retval EFI_NOT_FOUND No Legacy ROM loaded for this device\r
-\r
-**/\r
-EFI_STATUS\r
-IsLegacyRom (\r
- IN EFI_HANDLE PciHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- UINTN Index;\r
- UINTN Segment;\r
- UINTN Bus;\r
- UINTN Device;\r
- UINTN Function;\r
-\r
- //\r
- // Get the PCI I/O Protocol on PciHandle\r
- //\r
- Status = gBS->HandleProtocol (\r
- PciHandle,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Get the location of the PCI device\r
- //\r
- PciIo->GetLocation (\r
- PciIo,\r
- &Segment,\r
- &Bus,\r
- &Device,\r
- &Function\r
- );\r
-\r
- //\r
- // See if the option ROM from PciHandle has been previously posted\r
- //\r
- for (Index = 0; Index < mRomCount; Index++) {\r
- if (mRomEntry[Index].PciSegment == Segment &&\r
- mRomEntry[Index].PciBus == Bus &&\r
- mRomEntry[Index].PciDevice == Device &&\r
- mRomEntry[Index].PciFunction == Function\r
- ) {\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the\r
- related information from the header.\r
-\r
- @param Csm16Revision The PCI interface version of underlying CSM16\r
- @param VendorId Vendor ID of the PCI device\r
- @param DeviceId Device ID of the PCI device\r
- @param Rom On input pointing to beginning of the raw PCI OpROM\r
- On output pointing to the first legacy PCI OpROM\r
- @param ImageSize On input is the size of Raw PCI Rom\r
- On output is the size of the first legacy PCI ROM\r
- @param MaxRuntimeImageLength The max runtime image length only valid if OpRomRevision >= 3\r
- @param OpRomRevision Revision of the PCI Rom\r
- @param ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header\r
-\r
- @retval EFI_SUCCESS Successfully find the legacy PCI ROM\r
- @retval EFI_NOT_FOUND Failed to find the legacy PCI ROM\r
-\r
-**/\r
-EFI_STATUS\r
-GetPciLegacyRom (\r
- IN UINT16 Csm16Revision,\r
- IN UINT16 VendorId,\r
- IN UINT16 DeviceId,\r
- IN OUT VOID **Rom,\r
- IN OUT UINTN *ImageSize,\r
- OUT UINTN *MaxRuntimeImageLength, OPTIONAL\r
- OUT UINT8 *OpRomRevision, OPTIONAL\r
- OUT VOID **ConfigUtilityCodeHeader OPTIONAL\r
- )\r
-{\r
- BOOLEAN Match;\r
- UINT16 *DeviceIdList;\r
- EFI_PCI_ROM_HEADER RomHeader;\r
- PCI_3_0_DATA_STRUCTURE *Pcir;\r
- VOID *BackupImage;\r
- VOID *BestImage;\r
-\r
-\r
- if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- BestImage = NULL;\r
- BackupImage = NULL;\r
- RomHeader.Raw = *Rom;\r
- while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
- if (RomHeader.Generic->PcirOffset == 0 ||\r
- (RomHeader.Generic->PcirOffset & 3) !=0 ||\r
- *ImageSize < RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)) {\r
- break;\r
- }\r
-\r
- Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);\r
- //\r
- // Check signature in the PCI Data Structure.\r
- //\r
- if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
- break;\r
- }\r
-\r
- if (((UINTN)RomHeader.Raw - (UINTN)*Rom) + Pcir->ImageLength * 512 > *ImageSize) {\r
- break;\r
- }\r
-\r
- if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
- Match = FALSE;\r
- if (Pcir->VendorId == VendorId) {\r
- if (Pcir->DeviceId == DeviceId) {\r
- Match = TRUE;\r
- } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) {\r
- DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset);\r
- //\r
- // Checking the device list\r
- //\r
- while (*DeviceIdList != 0) {\r
- if (*DeviceIdList == DeviceId) {\r
- Match = TRUE;\r
- break;\r
- }\r
- DeviceIdList ++;\r
- }\r
- }\r
- }\r
-\r
- if (Match) {\r
- if (Csm16Revision >= 0x0300) {\r
- //\r
- // Case 1: CSM16 3.0\r
- //\r
- if (Pcir->Revision >= 3) {\r
- //\r
- // case 1.1: meets OpRom 3.0\r
- // Perfect!!!\r
- //\r
- BestImage = RomHeader.Raw;\r
- break;\r
- } else {\r
- //\r
- // case 1.2: meets OpRom 2.x\r
- // Store it and try to find the OpRom 3.0\r
- //\r
- BackupImage = RomHeader.Raw;\r
- }\r
- } else {\r
- //\r
- // Case 2: CSM16 2.x\r
- //\r
- if (Pcir->Revision >= 3) {\r
- //\r
- // case 2.1: meets OpRom 3.0\r
- // Store it and try to find the OpRom 2.x\r
- //\r
- BackupImage = RomHeader.Raw;\r
- } else {\r
- //\r
- // case 2.2: meets OpRom 2.x\r
- // Perfect!!!\r
- //\r
- BestImage = RomHeader.Raw;\r
- break;\r
- }\r
- }\r
- } else {\r
- DEBUG ((EFI_D_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId));\r
- }\r
- }\r
-\r
- if ((Pcir->Indicator & 0x80) == 0x80) {\r
- break;\r
- } else {\r
- RomHeader.Raw += 512 * Pcir->ImageLength;\r
- }\r
- }\r
-\r
- if (BestImage == NULL) {\r
- if (BackupImage == NULL) {\r
- return EFI_NOT_FOUND;\r
- }\r
- //\r
- // The versions of CSM16 and OpRom don't match exactly\r
- //\r
- BestImage = BackupImage;\r
- }\r
- RomHeader.Raw = BestImage;\r
- Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);\r
- *Rom = BestImage;\r
- *ImageSize = Pcir->ImageLength * 512;\r
-\r
- if (MaxRuntimeImageLength != NULL) {\r
- if (Pcir->Revision < 3) {\r
- *MaxRuntimeImageLength = 0;\r
- } else {\r
- *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;\r
- }\r
- }\r
-\r
- if (OpRomRevision != NULL) {\r
- //\r
- // Optional return PCI Data Structure revision\r
- //\r
- if (Pcir->Length >= 0x1C) {\r
- *OpRomRevision = Pcir->Revision;\r
- } else {\r
- *OpRomRevision = 0;\r
- }\r
- }\r
-\r
- if (ConfigUtilityCodeHeader != NULL) {\r
- //\r
- // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM\r
- //\r
- if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) {\r
- *ConfigUtilityCodeHeader = NULL;\r
- } else {\r
- *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset;\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Build a table of bridge info for PIRQ translation.\r
-\r
- @param RoutingTable RoutingTable obtained from Platform.\r
- @param RoutingTableEntries Number of RoutingTable entries.\r
-\r
- @retval EFI_SUCCESS New Subordinate bus.\r
- @retval EFI_NOT_FOUND No more Subordinate busses.\r
-\r
-**/\r
-EFI_STATUS\r
-CreateBridgeTable (\r
- IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,\r
- IN UINTN RoutingTableEntries\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN HandleCount;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN BridgeIndex;\r
- UINTN Index;\r
- UINTN Index1;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- PCI_TYPE01 PciConfigHeader;\r
- BRIDGE_TABLE SlotBridges[MAX_BRIDGE_INDEX];\r
- UINTN SlotBridgeIndex;\r
-\r
- BridgeIndex = 0x00;\r
- SlotBridgeIndex = 0x00;\r
-\r
- //\r
- // Assumption is table is built from low bus to high bus numbers.\r
- //\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiPciIoProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_NOT_FOUND;\r
- }\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
-\r
- PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- 0,\r
- sizeof (PciConfigHeader) / sizeof (UINT32),\r
- &PciConfigHeader\r
- );\r
-\r
- if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) {\r
- PciIo->GetLocation (\r
- PciIo,\r
- &Bridges[BridgeIndex].PciSegment,\r
- &Bridges[BridgeIndex].PciBus,\r
- &Bridges[BridgeIndex].PciDevice,\r
- &Bridges[BridgeIndex].PciFunction\r
- );\r
-\r
- Bridges[BridgeIndex].PrimaryBus = PciConfigHeader.Bridge.PrimaryBus;\r
-\r
- Bridges[BridgeIndex].SecondaryBus = PciConfigHeader.Bridge.SecondaryBus;\r
-\r
- Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus;\r
-\r
- for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){\r
- //\r
- // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board\r
- // Once we find one, store it in the SlotBridges[]\r
- //\r
- if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus)\r
- && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) {\r
- CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE));\r
- SlotBridgeIndex++;\r
-\r
- break;\r
- }\r
- }\r
-\r
- ++BridgeIndex;\r
- }\r
- }\r
-\r
- //\r
- // Pack up Bridges by removing those useless ones\r
- //\r
- for (Index = 0; Index < BridgeIndex;){\r
- for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) {\r
- if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) ||\r
- ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) {\r
- //\r
- // We have found one that meets our criteria\r
- //\r
- Index++;\r
- break;\r
- }\r
- }\r
-\r
- //\r
- // This one doesn't meet criteria, pack it\r
- //\r
- if (Index1 >= SlotBridgeIndex) {\r
- for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) {\r
- CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE));\r
- }\r
-\r
- BridgeIndex--;\r
- }\r
- }\r
-\r
- NumberOfBridges = BridgeIndex;\r
-\r
- //\r
- // Sort bridges low to high by Secondary bus followed by subordinate bus\r
- //\r
- if (NumberOfBridges > 1) {\r
- Index = 0;\r
- do {\r
- SortedBridgeIndex[Index] = Index;\r
- ++Index;\r
- } while (Index < NumberOfBridges);\r
-\r
- for (Index = 0; Index < NumberOfBridges - 1; Index++) {\r
- for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) {\r
- if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) {\r
- SortedBridgeIndex[Index] = Index1;\r
- SortedBridgeIndex[Index1] = Index;\r
- }\r
-\r
- if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) &&\r
- (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus)\r
- ) {\r
- SortedBridgeIndex[Index] = Index1;\r
- SortedBridgeIndex[Index1] = Index;\r
- }\r
- }\r
- }\r
- }\r
- FreePool (HandleBuffer);\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Find base Bridge for device.\r
-\r
- @param Private Legacy BIOS Instance data\r
- @param PciBus Input = Bus of device.\r
- @param PciDevice Input = Device.\r
- @param RoutingTable The platform specific routing table\r
- @param RoutingTableEntries Number of entries in table\r
-\r
- @retval EFI_SUCCESS At base bus.\r
- @retval EFI_NOT_FOUND Behind a bridge.\r
-\r
-**/\r
-EFI_STATUS\r
-GetBaseBus (\r
- IN LEGACY_BIOS_INSTANCE *Private,\r
- IN UINTN PciBus,\r
- IN UINTN PciDevice,\r
- IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,\r
- IN UINTN RoutingTableEntries\r
- )\r
-{\r
- UINTN Index;\r
- for (Index = 0; Index < RoutingTableEntries; Index++) {\r
- if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) {\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- Translate PIRQ through busses\r
-\r
- @param Private Legacy BIOS Instance data\r
- @param PciBus Input = Bus of device. Output = Translated Bus\r
- @param PciDevice Input = Device. Output = Translated Device\r
- @param PciFunction Input = Function. Output = Translated Function\r
- @param PirqIndex Input = Original PIRQ index. If single function\r
- device then 0, otherwise 0-3.\r
- Output = Translated Index\r
-\r
- @retval EFI_SUCCESS Pirq successfully translated.\r
- @retval EFI_NOT_FOUND The device is not behind any known bridge.\r
-\r
-**/\r
-EFI_STATUS\r
-TranslateBusPirq (\r
- IN LEGACY_BIOS_INSTANCE *Private,\r
- IN OUT UINTN *PciBus,\r
- IN OUT UINTN *PciDevice,\r
- IN OUT UINTN *PciFunction,\r
- IN OUT UINT8 *PirqIndex\r
- )\r
-{\r
- /*\r
- This routine traverses the PCI busses from base slot\r
- and translates the PIRQ register to the appropriate one.\r
-\r
- Example:\r
-\r
- Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.\r
- Primary bus# = 0\r
- Secondary bus # = 1\r
- Subordinate bus # is highest bus # behind this bus\r
- Bus 1, Device 0 is Slot 0 and is not a bridge.\r
- Bus 1, Device 1 is Slot 1 and is a bridge.\r
- Slot PIRQ routing is A,B,C,D.\r
- Primary bus # = 1\r
- Secondary bus # = 2\r
- Subordinate bus # = 5\r
- Bus 2, Device 6 is a bridge. It has no bridges behind it.\r
- Primary bus # = 2\r
- Secondary bus # = 3\r
- Subordinate bus # = 3\r
- Bridge PIRQ routing is C,D,A,B\r
- Bus 2, Device 7 is a bridge. It has 1 bridge behind it.\r
- Primary bus # = 2\r
- Secondary bus = 4 Device 6 takes bus 2.\r
- Subordinate bus = 5.\r
- Bridge PIRQ routing is D,A,B,C\r
- Bus 4, Device 2 is a bridge. It has no bridges behind it.\r
- Primary bus # = 4\r
- Secondary bus # = 5\r
- Subordinate bus = 5\r
- Bridge PIRQ routing is B,C,D,A\r
- Bus 5, Device 1 is to be programmed.\r
- Device PIRQ routing is C,D,A,B\r
-\r
-\r
-Search busses starting from slot bus for final bus >= Secondary bus and\r
-final bus <= Suborninate bus. Assumption is bus entries increase in bus\r
-number.\r
-Starting PIRQ is A,B,C,D.\r
-Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device\r
- 7 modulo 4 giving (D,A,B,C).\r
-Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving\r
- (B,C,D,A).\r
-No other busses match criteria. Device to be programmed is Bus 5, Device 1.\r
-Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.\r
-\r
-*/\r
- UINTN LocalBus;\r
- UINTN LocalDevice;\r
- UINTN BaseBus;\r
- UINTN BaseDevice;\r
- UINTN BaseFunction;\r
- UINT8 LocalPirqIndex;\r
- BOOLEAN BaseIndexFlag;\r
- UINTN BridgeIndex;\r
- UINTN SBridgeIndex;\r
- BaseIndexFlag = FALSE;\r
- BridgeIndex = 0x00;\r
-\r
- LocalPirqIndex = *PirqIndex;\r
- LocalBus = *PciBus;\r
- LocalDevice = *PciDevice;\r
- BaseBus = *PciBus;\r
- BaseDevice = *PciDevice;\r
- BaseFunction = *PciFunction;\r
-\r
- //\r
- // LocalPirqIndex list PIRQs in rotated fashion\r
- // = 0 A,B,C,D\r
- // = 1 B,C,D,A\r
- // = 2 C,D,A,B\r
- // = 3 D,A,B,C\r
- //\r
-\r
- for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) {\r
- SBridgeIndex = SortedBridgeIndex[BridgeIndex];\r
- //\r
- // Check if device behind this bridge\r
- //\r
- if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) {\r
- //\r
- // If BaseIndexFlag = FALSE then have found base bridge, i.e\r
- // bridge in slot. Save info for use by IRQ routing table.\r
- //\r
- if (!BaseIndexFlag) {\r
- BaseBus = Bridges[SBridgeIndex].PciBus;\r
- BaseDevice = Bridges[SBridgeIndex].PciDevice;\r
- BaseFunction = Bridges[SBridgeIndex].PciFunction;\r
- BaseIndexFlag = TRUE;\r
- } else {\r
- LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4);\r
- }\r
-\r
- //\r
- // Check if at device. If not get new PCI location & PIRQ\r
- //\r
- if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) {\r
- //\r
- // Translate PIRQ\r
- //\r
- LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4);\r
- break;\r
- }\r
- }\r
- }\r
-\r
- //\r
- // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user\r
- //\r
- if(BridgeIndex >= NumberOfBridges){\r
- DEBUG ((EFI_D_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction));\r
- }\r
-\r
- *PirqIndex = LocalPirqIndex;\r
- *PciBus = BaseBus;\r
- *PciDevice = BaseDevice;\r
- *PciFunction = BaseFunction;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Copy the $PIR table as required.\r
-\r
- @param Private Legacy BIOS Instance data\r
- @param RoutingTable Pointer to IRQ routing table\r
- @param RoutingTableEntries IRQ routing table entries\r
- @param PirqTable Pointer to $PIR table\r
- @param PirqTableSize Length of table\r
-\r
-**/\r
-VOID\r
-CopyPirqTable (\r
- IN LEGACY_BIOS_INSTANCE *Private,\r
- IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,\r
- IN UINTN RoutingTableEntries,\r
- IN EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable,\r
- IN UINTN PirqTableSize\r
- )\r
-{\r
- EFI_IA32_REGISTER_SET Regs;\r
- UINT32 Granularity;\r
-\r
- //\r
- // Copy $PIR table, if it exists.\r
- //\r
- if (PirqTable != NULL) {\r
- Private->LegacyRegion->UnLock (\r
- Private->LegacyRegion,\r
- 0xE0000,\r
- 0x20000,\r
- &Granularity\r
- );\r
-\r
- Private->InternalIrqRoutingTable = RoutingTable;\r
- Private->NumberIrqRoutingEntries = (UINT16) (RoutingTableEntries);\r
- ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
-\r
- Regs.X.AX = Legacy16GetTableAddress;\r
- Regs.X.CX = (UINT16) PirqTableSize;\r
- //\r
- // Allocate at F segment according to PCI IRQ Routing Table Specification\r
- //\r
- Regs.X.BX = (UINT16) 0x1;\r
- //\r
- // 16-byte boundary alignment requirement according to\r
- // PCI IRQ Routing Table Specification\r
- //\r
- Regs.X.DX = 0x10;\r
- Private->LegacyBios.FarCall86 (\r
- &Private->LegacyBios,\r
- Private->Legacy16CallSegment,\r
- Private->Legacy16CallOffset,\r
- &Regs,\r
- NULL,\r
- 0\r
- );\r
-\r
- Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
- if (Regs.X.AX != 0) {\r
- DEBUG ((EFI_D_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize));\r
- } else {\r
- DEBUG ((EFI_D_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer));\r
- Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize;\r
- CopyMem (\r
- (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer,\r
- PirqTable,\r
- PirqTableSize\r
- );\r
- }\r
-\r
- Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
- Private->LegacyRegion->Lock (\r
- Private->LegacyRegion,\r
- 0xE0000,\r
- 0x20000,\r
- &Granularity\r
- );\r
- }\r
-\r
- Private->PciInterruptLine = TRUE;\r
- mHandleCount = 0;\r
-}\r
-\r
-/**\r
- Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.\r
-\r
- @param PciHandle The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure\r
-\r
-**/\r
-VOID\r
-DumpPciHandle (\r
- IN EFI_LEGACY_INSTALL_PCI_HANDLER *PciHandle\r
- )\r
-{\r
- DEBUG ((EFI_D_INFO, "PciBus - %02x\n", (UINTN)PciHandle->PciBus));\r
- DEBUG ((EFI_D_INFO, "PciDeviceFun - %02x\n", (UINTN)PciHandle->PciDeviceFun));\r
- DEBUG ((EFI_D_INFO, "PciSegment - %02x\n", (UINTN)PciHandle->PciSegment));\r
- DEBUG ((EFI_D_INFO, "PciClass - %02x\n", (UINTN)PciHandle->PciClass));\r
- DEBUG ((EFI_D_INFO, "PciSubclass - %02x\n", (UINTN)PciHandle->PciSubclass));\r
- DEBUG ((EFI_D_INFO, "PciInterface - %02x\n", (UINTN)PciHandle->PciInterface));\r
-\r
- DEBUG ((EFI_D_INFO, "PrimaryIrq - %02x\n", (UINTN)PciHandle->PrimaryIrq));\r
- DEBUG ((EFI_D_INFO, "PrimaryReserved - %02x\n", (UINTN)PciHandle->PrimaryReserved));\r
- DEBUG ((EFI_D_INFO, "PrimaryControl - %04x\n", (UINTN)PciHandle->PrimaryControl));\r
- DEBUG ((EFI_D_INFO, "PrimaryBase - %04x\n", (UINTN)PciHandle->PrimaryBase));\r
- DEBUG ((EFI_D_INFO, "PrimaryBusMaster - %04x\n", (UINTN)PciHandle->PrimaryBusMaster));\r
-\r
- DEBUG ((EFI_D_INFO, "SecondaryIrq - %02x\n", (UINTN)PciHandle->SecondaryIrq));\r
- DEBUG ((EFI_D_INFO, "SecondaryReserved - %02x\n", (UINTN)PciHandle->SecondaryReserved));\r
- DEBUG ((EFI_D_INFO, "SecondaryControl - %04x\n", (UINTN)PciHandle->SecondaryControl));\r
- DEBUG ((EFI_D_INFO, "SecondaryBase - %04x\n", (UINTN)PciHandle->SecondaryBase));\r
- DEBUG ((EFI_D_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster));\r
- return;\r
-}\r
-\r
-/**\r
- Copy the $PIR table as required.\r
-\r
- @param Private Legacy BIOS Instance data\r
- @param PciIo Pointer to PCI_IO protocol\r
- @param PciIrq Pci IRQ number\r
- @param PciConfigHeader Type00 Pci configuration header\r
-\r
-**/\r
-VOID\r
-InstallLegacyIrqHandler (\r
- IN LEGACY_BIOS_INSTANCE *Private,\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT8 PciIrq,\r
- IN PCI_TYPE00 *PciConfigHeader\r
- )\r
-{\r
- EFI_IA32_REGISTER_SET Regs;\r
- UINT16 LegMask;\r
- UINTN PciSegment;\r
- UINTN PciBus;\r
- UINTN PciDevice;\r
- UINTN PciFunction;\r
- EFI_LEGACY_8259_PROTOCOL *Legacy8259;\r
- UINT16 PrimaryMaster;\r
- UINT16 SecondaryMaster;\r
- UINTN TempData;\r
- UINTN RegisterAddress;\r
- UINT32 Granularity;\r
-\r
- PrimaryMaster = 0;\r
- SecondaryMaster = 0;\r
- Legacy8259 = Private->Legacy8259;\r
- //\r
- // Disable interrupt in PIC, in case shared, to prevent an\r
- // interrupt from occuring.\r
- //\r
- Legacy8259->GetMask (\r
- Legacy8259,\r
- &LegMask,\r
- NULL,\r
- NULL,\r
- NULL\r
- );\r
-\r
- LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq));\r
-\r
- Legacy8259->SetMask (\r
- Legacy8259,\r
- &LegMask,\r
- NULL,\r
- NULL,\r
- NULL\r
- );\r
-\r
- PciIo->GetLocation (\r
- PciIo,\r
- &PciSegment,\r
- &PciBus,\r
- &PciDevice,\r
- &PciFunction\r
- );\r
- Private->IntThunk->PciHandler.PciBus = (UINT8) PciBus;\r
- Private->IntThunk->PciHandler.PciDeviceFun = (UINT8) ((PciDevice << 3) + PciFunction);\r
- Private->IntThunk->PciHandler.PciSegment = (UINT8) PciSegment;\r
- Private->IntThunk->PciHandler.PciClass = PciConfigHeader->Hdr.ClassCode[2];\r
- Private->IntThunk->PciHandler.PciSubclass = PciConfigHeader->Hdr.ClassCode[1];\r
- Private->IntThunk->PciHandler.PciInterface = PciConfigHeader->Hdr.ClassCode[0];\r
-\r
- //\r
- // Use native mode base address registers in two cases:\r
- // 1. Programming Interface (PI) register indicates Primary Controller is\r
- // in native mode OR\r
- // 2. PCI device Sub Class Code is not IDE\r
- //\r
- Private->IntThunk->PciHandler.PrimaryBusMaster = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc);\r
- if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {\r
- Private->IntThunk->PciHandler.PrimaryIrq = PciIrq;\r
- Private->IntThunk->PciHandler.PrimaryBase = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc);\r
- Private->IntThunk->PciHandler.PrimaryControl = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2);\r
- } else {\r
- Private->IntThunk->PciHandler.PrimaryIrq = 14;\r
- Private->IntThunk->PciHandler.PrimaryBase = 0x1f0;\r
- Private->IntThunk->PciHandler.PrimaryControl = 0x3f6;\r
- }\r
- //\r
- // Secondary controller data\r
- //\r
- if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) {\r
- Private->IntThunk->PciHandler.SecondaryBusMaster = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8);\r
- PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2);\r
- SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2);\r
-\r
- //\r
- // Clear pending interrupts in Bus Master registers\r
- //\r
- IoWrite16 (PrimaryMaster, 0x04);\r
- IoWrite16 (SecondaryMaster, 0x04);\r
-\r
- }\r
-\r
- //\r
- // Use native mode base address registers in two cases:\r
- // 1. Programming Interface (PI) register indicates Secondary Controller is\r
- // in native mode OR\r
- // 2. PCI device Sub Class Code is not IDE\r
- //\r
- if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {\r
- Private->IntThunk->PciHandler.SecondaryIrq = PciIrq;\r
- Private->IntThunk->PciHandler.SecondaryBase = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc);\r
- Private->IntThunk->PciHandler.SecondaryControl = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2);\r
- } else {\r
-\r
- Private->IntThunk->PciHandler.SecondaryIrq = 15;\r
- Private->IntThunk->PciHandler.SecondaryBase = 0x170;\r
- Private->IntThunk->PciHandler.SecondaryControl = 0x376;\r
- }\r
-\r
- //\r
- // Clear pending interrupts in IDE Command Block Status reg before we\r
- // Thunk to CSM16 below. Don't want a pending Interrupt before we\r
- // install the handlers as wierd corruption would occur and hang system.\r
- //\r
- //\r
- // Read IDE CMD blk status reg to clear out any pending interrupts.\r
- // Do here for Primary and Secondary IDE channels\r
- //\r
- RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07;\r
- IoRead8 (RegisterAddress);\r
- RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07;\r
- IoRead8 (RegisterAddress);\r
-\r
- Private->IntThunk->PciHandler.PrimaryReserved = 0;\r
- Private->IntThunk->PciHandler.SecondaryReserved = 0;\r
- Private->LegacyRegion->UnLock (\r
- Private->LegacyRegion,\r
- 0xE0000,\r
- 0x20000,\r
- &Granularity\r
- );\r
-\r
- Regs.X.AX = Legacy16InstallPciHandler;\r
- TempData = (UINTN) &Private->IntThunk->PciHandler;\r
- Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);\r
- Regs.X.BX = EFI_OFFSET ((UINT32) TempData);\r
-\r
- DumpPciHandle (&Private->IntThunk->PciHandler);\r
-\r
- Private->LegacyBios.FarCall86 (\r
- &Private->LegacyBios,\r
- Private->Legacy16CallSegment,\r
- Private->Legacy16CallOffset,\r
- &Regs,\r
- NULL,\r
- 0\r
- );\r
-\r
- Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
- Private->LegacyRegion->Lock (\r
- Private->LegacyRegion,\r
- 0xE0000,\r
- 0x20000,\r
- &Granularity\r
- );\r
-\r
-}\r
-\r
-\r
-/**\r
- Program the interrupt routing register in all the PCI devices. On a PC AT system\r
- this register contains the 8259 IRQ vector that matches it's PCI interrupt.\r
-\r
- @param Private Legacy BIOS Instance data\r
-\r
- @retval EFI_SUCCESS Succeed.\r
- @retval EFI_ALREADY_STARTED All PCI devices have been processed.\r
-\r
-**/\r
-EFI_STATUS\r
-PciProgramAllInterruptLineRegisters (\r
- IN LEGACY_BIOS_INSTANCE *Private\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- EFI_LEGACY_8259_PROTOCOL *Legacy8259;\r
- EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;\r
- EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
- UINT8 InterruptPin;\r
- UINTN Index;\r
- UINTN HandleCount;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN MassStorageHandleCount;\r
- EFI_HANDLE *MassStorageHandleBuffer;\r
- UINTN MassStorageHandleIndex;\r
- UINT8 PciIrq;\r
- UINT16 Command;\r
- UINTN PciSegment;\r
- UINTN PciBus;\r
- UINTN PciDevice;\r
- UINTN PciFunction;\r
- EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;\r
- UINTN RoutingTableEntries;\r
- UINT16 LegMask;\r
- UINT16 LegEdgeLevel;\r
- PCI_TYPE00 PciConfigHeader;\r
- EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable;\r
- UINTN PirqTableSize;\r
- UINTN Flags;\r
- HDD_INFO *HddInfo;\r
- UINT64 Supports;\r
-\r
- //\r
- // Note - This routine use to return immediately if Private->PciInterruptLine\r
- // was true. Routine changed since resets etc can cause not all\r
- // PciIo protocols to be registered the first time through.\r
- // New algorithm is to do the copy $PIR table on first pass and save\r
- // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives\r
- // a larger handle count then proceed with body of function else return\r
- // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.\r
- // If zero then function unprogrammed else skip function.\r
- //\r
- Legacy8259 = Private->Legacy8259;\r
- LegacyInterrupt = Private->LegacyInterrupt;\r
- LegacyBiosPlatform = Private->LegacyBiosPlatform;\r
-\r
- LegacyBiosPlatform->GetRoutingTable (\r
- Private->LegacyBiosPlatform,\r
- (VOID *) &RoutingTable,\r
- &RoutingTableEntries,\r
- (VOID *) &PirqTable,\r
- &PirqTableSize,\r
- NULL,\r
- NULL\r
- );\r
- CreateBridgeTable (RoutingTable, RoutingTableEntries);\r
-\r
- if (!Private->PciInterruptLine) {\r
- CopyPirqTable (\r
- Private,\r
- RoutingTable,\r
- RoutingTableEntries,\r
- PirqTable,\r
- PirqTableSize\r
- );\r
- }\r
-\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiPciIoProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_NOT_FOUND;\r
- }\r
- if (HandleCount == mHandleCount) {\r
- FreePool (HandleBuffer);\r
- return EFI_ALREADY_STARTED;\r
- }\r
-\r
- if (mHandleCount == 0x00) {\r
- mHandleCount = HandleCount;\r
- }\r
-\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- //\r
- // If VGA then only do VGA to allow drives fore time to spin up\r
- // otherwise assign PCI IRQs to all potential devices.\r
- //\r
- if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) {\r
- continue;\r
- } else {\r
- //\r
- // Force code to go through all handles next time called if video.\r
- // This will catch case where HandleCount doesn't change but want\r
- // to get drive info etc.\r
- //\r
- mHandleCount = 0x00;\r
- }\r
-\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Test whether the device can be enabled or not.\r
- // If it can't be enabled, then just skip it to avoid further operation.\r
- //\r
- PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- 0,\r
- sizeof (PciConfigHeader) / sizeof (UINT32),\r
- &PciConfigHeader\r
- );\r
- Command = PciConfigHeader.Hdr.Command;\r
-\r
- //\r
- // Note PciIo->Attributes does not program the PCI command register\r
- //\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationSupported,\r
- 0,\r
- &Supports\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationEnable,\r
- Supports,\r
- NULL\r
- );\r
- }\r
- PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command);\r
-\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
-\r
- InterruptPin = PciConfigHeader.Device.InterruptPin;\r
-\r
- if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) {\r
- PciIo->GetLocation (\r
- PciIo,\r
- &PciSegment,\r
- &PciBus,\r
- &PciDevice,\r
- &PciFunction\r
- );\r
- //\r
- // Translate PIRQ index back thru busses to slot bus with InterruptPin\r
- // zero based\r
- //\r
- InterruptPin -= 1;\r
-\r
- Status = GetBaseBus (\r
- Private,\r
- PciBus,\r
- PciDevice,\r
- RoutingTable,\r
- RoutingTableEntries\r
- );\r
-\r
- if (Status == EFI_NOT_FOUND) {\r
- TranslateBusPirq (\r
- Private,\r
- &PciBus,\r
- &PciDevice,\r
- &PciFunction,\r
- &InterruptPin\r
- );\r
- }\r
- //\r
- // Translate InterruptPin(0-3) into PIRQ\r
- //\r
- Status = LegacyBiosPlatform->TranslatePirq (\r
- LegacyBiosPlatform,\r
- PciBus,\r
- (PciDevice << 3),\r
- PciFunction,\r
- &InterruptPin,\r
- &PciIrq\r
- );\r
- //\r
- // TranslatePirq() should never fail or we are in trouble\r
- // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect\r
- //\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "Translate Pirq Failed - Status = %r\n ", Status));\r
- continue;\r
- }\r
-\r
- LegacyInterrupt->WritePirq (\r
- LegacyInterrupt,\r
- InterruptPin,\r
- PciIrq\r
- );\r
-\r
- //\r
- // Check if device has an OPROM associated with it.\r
- // If not invoke special 16-bit function, to allow 16-bit\r
- // code to install an interrupt handler.\r
- //\r
- Status = LegacyBiosCheckPciRom (\r
- &Private->LegacyBios,\r
- HandleBuffer[Index],\r
- NULL,\r
- NULL,\r
- &Flags\r
- );\r
- if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) {\r
- //\r
- // Device has no OPROM associated with it and is a mass storage\r
- // device. It needs to have an PCI IRQ handler installed. To\r
- // correctly install the handler we need to insure device is\r
- // connected. The device may just have register itself but not\r
- // been connected. Re-read PCI config space after as it can\r
- // change\r
- //\r
- //\r
- // Get IDE Handle. If matches handle then skip ConnectController\r
- // since ConnectController may force native mode and we don't\r
- // want that for primary IDE controller\r
- //\r
- MassStorageHandleCount = 0;\r
- MassStorageHandleBuffer = NULL;\r
- LegacyBiosPlatform->GetPlatformHandle (\r
- Private->LegacyBiosPlatform,\r
- EfiGetPlatformIdeHandle,\r
- 0,\r
- &MassStorageHandleBuffer,\r
- &MassStorageHandleCount,\r
- NULL\r
- );\r
-\r
- HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];\r
-\r
- LegacyBiosBuildIdeData (Private, &HddInfo, 0);\r
- PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- 0,\r
- sizeof (PciConfigHeader) / sizeof (UINT32),\r
- &PciConfigHeader\r
- );\r
-\r
- for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) {\r
- if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) {\r
- //\r
- // InstallLegacyIrqHandler according to Platform requirement\r
- //\r
- InstallLegacyIrqHandler (\r
- Private,\r
- PciIo,\r
- PciIrq,\r
- &PciConfigHeader\r
- );\r
- break;\r
- }\r
- }\r
- }\r
- //\r
- // Write InterruptPin and enable 8259.\r
- //\r
- PciIo->Pci.Write (\r
- PciIo,\r
- EfiPciIoWidthUint8,\r
- 0x3c,\r
- 1,\r
- &PciIrq\r
- );\r
- Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq));\r
-\r
- Legacy8259->GetMask (\r
- Legacy8259,\r
- &LegMask,\r
- &LegEdgeLevel,\r
- NULL,\r
- NULL\r
- );\r
-\r
- LegMask = (UINT16) (LegMask & (UINT16)~(1 << PciIrq));\r
- LegEdgeLevel = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq));\r
- Legacy8259->SetMask (\r
- Legacy8259,\r
- &LegMask,\r
- &LegEdgeLevel,\r
- NULL,\r
- NULL\r
- );\r
- }\r
- }\r
- FreePool (HandleBuffer);\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Find & verify PnP Expansion header in ROM image\r
-\r
- @param Private Protocol instance pointer.\r
- @param FirstHeader 1 = Find first header, 0 = Find successive headers\r
- @param PnpPtr Input Rom start if FirstHeader =1, Current Header\r
- otherwise Output Next header, if it exists\r
-\r
- @retval EFI_SUCCESS Next Header found at BasePnpPtr\r
- @retval EFI_NOT_FOUND No more headers\r
-\r
-**/\r
-EFI_STATUS\r
-FindNextPnpExpansionHeader (\r
- IN LEGACY_BIOS_INSTANCE *Private,\r
- IN BOOLEAN FirstHeader,\r
- IN OUT LEGACY_PNP_EXPANSION_HEADER **PnpPtr\r
-\r
- )\r
-{\r
- UINTN TempData;\r
- LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr;\r
- LocalPnpPtr = *PnpPtr;\r
- if (FirstHeader == FIRST_INSTANCE) {\r
- mBasePnpPtr = LocalPnpPtr;\r
- mBbsRomSegment = (UINT16) ((UINTN) mBasePnpPtr >> 4);\r
- //\r
- // Offset 0x1a gives offset to PnP expansion header for the first\r
- // instance, there after the structure gives the offset to the next\r
- // structure\r
- //\r
- LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a);\r
- TempData = (*((UINT16 *) LocalPnpPtr));\r
- } else {\r
- TempData = (UINT16) LocalPnpPtr->NextHeader;\r
- }\r
-\r
- LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData));\r
-\r
- //\r
- // Search for PnP table in Shadowed ROM\r
- //\r
- *PnpPtr = LocalPnpPtr;\r
- if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) {\r
- return EFI_SUCCESS;\r
- } else {\r
- return EFI_NOT_FOUND;\r
- }\r
-}\r
-\r
-\r
-/**\r
- Update list of Bev or BCV table entries.\r
-\r
- @param Private Protocol instance pointer.\r
- @param RomStart Table of ROM start address in RAM/ROM. PciIo _\r
- Handle to PCI IO for this device\r
- @param PciIo Instance of PCI I/O Protocol\r
-\r
- @retval EFI_SUCCESS Always should succeed.\r
-\r
-**/\r
-EFI_STATUS\r
-UpdateBevBcvTable (\r
- IN LEGACY_BIOS_INSTANCE *Private,\r
- IN EFI_LEGACY_EXPANSION_ROM_HEADER *RomStart,\r
- IN EFI_PCI_IO_PROTOCOL *PciIo\r
- )\r
-{\r
- VOID *RomEnd;\r
- BBS_TABLE *BbsTable;\r
- UINTN BbsIndex;\r
- EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr;\r
- LEGACY_PNP_EXPANSION_HEADER *PnpPtr;\r
- BOOLEAN Instance;\r
- EFI_STATUS Status;\r
- UINTN Segment;\r
- UINTN Bus;\r
- UINTN Device;\r
- UINTN Function;\r
- UINT8 Class;\r
- UINT16 DeviceType;\r
- Segment = 0;\r
- Bus = 0;\r
- Device = 0;\r
- Function = 0;\r
- Class = 0;\r
- DeviceType = BBS_UNKNOWN;\r
-\r
- //\r
- // Skip floppy and 2*onboard IDE controller entries(Master/Slave per\r
- // controller).\r
- //\r
- BbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
-\r
- BbsTable = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable;\r
- PnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) RomStart;\r
- PciPtr = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart;\r
-\r
- RomEnd = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr);\r
- Instance = FIRST_INSTANCE;\r
- //\r
- // OPROMs like PXE may not be tied to a piece of hardware and thus\r
- // don't have a PciIo associated with them\r
- //\r
- if (PciIo != NULL) {\r
- PciIo->GetLocation (\r
- PciIo,\r
- &Segment,\r
- &Bus,\r
- &Device,\r
- &Function\r
- );\r
- PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint8,\r
- 0x0b,\r
- 1,\r
- &Class\r
- );\r
-\r
- if (Class == PCI_CLASS_MASS_STORAGE) {\r
- DeviceType = BBS_HARDDISK;\r
- } else {\r
- if (Class == PCI_CLASS_NETWORK) {\r
- DeviceType = BBS_EMBED_NETWORK;\r
- }\r
- }\r
- }\r
-\r
- while (TRUE) {\r
- Status = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr);\r
- Instance = NOT_FIRST_INSTANCE;\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- //\r
- // There can be additional $PnP headers within the OPROM.\r
- // Example: SCSI can have one per drive.\r
- //\r
- BbsTable[BbsIndex].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
- BbsTable[BbsIndex].DeviceType = DeviceType;\r
- BbsTable[BbsIndex].Bus = (UINT32) Bus;\r
- BbsTable[BbsIndex].Device = (UINT32) Device;\r
- BbsTable[BbsIndex].Function = (UINT32) Function;\r
- BbsTable[BbsIndex].StatusFlags.OldPosition = 0;\r
- BbsTable[BbsIndex].StatusFlags.Reserved1 = 0;\r
- BbsTable[BbsIndex].StatusFlags.Enabled = 0;\r
- BbsTable[BbsIndex].StatusFlags.Failed = 0;\r
- BbsTable[BbsIndex].StatusFlags.MediaPresent = 0;\r
- BbsTable[BbsIndex].StatusFlags.Reserved2 = 0;\r
- BbsTable[BbsIndex].Class = PnpPtr->Class;\r
- BbsTable[BbsIndex].SubClass = PnpPtr->SubClass;\r
- BbsTable[BbsIndex].DescStringOffset = PnpPtr->ProductNamePointer;\r
- BbsTable[BbsIndex].DescStringSegment = mBbsRomSegment;\r
- BbsTable[BbsIndex].MfgStringOffset = PnpPtr->MfgPointer;\r
- BbsTable[BbsIndex].MfgStringSegment = mBbsRomSegment;\r
- BbsTable[BbsIndex].BootHandlerSegment = mBbsRomSegment;\r
-\r
- //\r
- // Have seen case where PXE base code have PnP expansion ROM\r
- // header but no Bcv or Bev vectors.\r
- //\r
- if (PnpPtr->Bcv != 0) {\r
- BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv;\r
- ++BbsIndex;\r
- }\r
-\r
- if (PnpPtr->Bev != 0) {\r
- BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bev;\r
- BbsTable[BbsIndex].DeviceType = BBS_BEV_DEVICE;\r
- ++BbsIndex;\r
- }\r
-\r
- if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) {\r
- break;\r
- }\r
- }\r
-\r
- BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY;\r
- Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex;\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol\r
- to chose the order. Skip any devices that have already have legacy\r
- BIOS run.\r
-\r
- @param Private Protocol instance pointer.\r
-\r
- @retval EFI_SUCCESS Succeed.\r
- @retval EFI_UNSUPPORTED Cannot get VGA device handle.\r
-\r
-**/\r
-EFI_STATUS\r
-PciShadowRoms (\r
- IN LEGACY_BIOS_INSTANCE *Private\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- PCI_TYPE00 Pci;\r
- UINTN Index;\r
- UINTN HandleCount;\r
- EFI_HANDLE *HandleBuffer;\r
- EFI_HANDLE VgaHandle;\r
- EFI_HANDLE FirstHandle;\r
- VOID **RomStart;\r
- UINTN Flags;\r
- PCI_TYPE00 PciConfigHeader;\r
- UINT16 *Command;\r
- UINT64 Supports;\r
-\r
- //\r
- // Make the VGA device first\r
- //\r
- Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
- Private->LegacyBiosPlatform,\r
- EfiGetPlatformVgaHandle,\r
- 0,\r
- &HandleBuffer,\r
- &HandleCount,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- VgaHandle = HandleBuffer[0];\r
-\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiPciIoProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Place the VGA handle as first.\r
- //\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- if (HandleBuffer[Index] == VgaHandle) {\r
- FirstHandle = HandleBuffer[0];\r
- HandleBuffer[0] = HandleBuffer[Index];\r
- HandleBuffer[Index] = FirstHandle;\r
- break;\r
- }\r
- }\r
- //\r
- // Allocate memory to save Command WORD from each device. We do this\r
- // to restore devices to same state as EFI after switching to legacy.\r
- //\r
- Command = (UINT16 *) AllocatePool (\r
- sizeof (UINT16) * (HandleCount + 1)\r
- );\r
- if (NULL == Command) {\r
- FreePool (HandleBuffer);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- //\r
- // Disconnect all EFI devices first. This covers cases where alegacy BIOS\r
- // may control multiple PCI devices.\r
- //\r
- for (Index = 0; Index < HandleCount; Index++) {\r
-\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Save command register for "connect" loop\r
- //\r
- PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- 0,\r
- sizeof (PciConfigHeader) / sizeof (UINT32),\r
- &PciConfigHeader\r
- );\r
- Command[Index] = PciConfigHeader.Hdr.Command;\r
- //\r
- // Skip any device that already has a legacy ROM run\r
- //\r
- Status = IsLegacyRom (HandleBuffer[Index]);\r
- if (!EFI_ERROR (Status)) {\r
- continue;\r
- }\r
- //\r
- // Stop EFI Drivers with oprom.\r
- //\r
- gBS->DisconnectController (\r
- HandleBuffer[Index],\r
- NULL,\r
- NULL\r
- );\r
- }\r
- //\r
- // For every device that has not had a legacy ROM started. Start a legacy ROM.\r
- //\r
- for (Index = 0; Index < HandleCount; Index++) {\r
-\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
-\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Here make sure if one VGA have been shadowed,\r
- // then wil not shadowed another one.\r
- //\r
- PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- 0,\r
- sizeof (Pci) / sizeof (UINT32),\r
- &Pci\r
- );\r
-\r
- //\r
- // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices,\r
- // one will work in legacy mode (OPROM will be given control) and\r
- // other Video devices will work in native mode (OS driver will handle these devices).\r
- //\r
- if (IS_PCI_DISPLAY (&Pci) && Index != 0) {\r
- continue;\r
- }\r
- //\r
- // Skip any device that already has a legacy ROM run\r
- //\r
- Status = IsLegacyRom (HandleBuffer[Index]);\r
- if (!EFI_ERROR (Status)) {\r
- continue;\r
- }\r
-\r
- //\r
- // If legacy VBIOS Oprom has not been dispatched before, install legacy VBIOS here.\r
- //\r
- if (IS_PCI_DISPLAY (&Pci) && Index == 0) {\r
- Status = LegacyBiosInstallVgaRom (Private);\r
- //\r
- // A return status of EFI_NOT_FOUND is considered valid (No EFI\r
- // driver is controlling video).\r
- //\r
- ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND));\r
- continue;\r
- }\r
-\r
- //\r
- // Install legacy ROM\r
- //\r
- Status = LegacyBiosInstallPciRom (\r
- &Private->LegacyBios,\r
- HandleBuffer[Index],\r
- NULL,\r
- &Flags,\r
- NULL,\r
- NULL,\r
- (VOID **) &RomStart,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) {\r
- continue;\r
- }\r
- }\r
- //\r
- // Restore Command register so legacy has same devices enabled or disabled\r
- // as EFI.\r
- // If Flags = NO_ROM use command register as is. This covers the\r
- // following cases:\r
- // Device has no ROMs associated with it.\r
- // Device has ROM associated with it but was already\r
- // installed.\r
- // = ROM_FOUND but not VALID_LEGACY_ROM, disable it.\r
- // = ROM_FOUND and VALID_LEGACY_ROM, enable it.\r
- //\r
- if ((Flags & ROM_FOUND) == ROM_FOUND) {\r
- if ((Flags & VALID_LEGACY_ROM) == 0) {\r
- Command[Index] = 0;\r
- } else {\r
- //\r
- // For several VGAs, only one of them can be enabled.\r
- //\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationSupported,\r
- 0,\r
- &Supports\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationEnable,\r
- Supports,\r
- NULL\r
- );\r
- }\r
- if (!EFI_ERROR (Status)) {\r
- Command[Index] = 0x1f;\r
- }\r
- }\r
- }\r
-\r
- PciIo->Pci.Write (\r
- PciIo,\r
- EfiPciIoWidthUint16,\r
- 0x04,\r
- 1,\r
- &Command[Index]\r
- );\r
- }\r
-\r
- FreePool (Command);\r
- FreePool (HandleBuffer);\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Test to see if a legacy PCI ROM exists for this device. Optionally return\r
- the Legacy ROM instance for this PCI device.\r
-\r
- @param This Protocol instance pointer.\r
- @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will\r
- be loaded\r
- @param RomImage Return the legacy PCI ROM for this device\r
- @param RomSize Size of ROM Image\r
- @param Flags Indicates if ROM found and if PC-AT.\r
-\r
- @retval EFI_SUCCESS Legacy Option ROM available for this device\r
- @retval EFI_UNSUPPORTED Legacy Option ROM not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-LegacyBiosCheckPciRom (\r
- IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
- IN EFI_HANDLE PciHandle,\r
- OUT VOID **RomImage, OPTIONAL\r
- OUT UINTN *RomSize, OPTIONAL\r
- OUT UINTN *Flags\r
- )\r
-{\r
- return LegacyBiosCheckPciRomEx (\r
- This,\r
- PciHandle,\r
- RomImage,\r
- RomSize,\r
- NULL,\r
- Flags,\r
- NULL,\r
- NULL\r
- );\r
-\r
-}\r
-\r
-/**\r
-\r
- Routine Description:\r
- Test to see if a legacy PCI ROM exists for this device. Optionally return\r
- the Legacy ROM instance for this PCI device.\r
-\r
- @param[in] This Protocol instance pointer.\r
- @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded\r
- @param[out] RomImage Return the legacy PCI ROM for this device\r
- @param[out] RomSize Size of ROM Image\r
- @param[out] RuntimeImageLength Runtime size of ROM Image\r
- @param[out] Flags Indicates if ROM found and if PC-AT.\r
- @param[out] OpromRevision Revision of the PCI Rom\r
- @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header\r
-\r
- @return EFI_SUCCESS Legacy Option ROM available for this device\r
- @return EFI_ALREADY_STARTED This device is already managed by its Oprom\r
- @return EFI_UNSUPPORTED Legacy Option ROM not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-LegacyBiosCheckPciRomEx (\r
- IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
- IN EFI_HANDLE PciHandle,\r
- OUT VOID **RomImage, OPTIONAL\r
- OUT UINTN *RomSize, OPTIONAL\r
- OUT UINTN *RuntimeImageLength, OPTIONAL\r
- OUT UINTN *Flags, OPTIONAL\r
- OUT UINT8 *OpromRevision, OPTIONAL\r
- OUT VOID **ConfigUtilityCodeHeader OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- LEGACY_BIOS_INSTANCE *Private;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- UINTN LocalRomSize;\r
- VOID *LocalRomImage;\r
- PCI_TYPE00 PciConfigHeader;\r
- VOID *LocalConfigUtilityCodeHeader;\r
-\r
- LocalConfigUtilityCodeHeader = NULL;\r
- *Flags = NO_ROM;\r
- Status = gBS->HandleProtocol (\r
- PciHandle,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- //\r
- // See if the option ROM for PciHandle has already been executed\r
- //\r
- Status = IsLegacyRom (PciHandle);\r
- if (!EFI_ERROR (Status)) {\r
- *Flags |= (UINTN)(ROM_FOUND | VALID_LEGACY_ROM);\r
- return EFI_SUCCESS;\r
- }\r
- //\r
- // Check for PCI ROM Bar\r
- //\r
- LocalRomSize = (UINTN) PciIo->RomSize;\r
- LocalRomImage = PciIo->RomImage;\r
- if (LocalRomSize != 0) {\r
- *Flags |= ROM_FOUND;\r
- }\r
-\r
- //\r
- // PCI specification states you should check VendorId and Device Id.\r
- //\r
- PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- 0,\r
- sizeof (PciConfigHeader) / sizeof (UINT32),\r
- &PciConfigHeader\r
- );\r
-\r
- Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
- Status = GetPciLegacyRom (\r
- Private->Csm16PciInterfaceVersion,\r
- PciConfigHeader.Hdr.VendorId,\r
- PciConfigHeader.Hdr.DeviceId,\r
- &LocalRomImage,\r
- &LocalRomSize,\r
- RuntimeImageLength,\r
- OpromRevision,\r
- &LocalConfigUtilityCodeHeader\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- *Flags |= VALID_LEGACY_ROM;\r
-\r
- //\r
- // See if Configuration Utility Code Header valid\r
- //\r
- if (LocalConfigUtilityCodeHeader != NULL) {\r
- *Flags |= ROM_WITH_CONFIG;\r
- }\r
-\r
- if (ConfigUtilityCodeHeader != NULL) {\r
- *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader;\r
- }\r
-\r
- if (RomImage != NULL) {\r
- *RomImage = LocalRomImage;\r
- }\r
-\r
- if (RomSize != NULL) {\r
- *RomSize = LocalRomSize;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Load a legacy PC-AT OPROM on the PciHandle device. Return information\r
- about how many disks were added by the OPROM and the shadow address and\r
- size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:\r
-\r
- @retval EFI_SUCCESS Legacy ROM loaded for this device\r
- @retval EFI_NOT_FOUND No PS2 Keyboard found\r
-\r
-**/\r
-EFI_STATUS\r
-EnablePs2Keyboard (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN HandleCount;\r
- EFI_ISA_IO_PROTOCOL *IsaIo;\r
- UINTN Index;\r
-\r
- //\r
- // Get SimpleTextIn and find PS2 controller\r
- //\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiSimpleTextInProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_NOT_FOUND;\r
- }\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- //\r
- // Open the IO Abstraction(s) needed to perform the supported test\r
- //\r
- Status = gBS->OpenProtocol (\r
- HandleBuffer[Index],\r
- &gEfiIsaIoProtocolGuid,\r
- (VOID **) &IsaIo,\r
- NULL,\r
- HandleBuffer[Index],\r
- EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL\r
- );\r
-\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // Use the ISA I/O Protocol to see if Controller is the Keyboard\r
- // controller\r
- //\r
- if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {\r
- Status = EFI_UNSUPPORTED;\r
- }\r
-\r
- gBS->CloseProtocol (\r
- HandleBuffer[Index],\r
- &gEfiIsaIoProtocolGuid,\r
- NULL,\r
- HandleBuffer[Index]\r
- );\r
- }\r
-\r
- if (!EFI_ERROR (Status)) {\r
- gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);\r
- }\r
- }\r
- FreePool (HandleBuffer);\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Load a legacy PC-AT OpROM for VGA controller.\r
-\r
- @param Private Driver private data.\r
-\r
- @retval EFI_SUCCESS Legacy ROM successfully installed for this device.\r
- @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video\r
- driver cannot be successfully disconnected, or VGA\r
- thunk driver cannot be successfully connected.\r
-\r
-**/\r
-EFI_STATUS\r
-LegacyBiosInstallVgaRom (\r
- IN LEGACY_BIOS_INSTANCE *Private\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_HANDLE VgaHandle;\r
- UINTN HandleCount;\r
- EFI_HANDLE *HandleBuffer;\r
- EFI_HANDLE *ConnectHandleBuffer;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- PCI_TYPE00 PciConfigHeader;\r
- UINT64 Supports;\r
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
- UINTN EntryCount;\r
- UINTN Index;\r
- VOID *Interface;\r
-\r
- //\r
- // EfiLegacyBiosGuild attached to a device implies that there is a legacy\r
- // BIOS associated with that device.\r
- //\r
- // There are 3 cases to consider.\r
- // Case 1: No EFI driver is controlling the video.\r
- // Action: Return EFI_SUCCESS from DisconnectController, search\r
- // video thunk driver, and connect it.\r
- // Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is\r
- // not on the image handle.\r
- // Action: Disconnect EFI driver.\r
- // ConnectController for video thunk\r
- // Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is\r
- // on the image handle.\r
- // Action: Do nothing and set Private->VgaInstalled = TRUE.\r
- // Then this routine is not called any more.\r
- //\r
- //\r
- // Get the VGA device.\r
- //\r
- Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
- Private->LegacyBiosPlatform,\r
- EfiGetPlatformVgaHandle,\r
- 0,\r
- &HandleBuffer,\r
- &HandleCount,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- VgaHandle = HandleBuffer[0];\r
-\r
- //\r
- // Check whether video thunk driver already starts.\r
- //\r
- Status = gBS->OpenProtocolInformation (\r
- VgaHandle,\r
- &gEfiPciIoProtocolGuid,\r
- &OpenInfoBuffer,\r
- &EntryCount\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- for (Index = 0; Index < EntryCount; Index++) {\r
- if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
- Status = gBS->HandleProtocol (\r
- OpenInfoBuffer[Index].AgentHandle,\r
- &gEfiLegacyBiosGuid,\r
- (VOID **) &Interface\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // This should be video thunk driver which is managing video device\r
- // So it need not start again\r
- //\r
- DEBUG ((EFI_D_INFO, "Video thunk driver already start! Return!\n"));\r
- Private->VgaInstalled = TRUE;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
- }\r
-\r
- //\r
- // Kick off the native EFI driver\r
- //\r
- Status = gBS->DisconnectController (\r
- VgaHandle,\r
- NULL,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- if (Status != EFI_NOT_FOUND) {\r
- return EFI_DEVICE_ERROR;\r
- } else {\r
- return Status;\r
- }\r
- }\r
- //\r
- // Find all the Thunk Driver\r
- //\r
- HandleBuffer = NULL;\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiLegacyBiosGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1));\r
- ASSERT (ConnectHandleBuffer != NULL);\r
-\r
- CopyMem (\r
- ConnectHandleBuffer,\r
- HandleBuffer,\r
- sizeof (EFI_HANDLE) * HandleCount\r
- );\r
- ConnectHandleBuffer[HandleCount] = NULL;\r
-\r
- FreePool (HandleBuffer);\r
-\r
- //\r
- // Enable the device and make sure VGA cycles are being forwarded to this VGA device\r
- //\r
- Status = gBS->HandleProtocol (\r
- VgaHandle,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- 0,\r
- sizeof (PciConfigHeader) / sizeof (UINT32),\r
- &PciConfigHeader\r
- );\r
-\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationSupported,\r
- 0,\r
- &Supports\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- Supports &= (UINT64)(EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \\r
- EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationEnable,\r
- Supports,\r
- NULL\r
- );\r
- }\r
-\r
- if (Status == EFI_SUCCESS) {\r
- Private->VgaInstalled = TRUE;\r
-\r
- //\r
- // Attach the VGA thunk driver.\r
- // Assume the video is installed. This prevents potential of infinite recursion.\r
- //\r
- Status = gBS->ConnectController (\r
- VgaHandle,\r
- ConnectHandleBuffer,\r
- NULL,\r
- TRUE\r
- );\r
- }\r
-\r
- FreePool (ConnectHandleBuffer);\r
-\r
- if (EFI_ERROR (Status)) {\r
-\r
- Private->VgaInstalled = FALSE;\r
-\r
- //\r
- // Reconnect the EFI VGA driver.\r
- //\r
- gBS->ConnectController (VgaHandle, NULL, NULL, TRUE);\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Load a legacy PC-AT OpROM.\r
-\r
- @param This Protocol instance pointer.\r
- @param Private Driver's private data.\r
- @param PciHandle The EFI handle for the PCI device. It could be\r
- NULL if the OpROM image is not associated with\r
- any device.\r
- @param OpromRevision The revision of PCI PC-AT ROM image.\r
- @param RomImage Pointer to PCI PC-AT ROM image header. It must not\r
- be NULL.\r
- @param ImageSize Size of the PCI PC-AT ROM image.\r
- @param RuntimeImageLength On input is the max runtime image length indicated by the PCIR structure\r
- On output is the actual runtime image length\r
- @param DiskStart Disk number of first device hooked by the ROM. If\r
- DiskStart is the same as DiskEnd no disked were\r
- hooked.\r
- @param DiskEnd Disk number of the last device hooked by the ROM.\r
- @param RomShadowAddress Shadow address of PC-AT ROM\r
-\r
- @retval EFI_SUCCESS Legacy ROM loaded for this device\r
- @retval EFI_OUT_OF_RESOURCES No more space for this ROM\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-LegacyBiosInstallRom (\r
- IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
- IN LEGACY_BIOS_INSTANCE *Private,\r
- IN EFI_HANDLE PciHandle,\r
- IN UINT8 OpromRevision,\r
- IN VOID *RomImage,\r
- IN UINTN ImageSize,\r
- IN OUT UINTN *RuntimeImageLength,\r
- OUT UINT8 *DiskStart, OPTIONAL\r
- OUT UINT8 *DiskEnd, OPTIONAL\r
- OUT VOID **RomShadowAddress OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_STATUS PciEnableStatus;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- UINT8 LocalDiskStart;\r
- UINT8 LocalDiskEnd;\r
- UINTN Segment;\r
- UINTN Bus;\r
- UINTN Device;\r
- UINTN Function;\r
- EFI_IA32_REGISTER_SET Regs;\r
- UINT8 VideoMode;\r
- UINT8 OldVideoMode;\r
- EFI_TIME BootTime;\r
- UINT32 *BdaPtr;\r
- UINT32 LocalTime;\r
- UINT32 StartBbsIndex;\r
- UINT32 EndBbsIndex;\r
- UINT32 MaxRomAddr;\r
- UINTN TempData;\r
- UINTN InitAddress;\r
- UINTN RuntimeAddress;\r
- EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
- UINT32 Granularity;\r
-\r
- PciIo = NULL;\r
- LocalDiskStart = 0;\r
- LocalDiskEnd = 0;\r
- Segment = 0;\r
- Bus = 0;\r
- Device = 0;\r
- Function = 0;\r
- VideoMode = 0;\r
- OldVideoMode = 0;\r
- PhysicalAddress = 0;\r
- MaxRomAddr = PcdGet32 (PcdEndOpromShadowAddress);\r
-\r
- if ((Private->Legacy16Table->TableLength >= OFFSET_OF(EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&\r
- (Private->Legacy16Table->UmaAddress != 0) &&\r
- (Private->Legacy16Table->UmaSize != 0) &&\r
- (MaxRomAddr > (Private->Legacy16Table->UmaAddress))) {\r
- MaxRomAddr = Private->Legacy16Table->UmaAddress;\r
- }\r
-\r
-\r
- PciProgramAllInterruptLineRegisters (Private);\r
-\r
- if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) {\r
- //\r
- // CSM16 3.0 meets PCI 3.0 OpROM\r
- // first test if there is enough space for its INIT code\r
- //\r
- PhysicalAddress = CONVENTIONAL_MEMORY_TOP;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiBootServicesCode,\r
- EFI_SIZE_TO_PAGES (ImageSize),\r
- &PhysicalAddress\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));\r
- //\r
- // Report Status Code to indicate that there is no enough space for OpROM\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)\r
- );\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- InitAddress = (UINTN) PhysicalAddress;\r
- //\r
- // then test if there is enough space for its RT code\r
- //\r
- RuntimeAddress = Private->OptionRom;\r
- if (RuntimeAddress + *RuntimeImageLength > MaxRomAddr) {\r
- DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));\r
- gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));\r
- //\r
- // Report Status Code to indicate that there is no enough space for OpROM\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)\r
- );\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- } else {\r
- // CSM16 3.0 meets PCI 2.x OpROM\r
- // CSM16 2.x meets PCI 2.x/3.0 OpROM\r
- // test if there is enough space for its INIT code\r
- //\r
- InitAddress = PCI_START_ADDRESS (Private->OptionRom);\r
- if (InitAddress + ImageSize > MaxRomAddr) {\r
- DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));\r
- //\r
- // Report Status Code to indicate that there is no enough space for OpROM\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)\r
- );\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- RuntimeAddress = InitAddress;\r
- }\r
-\r
- Private->LegacyRegion->UnLock (\r
- Private->LegacyRegion,\r
- 0xE0000,\r
- 0x20000,\r
- &Granularity\r
- );\r
-\r
- Private->LegacyRegion->UnLock (\r
- Private->LegacyRegion,\r
- (UINT32) RuntimeAddress,\r
- (UINT32) ImageSize,\r
- &Granularity\r
- );\r
-\r
- DEBUG ((EFI_D_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize));\r
-\r
- CopyMem ((VOID *) InitAddress, RomImage, ImageSize);\r
-\r
- //\r
- // Read the highest disk number "installed: and assume a new disk will\r
- // show up on the first drive past the current value.\r
- // There are several considerations here:\r
- // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo\r
- // the change until boot selection time frame.\r
- // 2. BBS compliants drives will not change 40:75 until boot time.\r
- // 3. Onboard IDE controllers will change 40:75\r
- //\r
- ACCESS_PAGE0_CODE (\r
- LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);\r
- if ((Private->Disk4075 + 0x80) < LocalDiskStart) {\r
- //\r
- // Update table since onboard IDE drives found\r
- //\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = 0xff;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = 0xff;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = 0xff;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = 0xff;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = (UINT8) (Private->Disk4075 + 0x80);\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = LocalDiskStart;\r
- Private->LegacyEfiHddTableIndex ++;\r
- Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f);\r
- Private->DiskEnd = LocalDiskStart;\r
- }\r
-\r
- if (PciHandle != mVgaHandle) {\r
-\r
- EnablePs2Keyboard ();\r
-\r
- //\r
- // Store current mode settings since PrepareToScanRom may change mode.\r
- //\r
- VideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));\r
- }\r
- );\r
-\r
- //\r
- // Notify the platform that we are about to scan the ROM\r
- //\r
- Status = Private->LegacyBiosPlatform->PlatformHooks (\r
- Private->LegacyBiosPlatform,\r
- EfiPlatformHookPrepareToScanRom,\r
- 0,\r
- PciHandle,\r
- &InitAddress,\r
- NULL,\r
- NULL\r
- );\r
-\r
- //\r
- // If Status returned is EFI_UNSUPPORTED then abort due to platform\r
- // policy.\r
- //\r
- if (Status == EFI_UNSUPPORTED) {\r
- goto Done;\r
- }\r
-\r
- //\r
- // Report corresponding status code\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT)\r
- );\r
-\r
- //\r
- // Generate number of ticks since midnight for BDA. Some OPROMs require\r
- // this. Place result in 40:6C-6F\r
- //\r
- gRT->GetTime (&BootTime, NULL);\r
- LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;\r
-\r
- //\r
- // Multiply result by 18.2 for number of ticks since midnight.\r
- // Use 182/10 to avoid floating point math.\r
- //\r
- ACCESS_PAGE0_CODE (\r
- LocalTime = (LocalTime * 182) / 10;\r
- BdaPtr = (UINT32 *) ((UINTN) 0x46C);\r
- *BdaPtr = LocalTime;\r
- );\r
-\r
- //\r
- // Pass in handoff data\r
- //\r
- PciEnableStatus = EFI_UNSUPPORTED;\r
- ZeroMem (&Regs, sizeof (Regs));\r
- if (PciHandle != NULL) {\r
-\r
- Status = gBS->HandleProtocol (\r
- PciHandle,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Enable command register.\r
- //\r
- PciEnableStatus = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationEnable,\r
- EFI_PCI_DEVICE_ENABLE,\r
- NULL\r
- );\r
-\r
- PciIo->GetLocation (\r
- PciIo,\r
- &Segment,\r
- &Bus,\r
- &Device,\r
- &Function\r
- );\r
- DEBUG ((EFI_D_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function));\r
- }\r
-\r
- mIgnoreBbsUpdateFlag = FALSE;\r
- Regs.X.AX = Legacy16DispatchOprom;\r
-\r
- //\r
- // Generate DispatchOpRomTable data\r
- //\r
- Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment;\r
- Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset = Private->Legacy16Table->PnPInstallationCheckOffset;\r
- Private->IntThunk->DispatchOpromTable.OpromSegment = (UINT16) (InitAddress >> 4);\r
- Private->IntThunk->DispatchOpromTable.PciBus = (UINT8) Bus;\r
- Private->IntThunk->DispatchOpromTable.PciDeviceFunction = (UINT8) ((Device << 3) | Function);\r
- Private->IntThunk->DispatchOpromTable.NumberBbsEntries = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
- Private->IntThunk->DispatchOpromTable.BbsTablePointer = (UINT32) (UINTN) Private->BbsTablePtr;\r
- Private->IntThunk->DispatchOpromTable.RuntimeSegment = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4));\r
- TempData = (UINTN) &Private->IntThunk->DispatchOpromTable;\r
- Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);\r
- Regs.X.BX = EFI_OFFSET ((UINT32) TempData);\r
- //\r
- // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes\r
- // Otherwise, it may cause the system to hang in some cases\r
- //\r
- if (!EFI_ERROR (PciEnableStatus)) {\r
- DEBUG ((EFI_D_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function));\r
- Private->LegacyBios.FarCall86 (\r
- &Private->LegacyBios,\r
- Private->Legacy16CallSegment,\r
- Private->Legacy16CallOffset,\r
- &Regs,\r
- NULL,\r
- 0\r
- );\r
- } else {\r
- Regs.X.BX = 0;\r
- }\r
-\r
- if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) {\r
- Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries;\r
- mIgnoreBbsUpdateFlag = TRUE;\r
- }\r
- //\r
- // Check if non-BBS compliant drives found\r
- //\r
- if (Regs.X.BX != 0) {\r
- LocalDiskEnd = (UINT8) (LocalDiskStart + Regs.H.BL);\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;\r
- Private->DiskEnd = LocalDiskEnd;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;\r
- Private->LegacyEfiHddTableIndex += 1;\r
- }\r
- //\r
- // Skip video mode set, if installing VGA\r
- //\r
- if (PciHandle != mVgaHandle) {\r
- //\r
- // Set mode settings since PrepareToScanRom may change mode\r
- //\r
- ACCESS_PAGE0_CODE ({\r
- OldVideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));\r
- });\r
-\r
- if (VideoMode != OldVideoMode) {\r
- //\r
- // The active video mode is changed, restore it to original mode.\r
- //\r
- Regs.H.AH = 0x00;\r
- Regs.H.AL = VideoMode;\r
- Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs);\r
- }\r
- }\r
- //\r
- // Regs.X.AX from the adapter initializion is ignored since some adapters\r
- // do not follow the standard of setting AX = 0 on success.\r
- //\r
- //\r
- // The ROM could have updated it's size so we need to read again.\r
- //\r
- if (((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
- //\r
- // Now we check the signature (0xaa55) to judge whether the run-time code is truly generated by INIT function.\r
- // If signature is not valid, that means the INIT function didn't copy the run-time code to RuntimeAddress.\r
- //\r
- *RuntimeImageLength = 0;\r
- } else {\r
- *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Size512 * 512;\r
- }\r
-\r
- DEBUG ((EFI_D_INFO, " fsize = %x\n", *RuntimeImageLength));\r
-\r
- //\r
- // If OpROM runs in 2.0 mode\r
- //\r
- if (PhysicalAddress == 0) {\r
- if (*RuntimeImageLength < ImageSize) {\r
- //\r
- // Make area from end of shadowed rom to end of original rom all ffs\r
- //\r
- gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff);\r
- }\r
- }\r
-\r
- ACCESS_PAGE0_CODE (\r
- LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);\r
- );\r
-\r
- //\r
- // Allow platform to perform any required actions after the\r
- // OPROM has been initialized.\r
- //\r
- Status = Private->LegacyBiosPlatform->PlatformHooks (\r
- Private->LegacyBiosPlatform,\r
- EfiPlatformHookAfterRomInit,\r
- 0,\r
- PciHandle,\r
- &RuntimeAddress,\r
- NULL,\r
- NULL\r
- );\r
- if (PciHandle != NULL) {\r
- //\r
- // If no PCI Handle then no header or Bevs.\r
- //\r
- if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) {\r
- StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
- TempData = RuntimeAddress;\r
- UpdateBevBcvTable (\r
- Private,\r
- (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData,\r
- PciIo\r
- );\r
- EndBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
- LocalDiskEnd = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex));\r
- if (LocalDiskEnd != LocalDiskStart) {\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;\r
- Private->DiskEnd = LocalDiskEnd;\r
- Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;\r
- Private->LegacyEfiHddTableIndex += 1;\r
- }\r
- }\r
- //\r
- // Mark PCI device as having a legacy BIOS ROM loaded.\r
- //\r
- RomShadow (\r
- PciHandle,\r
- (UINT32) RuntimeAddress,\r
- (UINT32) *RuntimeImageLength,\r
- LocalDiskStart,\r
- LocalDiskEnd\r
- );\r
- }\r
-\r
- //\r
- // Stuff caller's OPTIONAL return parameters.\r
- //\r
- if (RomShadowAddress != NULL) {\r
- *RomShadowAddress = (VOID *) RuntimeAddress;\r
- }\r
-\r
- if (DiskStart != NULL) {\r
- *DiskStart = LocalDiskStart;\r
- }\r
-\r
- if (DiskEnd != NULL) {\r
- *DiskEnd = LocalDiskEnd;\r
- }\r
-\r
- Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength);\r
-\r
- Status = EFI_SUCCESS;\r
-\r
-Done:\r
- if (PhysicalAddress != 0) {\r
- //\r
- // Free pages when OpROM is 3.0\r
- //\r
- gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));\r
- }\r
-\r
- //\r
- // Insure all shadowed areas are locked\r
- //\r
- Private->LegacyRegion->Lock (\r
- Private->LegacyRegion,\r
- 0xC0000,\r
- 0x40000,\r
- &Granularity\r
- );\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Let IOMMU grant DMA access for the PCI device.\r
-\r
- @param PciHandle The EFI handle for the PCI device.\r
- @param HostAddress The system memory address to map to the PCI controller.\r
- @param NumberOfBytes The number of bytes to map.\r
-\r
- @retval EFI_SUCCESS The DMA access is granted.\r
-**/\r
-EFI_STATUS\r
-IoMmuGrantAccess (\r
- IN EFI_HANDLE PciHandle,\r
- IN EFI_PHYSICAL_ADDRESS HostAddress,\r
- IN UINTN NumberOfBytes\r
- )\r
-{\r
- EFI_PHYSICAL_ADDRESS DeviceAddress;\r
- VOID *Mapping;\r
- EFI_STATUS Status;\r
-\r
- if (PciHandle == NULL) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- Status = EFI_SUCCESS;\r
- if (mIoMmu == NULL) {\r
- gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu);\r
- }\r
- if (mIoMmu != NULL) {\r
- Status = mIoMmu->Map (\r
- mIoMmu,\r
- EdkiiIoMmuOperationBusMasterCommonBuffer,\r
- (VOID *)(UINTN)HostAddress,\r
- &NumberOfBytes,\r
- &DeviceAddress,\r
- &Mapping\r
- );\r
- if (EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_ERROR, "LegacyPci - IoMmuMap - %r\n", Status));\r
- } else {\r
- ASSERT (DeviceAddress == HostAddress);\r
- Status = mIoMmu->SetAttribute (\r
- mIoMmu,\r
- PciHandle,\r
- Mapping,\r
- EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
- );\r
- if (EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_ERROR, "LegacyPci - IoMmuSetAttribute - %r\n", Status));\r
- }\r
- }\r
- }\r
- return Status;\r
-}\r
-\r
-/**\r
- Load a legacy PC-AT OPROM on the PciHandle device. Return information\r
- about how many disks were added by the OPROM and the shadow address and\r
- size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:\r
-\r
- @param This Protocol instance pointer.\r
- @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will\r
- be loaded. This value is NULL if RomImage is\r
- non-NULL. This is the normal case.\r
- @param RomImage A PCI PC-AT ROM image. This argument is non-NULL\r
- if there is no hardware associated with the ROM\r
- and thus no PciHandle, otherwise is must be NULL.\r
- Example is PXE base code.\r
- @param Flags Indicates if ROM found and if PC-AT.\r
- @param DiskStart Disk number of first device hooked by the ROM. If\r
- DiskStart is the same as DiskEnd no disked were\r
- hooked.\r
- @param DiskEnd Disk number of the last device hooked by the ROM.\r
- @param RomShadowAddress Shadow address of PC-AT ROM\r
- @param RomShadowedSize Size of RomShadowAddress in bytes\r
-\r
- @retval EFI_SUCCESS Legacy ROM loaded for this device\r
- @retval EFI_INVALID_PARAMETER PciHandle not found\r
- @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard\r
- ROM\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-LegacyBiosInstallPciRom (\r
- IN EFI_LEGACY_BIOS_PROTOCOL * This,\r
- IN EFI_HANDLE PciHandle,\r
- IN VOID **RomImage,\r
- OUT UINTN *Flags,\r
- OUT UINT8 *DiskStart, OPTIONAL\r
- OUT UINT8 *DiskEnd, OPTIONAL\r
- OUT VOID **RomShadowAddress, OPTIONAL\r
- OUT UINT32 *RomShadowedSize OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- LEGACY_BIOS_INSTANCE *Private;\r
- VOID *LocalRomImage;\r
- UINTN ImageSize;\r
- UINTN RuntimeImageLength;\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- PCI_TYPE01 PciConfigHeader;\r
- UINTN HandleCount;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN PciSegment;\r
- UINTN PciBus;\r
- UINTN PciDevice;\r
- UINTN PciFunction;\r
- UINTN LastBus;\r
- UINTN Index;\r
- UINT8 OpromRevision;\r
- UINT32 Granularity;\r
- PCI_3_0_DATA_STRUCTURE *Pcir;\r
-\r
- OpromRevision = 0;\r
-\r
- Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
- if (Private->Legacy16Table->LastPciBus == 0) {\r
- //\r
- // Get last bus number if not already found\r
- //\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiPciIoProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer\r
- );\r
-\r
- LastBus = 0;\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
-\r
- Status = PciIo->GetLocation (\r
- PciIo,\r
- &PciSegment,\r
- &PciBus,\r
- &PciDevice,\r
- &PciFunction\r
- );\r
- if (PciBus > LastBus) {\r
- LastBus = PciBus;\r
- }\r
- }\r
-\r
- Private->LegacyRegion->UnLock (\r
- Private->LegacyRegion,\r
- 0xE0000,\r
- 0x20000,\r
- &Granularity\r
- );\r
- Private->Legacy16Table->LastPciBus = (UINT8) LastBus;\r
- Private->LegacyRegion->Lock (\r
- Private->LegacyRegion,\r
- 0xE0000,\r
- 0x20000,\r
- &Granularity\r
- );\r
- }\r
-\r
- *Flags = 0;\r
- if ((PciHandle != NULL) && (RomImage == NULL)) {\r
- //\r
- // If PciHandle has OpRom to Execute\r
- // and OpRom are all associated with Hardware\r
- //\r
- Status = gBS->HandleProtocol (\r
- PciHandle,\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) &PciIo\r
- );\r
-\r
- if (!EFI_ERROR (Status)) {\r
- PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- 0,\r
- sizeof (PciConfigHeader) / sizeof (UINT32),\r
- &PciConfigHeader\r
- );\r
-\r
- //\r
- // if video installed & OPROM is video return\r
- //\r
- if (\r
- (\r
- ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) &&\r
- (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA))\r
- ||\r
- ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) &&\r
- (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA))\r
- )\r
- &&\r
- (!Private->VgaInstalled)\r
- ) {\r
- mVgaInstallationInProgress = TRUE;\r
-\r
- //\r
- // return EFI_UNSUPPORTED;\r
- //\r
- }\r
- }\r
- //\r
- // To run any legacy image, the VGA needs to be installed first.\r
- // if installing the video, then don't need the thunk as already installed.\r
- //\r
- Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
- Private->LegacyBiosPlatform,\r
- EfiGetPlatformVgaHandle,\r
- 0,\r
- &HandleBuffer,\r
- &HandleCount,\r
- NULL\r
- );\r
-\r
- if (!EFI_ERROR (Status)) {\r
- mVgaHandle = HandleBuffer[0];\r
- if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) {\r
- //\r
- // A return status of EFI_NOT_FOUND is considered valid (No EFI\r
- // driver is controlling video.\r
- //\r
- mVgaInstallationInProgress = TRUE;\r
- Status = LegacyBiosInstallVgaRom (Private);\r
- if (EFI_ERROR (Status)) {\r
- if (Status != EFI_NOT_FOUND) {\r
- mVgaInstallationInProgress = FALSE;\r
- return Status;\r
- }\r
- } else {\r
- mVgaInstallationInProgress = FALSE;\r
- }\r
- }\r
- }\r
- //\r
- // See if the option ROM for PciHandle has already been executed\r
- //\r
- Status = IsLegacyRom (PciHandle);\r
-\r
- if (!EFI_ERROR (Status)) {\r
- mVgaInstallationInProgress = FALSE;\r
- GetShadowedRomParameters (\r
- PciHandle,\r
- DiskStart,\r
- DiskEnd,\r
- RomShadowAddress,\r
- (UINTN *) RomShadowedSize\r
- );\r
- return EFI_SUCCESS;\r
- }\r
-\r
- Status = LegacyBiosCheckPciRomEx (\r
- &Private->LegacyBios,\r
- PciHandle,\r
- &LocalRomImage,\r
- &ImageSize,\r
- &RuntimeImageLength,\r
- Flags,\r
- &OpromRevision,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // There is no PCI ROM in the ROM BAR or no onboard ROM\r
- //\r
- mVgaInstallationInProgress = FALSE;\r
- return EFI_UNSUPPORTED;\r
- }\r
- } else {\r
- if ((RomImage == NULL) || (*RomImage == NULL)) {\r
- //\r
- // If PciHandle is NULL, and no OpRom is to be associated\r
- //\r
- mVgaInstallationInProgress = FALSE;\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
- Private->LegacyBiosPlatform,\r
- EfiGetPlatformVgaHandle,\r
- 0,\r
- &HandleBuffer,\r
- &HandleCount,\r
- NULL\r
- );\r
- if ((!EFI_ERROR (Status)) && (!Private->VgaInstalled)) {\r
- //\r
- // A return status of EFI_NOT_FOUND is considered valid (No EFI\r
- // driver is controlling video.\r
- //\r
- mVgaInstallationInProgress = TRUE;\r
- Status = LegacyBiosInstallVgaRom (Private);\r
- if (EFI_ERROR (Status)) {\r
- if (Status != EFI_NOT_FOUND) {\r
- mVgaInstallationInProgress = FALSE;\r
- return Status;\r
- }\r
- } else {\r
- mVgaInstallationInProgress = FALSE;\r
- }\r
- }\r
-\r
- LocalRomImage = *RomImage;\r
- if (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE ||\r
- ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset == 0 ||\r
- (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset & 3 ) != 0) {\r
- mVgaInstallationInProgress = FALSE;\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- Pcir = (PCI_3_0_DATA_STRUCTURE *)\r
- ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset);\r
-\r
- if ((Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) || (Pcir->CodeType != PCI_CODE_TYPE_PCAT_IMAGE)) {\r
- mVgaInstallationInProgress = FALSE;\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- ImageSize = Pcir->ImageLength * 512;\r
- if (Pcir->Length >= 0x1C) {\r
- OpromRevision = Pcir->Revision;\r
- } else {\r
- OpromRevision = 0;\r
- }\r
- if (Pcir->Revision < 3) {\r
- RuntimeImageLength = 0;\r
- } else {\r
- RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;\r
- }\r
- }\r
-\r
- //\r
- // Grant access for below 1M\r
- // BDA/EBDA/LowPMM and scratch memory for OPROM.\r
- //\r
- IoMmuGrantAccess (PciHandle, 0, SIZE_1MB);\r
- //\r
- // Grant access for HiPmm\r
- //\r
- IoMmuGrantAccess (\r
- PciHandle,\r
- Private->IntThunk->EfiToLegacy16InitTable.HiPmmMemory,\r
- Private->IntThunk->EfiToLegacy16InitTable.HiPmmMemorySizeInBytes\r
- );\r
-\r
- //\r
- // Shadow and initialize the OpROM.\r
- //\r
- ASSERT (Private->TraceIndex < 0x200);\r
- Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000;\r
- Private->TraceIndex ++;\r
- Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200);\r
- Status = LegacyBiosInstallRom (\r
- This,\r
- Private,\r
- PciHandle,\r
- OpromRevision,\r
- LocalRomImage,\r
- ImageSize,\r
- &RuntimeImageLength,\r
- DiskStart,\r
- DiskEnd,\r
- RomShadowAddress\r
- );\r
- if (RomShadowedSize != NULL) {\r
- *RomShadowedSize = (UINT32) RuntimeImageLength;\r
- }\r
-\r
- mVgaInstallationInProgress = FALSE;\r
- return Status;\r
-}\r
-\r