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