1 /** @file 2 Legacy BIOS Platform support 3 4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials are 7 licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The 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 "LegacyPlatform.h" 17 18 EFI_SETUP_BBS_MAP mSetupBbsMap[] = { 19 { 1, 2, 1, 1 }, // ATA HardDrive 20 { 2, 3, 1, 1 }, // ATAPI CDROM 21 { 3, 0x80, 2, 0 }, // PXE 22 { 4, 1, 0, 6 }, // USB Floppy 23 { 4, 2, 0, 6 }, // USB HDD 24 { 4, 3, 0, 6 }, // USB CD 25 { 4, 1, 0, 0 }, // USB ZIP Bugbug since Class/SubClass code is uninitialized 26 { 4, 2, 0, 0 } // USB ZIP Bugbug since Class/SubClass code is uninitialized 27 }; 28 29 // 30 // Global variables for System ROMs 31 // 32 #define SYSTEM_ROM_FILE_GUID \ 33 { 0x1547B4F3, 0x3E8A, 0x4FEF, { 0x81, 0xC8, 0x32, 0x8E, 0xD6, 0x47, 0xAB, 0x1A } } 34 35 #define NULL_ROM_FILE_GUID \ 36 { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } 37 38 SYSTEM_ROM_TABLE mSystemRomTable[] = { 39 { SYSTEM_ROM_FILE_GUID, 1 }, 40 { NULL_ROM_FILE_GUID, 0 } 41 }; 42 43 EFI_HANDLE mVgaHandles[0x20]; 44 EFI_HANDLE mDiskHandles[0x20]; 45 EFI_HANDLE mIsaHandles[0x20]; 46 47 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY IrqPriorityTable[MAX_IRQ_PRIORITY_ENTRIES] = { 48 {0x0B,0}, 49 {0x09,0}, 50 {0x0A,0}, 51 {0x05,0}, 52 {0x07,0}, 53 {0x00,0}, 54 {0x00,0} 55 }; 56 57 // 58 // PIRQ Table 59 // - Slot numbering will be used to update the bus number and determine bridge 60 // to check to get bus number. The Slot number - 1 is an index into a decode 61 // table to get the bridge information. 62 // 63 EFI_LEGACY_PIRQ_TABLE PirqTableHead = { 64 { 65 EFI_LEGACY_PIRQ_TABLE_SIGNATURE, // UINT32 Signature 66 0x00, // UINT8 MinorVersion 67 0x01, // UINT8 MajorVersion 68 0x0000, // UINT16 TableSize 69 0x00, // UINT8 Bus 70 0x08, // UINT8 DevFun 71 0x0000, // UINT16 PciOnlyIrq 72 0x8086, // UINT16 CompatibleVid 73 0x122e, // UINT16 CompatibleDid 74 0x00000000, // UINT32 Miniport 75 { // UINT8 Reserved[11] 76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 0x00, 0x00, 0x00 78 }, 79 0x00, // UINT8 Checksum 80 }, 81 { 82 // -- Pin 1 -- -- Pin 2 -- -- Pin 3 -- -- Pin 4 -- 83 // Bus Dev Reg Map Reg Map Reg Map Reg Map 84 // 85 {0x00,0x08,{{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8}},0x00,0x00}, 86 {0x00,0x10,{{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8}},0x01,0x00}, 87 {0x00,0x18,{{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8},{0x61,0xDEB8}},0x02,0x00}, 88 {0x00,0x20,{{0x63,0xDEB8},{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8}},0x03,0x00}, 89 {0x00,0x28,{{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8}},0x04,0x00}, 90 {0x00,0x30,{{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8}},0x05,0x00}, 91 } 92 }; 93 94 LEGACY_BIOS_PLATFORM_INSTANCE mPrivateData; 95 EFI_HANDLE mImageHandle = NULL; 96 97 /** 98 Return the handles and assorted information for the specified PCI Class code 99 100 @param[in] PciClasses Array of PCI_CLASS_RECORD to find terminated with ClassCode 0xff 101 @param[in,out] DeviceTable Table to place handles etc in. 102 @param[in,out] DeviceIndex Number of devices found 103 @param[in] DeviceFlags FALSE if a valid legacy ROM is required, TRUE otherwise. 104 105 @retval EFI_SUCCESS One or more devices found 106 @retval EFI_NOT_FOUND No device found 107 108 **/ 109 EFI_STATUS 110 FindAllDeviceTypes ( 111 IN PCI_CLASS_RECORD *PciClasses, 112 IN OUT DEVICE_STRUCTURE *DeviceTable, 113 IN OUT UINT16 *DeviceIndex, 114 IN BOOLEAN DeviceFlags 115 ) 116 { 117 UINTN HandleCount; 118 EFI_HANDLE *HandleBuffer; 119 UINTN Index; 120 UINTN StartIndex; 121 PCI_TYPE00 PciConfigHeader; 122 EFI_PCI_IO_PROTOCOL *PciIo; 123 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 124 UINTN Flags; 125 EFI_STATUS Status; 126 UINTN Index2; 127 128 // 129 // Get legacy BIOS protocol as it is required to deal with Option ROMs. 130 // 131 StartIndex = *DeviceIndex; 132 Status = gBS->LocateProtocol ( 133 &gEfiLegacyBiosProtocolGuid, 134 NULL, 135 (VOID**)&LegacyBios 136 ); 137 ASSERT_EFI_ERROR (Status); 138 139 // 140 // Get all PCI handles and check them to generate a list of matching devices. 141 // 142 gBS->LocateHandleBuffer ( 143 ByProtocol, 144 &gEfiPciIoProtocolGuid, 145 NULL, 146 &HandleCount, 147 &HandleBuffer 148 ); 149 for (Index = 0; Index < HandleCount; Index++) { 150 gBS->HandleProtocol ( 151 HandleBuffer[Index], 152 &gEfiPciIoProtocolGuid, 153 (VOID**)&PciIo 154 ); 155 PciIo->Pci.Read ( 156 PciIo, 157 EfiPciIoWidthUint32, 158 0, 159 sizeof (PciConfigHeader) / sizeof (UINT32), 160 &PciConfigHeader 161 ); 162 for (Index2 = 0; PciClasses[Index2].Class != 0xff; Index2++) { 163 if ((PciConfigHeader.Hdr.ClassCode[2] == PciClasses[Index2].Class) && 164 (PciConfigHeader.Hdr.ClassCode[1] == PciClasses[Index2].SubClass)) { 165 LegacyBios->CheckPciRom ( 166 LegacyBios, 167 HandleBuffer[Index], 168 NULL, 169 NULL, 170 &Flags 171 ); 172 173 // 174 // Verify that results of OPROM check match request. 175 // The two valid requests are: 176 // DeviceFlags = 0 require a valid legacy ROM 177 // DeviceFlags = 1 require either no ROM or a valid legacy ROM 178 // 179 if ( 180 ((DeviceFlags != 0) && (Flags == NO_ROM)) || 181 ((Flags & (ROM_FOUND | VALID_LEGACY_ROM)) == (ROM_FOUND | VALID_LEGACY_ROM)) 182 ) { 183 DeviceTable->Handle = HandleBuffer[Index]; 184 DeviceTable->Vid = PciConfigHeader.Hdr.VendorId; 185 DeviceTable->Did = PciConfigHeader.Hdr.DeviceId; 186 DeviceTable->SvId = PciConfigHeader.Device.SubsystemVendorID; 187 DeviceTable->SysId = PciConfigHeader.Device.SubsystemID; 188 ++ *DeviceIndex; 189 DeviceTable++; 190 } 191 } 192 } 193 } 194 195 // 196 // Free any allocated buffers 197 // 198 gBS->FreePool (HandleBuffer); 199 200 if (*DeviceIndex != StartIndex) { 201 return EFI_SUCCESS; 202 } else { 203 return EFI_NOT_FOUND; 204 } 205 } 206 207 /** 208 Load and initialize the Legacy BIOS SMM handler. 209 210 @param This The protocol instance pointer. 211 @param EfiToLegacy16BootTable A pointer to Legacy16 boot table. 212 213 @retval EFI_SUCCESS SMM code loaded. 214 @retval EFI_DEVICE_ERROR SMM code failed to load 215 216 **/ 217 EFI_STATUS 218 EFIAPI 219 SmmInit ( 220 IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, 221 IN VOID *EfiToLegacy16BootTable 222 ) 223 { 224 return EFI_SUCCESS; 225 } 226 227 /** 228 Finds the device path that should be used as the primary display adapter. 229 230 @param VgaHandle - The handle of the video device 231 232 **/ 233 VOID 234 GetSelectedVgaDeviceInfo ( 235 OUT EFI_HANDLE *VgaHandle 236 ) 237 { 238 EFI_STATUS Status; 239 UINTN HandleCount; 240 EFI_HANDLE *HandleBuffer; 241 UINTN Index; 242 EFI_PCI_IO_PROTOCOL *PciIo; 243 PCI_TYPE00 Pci; 244 UINT8 MinBus; 245 UINT8 MaxBus; 246 UINTN Segment; 247 UINTN Bus; 248 UINTN Device; 249 UINTN Function; 250 UINTN SelectedAddress; 251 UINTN CurrentAddress; 252 253 // 254 // Initialize return to 'not found' state 255 // 256 *VgaHandle = NULL; 257 258 // 259 // Initialize variable states. This is important for selecting the VGA 260 // device if multiple devices exist behind a single bridge. 261 // 262 HandleCount = 0; 263 HandleBuffer = NULL; 264 SelectedAddress = PCI_LIB_ADDRESS(0xff, 0x1f, 0x7, 0); 265 266 // 267 // The bus range to search for a VGA device in. 268 // 269 MinBus = MaxBus = 0; 270 271 // 272 // Start to check all the pci io to find all possible VGA device 273 // 274 HandleCount = 0; 275 HandleBuffer = NULL; 276 Status = gBS->LocateHandleBuffer ( 277 ByProtocol, 278 &gEfiPciIoProtocolGuid, 279 NULL, 280 &HandleCount, 281 &HandleBuffer 282 ); 283 if (EFI_ERROR (Status)) { 284 return; 285 } 286 287 for (Index = 0; Index < HandleCount; Index++) { 288 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID**)&PciIo); 289 if (!EFI_ERROR (Status)) { 290 // 291 // Detemine if this is in the correct bus range. 292 // 293 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function); 294 if (EFI_ERROR(Status) || (Bus < MinBus || Bus > MaxBus)) { 295 continue; 296 } 297 298 // 299 // Read device information. 300 // 301 Status = PciIo->Pci.Read ( 302 PciIo, 303 EfiPciIoWidthUint32, 304 0, 305 sizeof (Pci) / sizeof (UINT32), 306 &Pci 307 ); 308 if (EFI_ERROR (Status)) { 309 continue; 310 } 311 312 // 313 // Make sure the device is a VGA device. 314 // 315 if (!IS_PCI_VGA (&Pci)) { 316 continue; 317 } 318 DEBUG ((EFI_D_INFO, 319 "PCI VGA: 0x%04x:0x%04x\n", 320 Pci.Hdr.VendorId, 321 Pci.Hdr.DeviceId 322 )); 323 324 // 325 // Currently we use the lowest numbered bus/device/function if multiple 326 // devices are found in the target bus range. 327 // 328 CurrentAddress = PCI_LIB_ADDRESS(Bus, Device, Function, 0); 329 if (CurrentAddress < SelectedAddress) { 330 SelectedAddress = CurrentAddress; 331 *VgaHandle = HandleBuffer[Index]; 332 } 333 } 334 } 335 336 FreePool (HandleBuffer); 337 } 338 339 340 /** 341 Returns a buffer of handles for the requested subfunction. 342 343 @param This The protocol instance pointer. 344 @param Mode Specifies what handle to return. See EFI_GET_PLATFORM_HANDLE_MODE enum. 345 @param Type Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. 346 @param HandleBuffer Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. 347 @param HandleCount Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. 348 @param AdditionalData Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. 349 350 @retval EFI_SUCCESS Handle is valid. 351 @retval EFI_UNSUPPORTED Mode is not supported on the platform. 352 @retval EFI_NOT_FOUND Handle is not known. 353 354 **/ 355 EFI_STATUS 356 EFIAPI 357 GetPlatformHandle ( 358 IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, 359 IN EFI_GET_PLATFORM_HANDLE_MODE Mode, 360 IN UINT16 Type, 361 OUT EFI_HANDLE **HandleBuffer, 362 OUT UINTN *HandleCount, 363 OUT VOID **AdditionalData OPTIONAL 364 ) 365 { 366 DEVICE_STRUCTURE LocalDevice[0x40]; 367 UINT32 LocalIndex; 368 UINT32 Index; 369 DEVICE_STRUCTURE TempDevice; 370 EFI_STATUS Status; 371 EFI_PCI_IO_PROTOCOL *PciIo; 372 UINTN Segment; 373 UINTN Bus; 374 UINTN Device; 375 UINTN Function; 376 HDD_INFO *HddInfo; 377 PCI_TYPE00 PciConfigHeader; 378 UINT32 HddIndex; 379 EFI_HANDLE IdeHandle; 380 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 381 PCI_CLASS_RECORD ClassLists[10]; 382 UINTN PriorityIndex; 383 384 static BOOLEAN bConnected = FALSE; 385 386 LocalIndex = 0x00; 387 HddInfo = NULL; 388 HddIndex = 0; 389 390 Status = gBS->LocateProtocol ( 391 &gEfiLegacyBiosProtocolGuid, 392 NULL, 393 (VOID**)&LegacyBios 394 ); 395 396 // 397 // Process mode specific operations 398 // 399 switch (Mode) { 400 case EfiGetPlatformVgaHandle: 401 // 402 // Get the handle for the currently selected VGA device. 403 // 404 GetSelectedVgaDeviceInfo (&mVgaHandles[0]); 405 *HandleBuffer = &mVgaHandles[0]; 406 *HandleCount = (mVgaHandles[0] != NULL) ? 1 : 0; 407 return EFI_SUCCESS; 408 case EfiGetPlatformIdeHandle: 409 IdeHandle = NULL; 410 if (AdditionalData != NULL) { 411 HddInfo = (HDD_INFO *) *AdditionalData; 412 } 413 414 // 415 // Locate all found block io devices 416 // 417 ClassLists[0].Class = PCI_CLASS_MASS_STORAGE; 418 ClassLists[0].SubClass = PCI_CLASS_MASS_STORAGE_SCSI; 419 ClassLists[1].Class = PCI_CLASS_MASS_STORAGE; 420 ClassLists[1].SubClass = PCI_CLASS_MASS_STORAGE_IDE; 421 ClassLists[2].Class = PCI_CLASS_MASS_STORAGE; 422 ClassLists[2].SubClass = PCI_CLASS_MASS_STORAGE_RAID; 423 ClassLists[3].Class = PCI_CLASS_MASS_STORAGE; 424 ClassLists[3].SubClass = PCI_CLASS_MASS_STORAGE_SATADPA; 425 ClassLists[4].Class = 0xff; 426 FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) &LocalIndex, TRUE); 427 if (LocalIndex == 0) { 428 return EFI_NOT_FOUND; 429 } 430 431 // 432 // Make sure all IDE controllers are connected. This is necessary 433 // in NO_CONFIG_CHANGE boot path to ensure IDE controller is correctly 434 // initialized and all IDE drives are enumerated 435 // 436 if (!bConnected) { 437 for (Index = 0; Index < LocalIndex; Index++) { 438 gBS->ConnectController (LocalDevice[Index].Handle, NULL, NULL, TRUE); 439 } 440 } 441 442 // 443 // Locate onboard controllers. 444 // 445 for (Index = 0; Index < LocalIndex; Index++) { 446 if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) { 447 if (LocalDevice[Index].Did == V_PIIX4_IDE_DEVICE_ID) { 448 IdeHandle = LocalDevice[Index].Handle; 449 } 450 } 451 } 452 453 // 454 // Set the IDE contorller as primary devices. 455 // 456 PriorityIndex = 0; 457 for (Index = 0; Index < LocalIndex; Index++) { 458 if (LocalDevice[Index].Handle == IdeHandle && PriorityIndex == 0) { 459 TempDevice = LocalDevice[PriorityIndex]; 460 LocalDevice[PriorityIndex] = LocalDevice[Index]; 461 LocalDevice[Index] = TempDevice; 462 PriorityIndex++; 463 break; 464 } 465 } 466 467 // 468 // Copy over handles and update return values. 469 // 470 for (Index = 0; Index < LocalIndex; Index++) { 471 mDiskHandles[Index] = LocalDevice[Index].Handle; 472 } 473 *HandleBuffer = &mDiskHandles[0]; 474 *HandleCount = LocalIndex; 475 476 // 477 // We have connected all IDE controllers once. No more needed 478 // 479 bConnected = TRUE; 480 481 // 482 // Log all onboard controllers. 483 // 484 for (Index = 0; (Index < LocalIndex) && (AdditionalData != NULL); Index++) { 485 if ((LocalDevice[Index].Handle != NULL) && 486 (LocalDevice[Index].Handle == IdeHandle)) { 487 Status = gBS->HandleProtocol ( 488 LocalDevice[Index].Handle, 489 &gEfiPciIoProtocolGuid, 490 (VOID **) &PciIo 491 ); 492 PciIo->Pci.Read ( 493 PciIo, 494 EfiPciIoWidthUint32, 495 0, 496 sizeof (PciConfigHeader) / sizeof (UINT32), 497 &PciConfigHeader 498 ); 499 if (!EFI_ERROR (Status)) { 500 PciIo->GetLocation ( 501 PciIo, 502 &Segment, 503 &Bus, 504 &Device, 505 &Function 506 ); 507 508 // 509 // Be sure to only fill out correct information based on platform 510 // configureation. 511 // 512 HddInfo[HddIndex].Status |= HDD_PRIMARY; 513 HddInfo[HddIndex].Bus = (UINT32)Bus; 514 HddInfo[HddIndex].Device = (UINT32)Device; 515 HddInfo[HddIndex].Function = (UINT32)Function; 516 HddInfo[HddIndex + 1].Status |= HDD_SECONDARY; 517 HddInfo[HddIndex + 1].Bus = (UINT32)Bus; 518 HddInfo[HddIndex + 1].Device = (UINT32)Device; 519 HddInfo[HddIndex + 1].Function = (UINT32)Function; 520 521 // 522 // Primary controller data 523 // 524 if ((PciConfigHeader.Hdr.ClassCode[0] & 0x01) != 0) { 525 HddInfo[HddIndex].CommandBaseAddress = 526 (UINT16)(PciConfigHeader.Device.Bar[0] & 0xfffc); 527 HddInfo[HddIndex].ControlBaseAddress = 528 (UINT16)((PciConfigHeader.Device.Bar[1] & 0xfffc)+2); 529 HddInfo[HddIndex].BusMasterAddress = 530 (UINT16)(PciConfigHeader.Device.Bar[4] & 0xfffc); 531 HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine; 532 } else { 533 HddInfo[HddIndex].HddIrq = 14; 534 HddInfo[HddIndex].CommandBaseAddress = 0x1f0; 535 HddInfo[HddIndex].ControlBaseAddress = 0x3f6; 536 HddInfo[HddIndex].BusMasterAddress = 0; 537 } 538 HddIndex++; 539 540 // 541 // Secondary controller data 542 // 543 if ((PciConfigHeader.Hdr.ClassCode[0] & 0x04) != 0) { 544 HddInfo[HddIndex].CommandBaseAddress = 545 (UINT16)(PciConfigHeader.Device.Bar[2] & 0xfffc); 546 HddInfo[HddIndex].ControlBaseAddress = 547 (UINT16)((PciConfigHeader.Device.Bar[3] & 0xfffc)+2); 548 HddInfo[HddIndex].BusMasterAddress = 549 (UINT16)(HddInfo[HddIndex].BusMasterAddress + 8); 550 HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine; 551 } else { 552 HddInfo[HddIndex].HddIrq = 15; 553 HddInfo[HddIndex].CommandBaseAddress = 0x170; 554 HddInfo[HddIndex].ControlBaseAddress = 0x376; 555 HddInfo[HddIndex].BusMasterAddress = 0; 556 } 557 HddIndex++; 558 } 559 } 560 } 561 return EFI_SUCCESS; 562 case EfiGetPlatformIsaBusHandle: 563 ClassLists[0].Class = (UINT8) PCI_CLASS_BRIDGE; 564 ClassLists[0].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA_PDECODE; 565 ClassLists[1].Class = (UINT8) PCI_CLASS_BRIDGE; 566 ClassLists[1].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA; 567 ClassLists[2].Class = 0xff; 568 569 // 570 // Locate all found block io devices 571 // 572 FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) (&LocalIndex), TRUE); 573 if (LocalIndex == 0) { 574 return EFI_NOT_FOUND; 575 } 576 577 // 578 // Find our ISA bridge. 579 // 580 for (Index = 0; Index < LocalIndex; Index++) { 581 if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) { 582 TempDevice = LocalDevice[0]; 583 LocalDevice[0] = LocalDevice[Index]; 584 LocalDevice[Index] = TempDevice; 585 } 586 } 587 588 // 589 // Perform copy and update return values. 590 // 591 for (Index = 0; Index < LocalIndex; Index++) { 592 mIsaHandles[Index] = LocalDevice[Index].Handle; 593 } 594 *HandleBuffer = &mIsaHandles[0]; 595 *HandleCount = LocalIndex; 596 return EFI_SUCCESS; 597 case EfiGetPlatformUsbHandle: 598 default: 599 return EFI_UNSUPPORTED; 600 }; 601 } 602 603 /** 604 Allows platform to perform any required action after a LegacyBios operation. 605 Invokes the specific sub function specified by Mode. 606 607 @param This The protocol instance pointer. 608 @param Mode Specifies what handle to return. See EFI_GET_PLATFORM_HOOK_MODE enum. 609 @param Type Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. 610 @param DeviceHandle Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. 611 @param ShadowAddress Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. 612 @param Compatibility16Table Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. 613 @param AdditionalData Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. 614 615 @retval EFI_SUCCESS The operation performed successfully. Mode specific. 616 @retval EFI_UNSUPPORTED Mode is not supported on the platform. 617 618 **/ 619 EFI_STATUS 620 EFIAPI 621 PlatformHooks ( 622 IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, 623 IN EFI_GET_PLATFORM_HOOK_MODE Mode, 624 IN UINT16 Type, 625 OUT EFI_HANDLE DeviceHandle, OPTIONAL 626 IN OUT UINTN *Shadowaddress, OPTIONAL 627 IN EFI_COMPATIBILITY16_TABLE *Compatibility16Table, OPTIONAL 628 OUT VOID **AdditionalData OPTIONAL 629 ) 630 { 631 EFI_IA32_REGISTER_SET Regs; 632 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 633 EFI_STATUS Status; 634 635 switch (Mode) { 636 case EfiPlatformHookPrepareToScanRom: 637 Status = gBS->LocateProtocol ( 638 &gEfiLegacyBiosProtocolGuid, 639 NULL, 640 (VOID**)&LegacyBios 641 ); 642 643 // 644 // Set the 80x25 Text VGA Mode 645 // 646 Regs.H.AH = 0x00; 647 Regs.H.AL = 0x03; 648 Status = LegacyBios->Int86 (LegacyBios, 0x10, &Regs); 649 return Status; 650 case EfiPlatformHookShadowServiceRoms: 651 return EFI_SUCCESS; 652 case EfiPlatformHookAfterRomInit: 653 default: 654 return EFI_UNSUPPORTED; 655 }; 656 } 657 658 /** 659 Returns information associated with PCI IRQ routing. 660 This function returns the following information associated with PCI IRQ routing: 661 * An IRQ routing table and number of entries in the table. 662 * The $PIR table and its size. 663 * A list of PCI IRQs and the priority order to assign them. 664 665 @param This The protocol instance pointer. 666 @param RoutingTable The pointer to PCI IRQ Routing table. 667 This location is the $PIR table minus the header. 668 @param RoutingTableEntries The number of entries in table. 669 @param LocalPirqTable $PIR table. 670 @param PirqTableSize $PIR table size. 671 @param LocalIrqPriorityTable A list of interrupts in priority order to assign. 672 @param IrqPriorityTableEntries The number of entries in the priority table. 673 674 @retval EFI_SUCCESS Data was successfully returned. 675 676 **/ 677 EFI_STATUS 678 EFIAPI 679 GetRoutingTable ( 680 IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, 681 OUT VOID **RoutingTable, 682 OUT UINTN *RoutingTableEntries, 683 OUT VOID **LocalPirqTable, OPTIONAL 684 OUT UINTN *PirqTableSize, OPTIONAL 685 OUT VOID **LocalIrqPriorityTable, OPTIONAL 686 OUT UINTN *IrqPriorityTableEntries OPTIONAL 687 ) 688 { 689 UINT16 PTableSize; 690 UINT32 Index; 691 UINT8 Bus; 692 UINT8 Device; 693 UINT8 Function; 694 UINT8 Checksum; 695 UINT8 *Ptr; 696 EFI_STATUS Status; 697 EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt; 698 699 Checksum = 0; 700 701 if (LocalPirqTable != NULL) { 702 PTableSize = sizeof (EFI_LEGACY_PIRQ_TABLE_HEADER) + 703 sizeof (EFI_LEGACY_IRQ_ROUTING_ENTRY) * MAX_IRQ_ROUTING_ENTRIES; 704 705 Status = gBS->LocateProtocol ( 706 &gEfiLegacyInterruptProtocolGuid, 707 NULL, 708 (VOID**)&LegacyInterrupt 709 ); 710 ASSERT_EFI_ERROR (Status); 711 LegacyInterrupt->GetLocation ( 712 LegacyInterrupt, 713 &Bus, 714 &Device, 715 &Function 716 ); 717 718 // 719 // Update fields in $PIR table header 720 // 721 PirqTableHead.PirqTable.TableSize = PTableSize; 722 PirqTableHead.PirqTable.Bus = Bus; 723 PirqTableHead.PirqTable.DevFun = (UINT8) ((Device << 3) + Function); 724 Ptr = (UINT8 *) (&PirqTableHead); 725 726 // 727 // Calculate checksum. 728 // 729 for (Index = 0; Index < PTableSize; Index++) { 730 Checksum = (UINT8) (Checksum + (UINT8) *Ptr); 731 Ptr += 1; 732 } 733 Checksum = (UINT8) (0x00 - Checksum); 734 PirqTableHead.PirqTable.Checksum = Checksum; 735 736 // 737 // Update return values. 738 // 739 *LocalPirqTable = (VOID *) (&PirqTableHead); 740 *PirqTableSize = PTableSize; 741 } 742 743 // 744 // More items to return. 745 // 746 *RoutingTable = PirqTableHead.IrqRoutingEntry; 747 *RoutingTableEntries = MAX_IRQ_ROUTING_ENTRIES; 748 if (LocalIrqPriorityTable != NULL) { 749 *LocalIrqPriorityTable = IrqPriorityTable; 750 *IrqPriorityTableEntries = MAX_IRQ_PRIORITY_ENTRIES; 751 } 752 753 return EFI_SUCCESS; 754 } 755 756 /** 757 Finds the binary data or other platform information. 758 759 @param This The protocol instance pointer. 760 @param Mode Specifies what data to return. See See EFI_GET_PLATFORM_INFO_MODE enum. 761 @param Table Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. 762 @param TableSize Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. 763 @param Location Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. 764 @param Alignment Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. 765 @param LegacySegment Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. 766 @param LegacyOffset Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. 767 768 @retval EFI_SUCCESS Data returned successfully. 769 @retval EFI_UNSUPPORTED Mode is not supported on the platform. 770 @retval EFI_NOT_FOUND Binary image or table not found. 771 772 **/ 773 EFI_STATUS 774 EFIAPI 775 GetPlatformInfo ( 776 IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, 777 IN EFI_GET_PLATFORM_INFO_MODE Mode, 778 OUT VOID **Table, 779 OUT UINTN *TableSize, 780 OUT UINTN *Location, 781 OUT UINTN *Alignment, 782 IN UINT16 LegacySegment, 783 IN UINT16 LegacyOffset 784 ) 785 { 786 EFI_STATUS Status; 787 UINTN Index; 788 789 switch (Mode) { 790 case EfiGetPlatformBinarySystemRom: 791 // 792 // Loop through table of System rom descriptions 793 // 794 for (Index = 0; mSystemRomTable[Index].Valid != 0; Index++) { 795 Status = GetSectionFromFv ( 796 &mSystemRomTable[Index].FileName, 797 EFI_SECTION_RAW, 798 0, 799 Table, 800 (UINTN *) TableSize 801 ); 802 if (EFI_ERROR (Status)) { 803 continue; 804 } 805 return EFI_SUCCESS; 806 } 807 808 return EFI_NOT_FOUND; 809 case EfiGetPlatformBinaryOem16Data: 810 case EfiGetPlatformBinaryMpTable: 811 case EfiGetPlatformBinaryOemIntData: 812 case EfiGetPlatformBinaryOem32Data: 813 case EfiGetPlatformBinaryTpmBinary: 814 case EfiGetPlatformPciExpressBase: 815 default: 816 return EFI_UNSUPPORTED; 817 }; 818 } 819 820 /** 821 Translates the given PIRQ accounting for bridge. 822 This function translates the given PIRQ back through all buses, if required, 823 and returns the true PIRQ and associated IRQ. 824 825 @param This The protocol instance pointer. 826 @param PciBus The PCI bus number for this device. 827 @param PciDevice The PCI device number for this device. 828 @param PciFunction The PCI function number for this device. 829 @param Pirq Input is PIRQ reported by device, and output is true PIRQ. 830 @param PciIrq The IRQ already assigned to the PIRQ, or the IRQ to be 831 assigned to the PIRQ. 832 833 @retval EFI_SUCCESS The PIRQ was translated. 834 835 **/ 836 EFI_STATUS 837 EFIAPI 838 TranslatePirq ( 839 IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, 840 IN UINTN PciBus, 841 IN UINTN PciDevice, 842 IN UINTN PciFunction, 843 IN OUT UINT8 *Pirq, 844 OUT UINT8 *PciIrq 845 ) 846 { 847 EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt; 848 EFI_STATUS Status; 849 UINTN Index; 850 UINTN Index1; 851 UINT8 LocalPirq; 852 UINT8 PirqData; 853 UINT8 MatchData; 854 855 Status = gBS->LocateProtocol ( 856 &gEfiLegacyInterruptProtocolGuid, 857 NULL, 858 (VOID**)&LegacyInterrupt 859 ); 860 ASSERT_EFI_ERROR (Status); 861 LocalPirq = (UINT8) (*Pirq); 862 863 for (Index = 0; Index < MAX_IRQ_ROUTING_ENTRIES; Index++) { 864 if ((PirqTableHead.IrqRoutingEntry[Index].Bus == PciBus) && 865 (PirqTableHead.IrqRoutingEntry[Index].Device == PciDevice)) { 866 LocalPirq = (UINT8) (PirqTableHead.IrqRoutingEntry[Index].PirqEntry[LocalPirq].Pirq & 0x0f); 867 if (LocalPirq > 4) { 868 LocalPirq -= 4; 869 } 870 871 LegacyInterrupt->ReadPirq (LegacyInterrupt, LocalPirq, &PirqData); 872 MatchData = PCI_UNUSED; 873 while (PirqData == 0) { 874 for (Index1 = 0; Index1 < MAX_IRQ_PRIORITY_ENTRIES; Index1++) { 875 if ((IrqPriorityTable[Index1].Used == MatchData) && 876 (IrqPriorityTable[Index1].Irq != 0)) { 877 PirqData = IrqPriorityTable[Index1].Irq; 878 IrqPriorityTable[Index1].Used = 0xff; 879 LegacyInterrupt->WritePirq ( 880 LegacyInterrupt, 881 LocalPirq, 882 PirqData 883 ); 884 break; 885 } 886 } 887 888 if (PirqData == 0) { 889 890 // 891 // No unused interrpts, so start reusing them. 892 // 893 MatchData = (UINT8) (~MatchData); 894 } 895 } 896 897 *PciIrq = PirqData; 898 *Pirq = LocalPirq; 899 } 900 } 901 902 return EFI_SUCCESS; 903 } 904 905 906 /** 907 Attempt to legacy boot the BootOption. If the EFI contexted has been 908 compromised this function will not return. 909 910 @param This The protocol instance pointer. 911 @param BbsDevicePath The EFI Device Path from BootXXXX variable. 912 @param BbsTable The Internal BBS table. 913 @param LoadOptionSize The size of LoadOption in size. 914 @param LoadOption The LoadOption from BootXXXX variable 915 @param EfiToLegacy16BootTable A pointer to BootTable structure 916 917 @retval EFI_SUCCESS Ready to boot. 918 919 **/ 920 EFI_STATUS 921 EFIAPI 922 PrepareToBoot ( 923 IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, 924 IN BBS_BBS_DEVICE_PATH *BbsDevicePath, 925 IN VOID *BbsTable, 926 IN UINT32 LoadOptionsSize, 927 IN VOID *LoadOptions, 928 IN VOID *EfiToLegacy16BootTable 929 ) 930 { 931 BBS_TABLE *LocalBbsTable; 932 EFI_TO_COMPATIBILITY16_BOOT_TABLE *Legacy16BootTable; 933 DEVICE_PRODUCER_DATA_HEADER *SioPtr; 934 UINT16 DevicePathType; 935 UINT16 Index; 936 UINT16 Priority; 937 938 // 939 // Initialize values 940 // 941 Priority = 0; 942 Legacy16BootTable = (EFI_TO_COMPATIBILITY16_BOOT_TABLE*) EfiToLegacy16BootTable; 943 944 // 945 // Set how Gate A20 is gated by hardware 946 // 947 SioPtr = &Legacy16BootTable->SioData; 948 SioPtr->Flags.A20Kybd = 1; 949 SioPtr->Flags.A20Port90 = 1; 950 SioPtr->MousePresent = 1; 951 952 LocalBbsTable = BbsTable; 953 954 // 955 // There are 2 cases that must be covered. 956 // Case 1: Booting to a legacy OS - BbsDevicePath is non-NULL. 957 // Case 2: Booting to an EFI aware OS - BbsDevicePath is NULL. 958 // We need to perform the PrepareToBoot function to assign 959 // drive numbers to HDD devices to allow the shell or EFI 960 // to access them. 961 // 962 if (BbsDevicePath != NULL) { 963 DevicePathType = BbsDevicePath->DeviceType; 964 } else { 965 DevicePathType = BBS_HARDDISK; 966 } 967 968 // 969 // Skip the boot devices where priority is set by BDS and set the next one 970 // 971 for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { 972 if ((LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) && 973 (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY) && 974 (LocalBbsTable[Index].BootPriority != BBS_LOWEST_PRIORITY) && 975 (Priority <= LocalBbsTable[Index].BootPriority)) { 976 Priority = (UINT16) (LocalBbsTable[Index].BootPriority + 1); 977 } 978 } 979 980 switch (DevicePathType) { 981 case BBS_FLOPPY: 982 case BBS_HARDDISK: 983 case BBS_CDROM: 984 case BBS_EMBED_NETWORK: 985 for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { 986 if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) && 987 (LocalBbsTable[Index].DeviceType == DevicePathType)) { 988 LocalBbsTable[Index].BootPriority = Priority; 989 ++Priority; 990 } 991 } 992 break; 993 case BBS_BEV_DEVICE: 994 for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { 995 if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) && 996 (LocalBbsTable[Index].Class == 01) && 997 (LocalBbsTable[Index].SubClass == 01)) { 998 LocalBbsTable[Index].BootPriority = Priority; 999 ++Priority; 1000 } 1001 } 1002 break; 1003 case BBS_USB: 1004 case BBS_PCMCIA: 1005 case BBS_UNKNOWN: 1006 default: 1007 break; 1008 }; 1009 1010 // 1011 // Set priority for rest of devices 1012 // 1013 for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { 1014 if (LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) { 1015 LocalBbsTable[Index].BootPriority = Priority; 1016 ++Priority; 1017 } 1018 } 1019 1020 return EFI_SUCCESS; 1021 } 1022 1023 1024 /** 1025 Initialize Legacy Platform support 1026 1027 @retval EFI_SUCCESS Successfully initialized 1028 1029 **/ 1030 EFI_STATUS 1031 LegacyBiosPlatformInstall ( 1032 VOID 1033 ) 1034 { 1035 EFI_STATUS Status; 1036 LEGACY_BIOS_PLATFORM_INSTANCE *Private; 1037 1038 mImageHandle = gImageHandle; 1039 Private = &mPrivateData; 1040 1041 // 1042 // Grab a copy of all the protocols we depend on. 1043 // 1044 Private->Signature = LEGACY_BIOS_PLATFORM_INSTANCE_SIGNATURE; 1045 Private->LegacyBiosPlatform.GetPlatformInfo = GetPlatformInfo; 1046 Private->LegacyBiosPlatform.GetPlatformHandle = GetPlatformHandle; 1047 Private->LegacyBiosPlatform.SmmInit = SmmInit; 1048 Private->LegacyBiosPlatform.PlatformHooks = PlatformHooks; 1049 Private->LegacyBiosPlatform.GetRoutingTable = GetRoutingTable; 1050 Private->LegacyBiosPlatform.TranslatePirq = TranslatePirq; 1051 Private->LegacyBiosPlatform.PrepareToBoot = PrepareToBoot; 1052 Private->ImageHandle = gImageHandle; 1053 1054 // 1055 // Make a new handle and install the protocol 1056 // 1057 Private->Handle = NULL; 1058 Status = gBS->InstallProtocolInterface ( 1059 &Private->Handle, 1060 &gEfiLegacyBiosPlatformProtocolGuid, 1061 EFI_NATIVE_INTERFACE, 1062 &Private->LegacyBiosPlatform 1063 ); 1064 return Status; 1065 } 1066 1067