LegacyBootSupport.c revision 81c0d6e9a7f78bb43e9a1045ea084e728fa76983
1/** @file 2 3Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> 4 5This program and the accompanying materials 6are licensed and made available under the terms and conditions 7of the BSD License which accompanies this distribution. The 8full text of the license may be found at 9http://opensource.org/licenses/bsd-license.php 10 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15 16#include "LegacyBiosInterface.h" 17#include <IndustryStandard/Pci.h> 18 19#define BOOT_LEGACY_OS 0 20#define BOOT_EFI_OS 1 21#define BOOT_UNCONVENTIONAL_DEVICE 2 22 23UINT32 mLoadOptionsSize = 0; 24UINTN mBootMode = BOOT_LEGACY_OS; 25VOID *mLoadOptions = NULL; 26BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL; 27BBS_BBS_DEVICE_PATH mBbsDevicePathNode; 28UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 }; 29UINTN mBbsEntry = 0; 30VOID *mBeerData = NULL; 31VOID *mServiceAreaData = NULL; 32UINT64 mLowWater = 0xffffffffffffffffULL; 33 34extern BBS_TABLE *mBbsTable; 35 36/** 37 Print the BBS Table. 38 39 @param BbsTable The BBS table. 40 41 42**/ 43VOID 44PrintBbsTable ( 45 IN BBS_TABLE *BbsTable 46 ) 47{ 48 UINT16 Index; 49 UINT16 SubIndex; 50 CHAR8 *String; 51 52 DEBUG ((EFI_D_INFO, "\n")); 53 DEBUG ((EFI_D_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n")); 54 DEBUG ((EFI_D_INFO, "=================================================================\n")); 55 for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) { 56 // 57 // Filter 58 // 59 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { 60 continue; 61 } 62 63 DEBUG (( 64 EFI_D_INFO, 65 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x", 66 (UINTN) Index, 67 (UINTN) BbsTable[Index].BootPriority, 68 (UINTN) BbsTable[Index].Bus, 69 (UINTN) BbsTable[Index].Device, 70 (UINTN) BbsTable[Index].Function, 71 (UINTN) BbsTable[Index].Class, 72 (UINTN) BbsTable[Index].SubClass, 73 (UINTN) BbsTable[Index].DeviceType, 74 (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags 75 )); 76 DEBUG (( 77 EFI_D_INFO, 78 " %04x:%04x %04x:%04x %04x:%04x", 79 (UINTN) BbsTable[Index].BootHandlerSegment, 80 (UINTN) BbsTable[Index].BootHandlerOffset, 81 (UINTN) BbsTable[Index].MfgStringSegment, 82 (UINTN) BbsTable[Index].MfgStringOffset, 83 (UINTN) BbsTable[Index].DescStringSegment, 84 (UINTN) BbsTable[Index].DescStringOffset 85 )); 86 87 // 88 // Print DescString 89 // 90 String = (CHAR8 *)(UINTN)((BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset); 91 if (String != NULL) { 92 DEBUG ((EFI_D_INFO," (")); 93 for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) { 94 DEBUG ((EFI_D_INFO, "%c", String[SubIndex])); 95 } 96 DEBUG ((EFI_D_INFO,")")); 97 } 98 DEBUG ((EFI_D_INFO,"\n")); 99 } 100 101 DEBUG ((EFI_D_INFO, "\n")); 102 103 return ; 104} 105 106/** 107 Print the BBS Table. 108 109 @param HddInfo The HddInfo table. 110 111 112**/ 113VOID 114PrintHddInfo ( 115 IN HDD_INFO *HddInfo 116 ) 117{ 118 UINTN Index; 119 120 DEBUG ((EFI_D_INFO, "\n")); 121 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { 122 DEBUG ((EFI_D_INFO, "Index - %04x\n", Index)); 123 DEBUG ((EFI_D_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status)); 124 DEBUG ((EFI_D_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function)); 125 DEBUG ((EFI_D_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress)); 126 DEBUG ((EFI_D_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress)); 127 DEBUG ((EFI_D_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress)); 128 DEBUG ((EFI_D_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq)); 129 DEBUG ((EFI_D_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0])); 130 DEBUG ((EFI_D_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0])); 131 } 132 133 DEBUG ((EFI_D_INFO, "\n")); 134 135 return ; 136} 137 138/** 139 Print the PCI Interrupt Line and Interrupt Pin registers. 140**/ 141VOID 142PrintPciInterruptRegister ( 143 VOID 144 ) 145{ 146 EFI_STATUS Status; 147 UINTN Index; 148 EFI_HANDLE *Handles; 149 UINTN HandleNum; 150 EFI_PCI_IO_PROTOCOL *PciIo; 151 UINT8 Interrupt[2]; 152 UINTN Segment; 153 UINTN Bus; 154 UINTN Device; 155 UINTN Function; 156 157 gBS->LocateHandleBuffer ( 158 ByProtocol, 159 &gEfiPciIoProtocolGuid, 160 NULL, 161 &HandleNum, 162 &Handles 163 ); 164 165 Bus = 0; 166 Device = 0; 167 Function = 0; 168 169 DEBUG ((EFI_D_INFO, "\n")); 170 DEBUG ((EFI_D_INFO, " bb/dd/ff interrupt line interrupt pin\n")); 171 DEBUG ((EFI_D_INFO, "======================================\n")); 172 for (Index = 0; Index < HandleNum; Index++) { 173 Status = gBS->HandleProtocol (Handles[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo); 174 if (!EFI_ERROR (Status)) { 175 Status = PciIo->Pci.Read ( 176 PciIo, 177 EfiPciIoWidthUint8, 178 PCI_INT_LINE_OFFSET, 179 2, 180 Interrupt 181 ); 182 } 183 if (!EFI_ERROR (Status)) { 184 Status = PciIo->GetLocation ( 185 PciIo, 186 &Segment, 187 &Bus, 188 &Device, 189 &Function 190 ); 191 } 192 if (!EFI_ERROR (Status)) { 193 DEBUG ((EFI_D_INFO, " %02x/%02x/%02x 0x%02x 0x%02x\n", 194 Bus, Device, Function, Interrupt[0], Interrupt[1])); 195 } 196 } 197 DEBUG ((EFI_D_INFO, "\n")); 198 199 if (Handles != NULL) { 200 FreePool (Handles); 201 } 202} 203 204/** 205 Identify drive data must be updated to actual parameters before boot. 206 207 @param IdentifyDriveData ATA Identify Data 208 209**/ 210VOID 211UpdateIdentifyDriveData ( 212 IN UINT8 *IdentifyDriveData 213 ); 214 215/** 216 Update SIO data. 217 218 @param Private Legacy BIOS Instance data 219 220 @retval EFI_SUCCESS Removable media not present 221 222**/ 223EFI_STATUS 224UpdateSioData ( 225 IN LEGACY_BIOS_INSTANCE *Private 226 ) 227{ 228 EFI_STATUS Status; 229 UINTN Index; 230 UINTN Index1; 231 UINT8 LegacyInterrupts[16]; 232 EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable; 233 UINTN RoutingTableEntries; 234 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable; 235 UINTN NumberPriorityEntries; 236 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; 237 UINT8 HddIrq; 238 UINT16 LegacyInt; 239 UINT16 LegMask; 240 UINT32 Register; 241 UINTN HandleCount; 242 EFI_HANDLE *HandleBuffer; 243 EFI_ISA_IO_PROTOCOL *IsaIo; 244 245 LegacyInt = 0; 246 HandleBuffer = NULL; 247 248 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; 249 LegacyBiosBuildSioData (Private); 250 SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0); 251 252 // 253 // Create list of legacy interrupts. 254 // 255 for (Index = 0; Index < 4; Index++) { 256 LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq; 257 } 258 259 for (Index = 4; Index < 7; Index++) { 260 LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq; 261 } 262 263 LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq; 264 265 // 266 // Get Legacy Hdd IRQs. If native mode treat as PCI 267 // 268 for (Index = 0; Index < 2; Index++) { 269 HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq; 270 if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) { 271 LegacyInterrupts[Index + 8] = HddIrq; 272 } 273 } 274 275 Private->LegacyBiosPlatform->GetRoutingTable ( 276 Private->LegacyBiosPlatform, 277 (VOID *) &RoutingTable, 278 &RoutingTableEntries, 279 NULL, 280 NULL, 281 (VOID **) &IrqPriorityTable, 282 &NumberPriorityEntries 283 ); 284 // 285 // Remove legacy interrupts from the list of PCI interrupts available. 286 // 287 for (Index = 0; Index <= 0x0b; Index++) { 288 for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) { 289 if (LegacyInterrupts[Index] != 0) { 290 LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index])); 291 if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) { 292 IrqPriorityTable[Index1].Used = LEGACY_USED; 293 } 294 } 295 } 296 } 297 298 Private->Legacy8259->GetMask ( 299 Private->Legacy8259, 300 &LegMask, 301 NULL, 302 NULL, 303 NULL 304 ); 305 306 // 307 // Set SIO interrupts and disable mouse. Let mouse driver 308 // re-enable it. 309 // 310 LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000); 311 Private->Legacy8259->SetMask ( 312 Private->Legacy8259, 313 &LegMask, 314 NULL, 315 NULL, 316 NULL 317 ); 318 319 // 320 // Disable mouse in keyboard controller 321 // 322 Register = 0xA7; 323 Status = gBS->LocateHandleBuffer ( 324 ByProtocol, 325 &gEfiIsaIoProtocolGuid, 326 NULL, 327 &HandleCount, 328 &HandleBuffer 329 ); 330 if (EFI_ERROR (Status)) { 331 return Status; 332 } 333 334 for (Index = 0; Index < HandleCount; Index++) { 335 Status = gBS->HandleProtocol ( 336 HandleBuffer[Index], 337 &gEfiIsaIoProtocolGuid, 338 (VOID **) &IsaIo 339 ); 340 ASSERT_EFI_ERROR (Status); 341 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register); 342 343 } 344 345 if (HandleBuffer != NULL) { 346 FreePool (HandleBuffer); 347 } 348 349 return EFI_SUCCESS; 350 351} 352 353/** 354 Identify drive data must be updated to actual parameters before boot. 355 This requires updating the checksum, if it exists. 356 357 @param IdentifyDriveData ATA Identify Data 358 @param Checksum checksum of the ATA Identify Data 359 360 @retval EFI_SUCCESS checksum calculated 361 @retval EFI_SECURITY_VIOLATION IdentifyData invalid 362 363**/ 364EFI_STATUS 365CalculateIdentifyDriveChecksum ( 366 IN UINT8 *IdentifyDriveData, 367 OUT UINT8 *Checksum 368 ) 369{ 370 UINTN Index; 371 UINT8 LocalChecksum; 372 LocalChecksum = 0; 373 *Checksum = 0; 374 if (IdentifyDriveData[510] != 0xA5) { 375 return EFI_SECURITY_VIOLATION; 376 } 377 378 for (Index = 0; Index < 512; Index++) { 379 LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]); 380 } 381 382 *Checksum = LocalChecksum; 383 return EFI_SUCCESS; 384} 385 386 387/** 388 Identify drive data must be updated to actual parameters before boot. 389 390 @param IdentifyDriveData ATA Identify Data 391 392 393**/ 394VOID 395UpdateIdentifyDriveData ( 396 IN UINT8 *IdentifyDriveData 397 ) 398{ 399 UINT16 NumberCylinders; 400 UINT16 NumberHeads; 401 UINT16 NumberSectorsTrack; 402 UINT32 CapacityInSectors; 403 UINT8 OriginalChecksum; 404 UINT8 FinalChecksum; 405 EFI_STATUS Status; 406 ATAPI_IDENTIFY *ReadInfo; 407 408 // 409 // Status indicates if Integrity byte is correct. Checksum should be 410 // 0 if valid. 411 // 412 ReadInfo = (ATAPI_IDENTIFY *) IdentifyDriveData; 413 Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum); 414 if (OriginalChecksum != 0) { 415 Status = EFI_SECURITY_VIOLATION; 416 } 417 // 418 // If NumberCylinders = 0 then do data(Controller present but don drive attached). 419 // 420 NumberCylinders = ReadInfo->Raw[1]; 421 if (NumberCylinders != 0) { 422 ReadInfo->Raw[54] = NumberCylinders; 423 424 NumberHeads = ReadInfo->Raw[3]; 425 ReadInfo->Raw[55] = NumberHeads; 426 427 NumberSectorsTrack = ReadInfo->Raw[6]; 428 ReadInfo->Raw[56] = NumberSectorsTrack; 429 430 // 431 // Copy Multisector info and set valid bit. 432 // 433 ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100); 434 CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack)); 435 ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16); 436 ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff); 437 if (Status == EFI_SUCCESS) { 438 // 439 // Forece checksum byte to 0 and get new checksum. 440 // 441 ReadInfo->Raw[255] &= 0xff; 442 CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum); 443 444 // 445 // Force new checksum such that sum is 0. 446 // 447 FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum); 448 ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8)); 449 } 450 } 451} 452 453/** 454 Identify drive data must be updated to actual parameters before boot. 455 Do for all drives. 456 457 @param Private Legacy BIOS Instance data 458 459 460**/ 461VOID 462UpdateAllIdentifyDriveData ( 463 IN LEGACY_BIOS_INSTANCE *Private 464 ) 465{ 466 UINTN Index; 467 HDD_INFO *HddInfo; 468 469 HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0]; 470 471 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { 472 // 473 // Each controller can have 2 devices. Update for each device 474 // 475 if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) { 476 UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0])); 477 } 478 479 if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) { 480 UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0])); 481 } 482 } 483} 484 485/** 486 Enable ide controller. This gets disabled when LegacyBoot.c is about 487 to run the Option ROMs. 488 489 @param Private Legacy BIOS Instance data 490 491 492**/ 493VOID 494EnableIdeController ( 495 IN LEGACY_BIOS_INSTANCE *Private 496 ) 497{ 498 EFI_PCI_IO_PROTOCOL *PciIo; 499 EFI_STATUS Status; 500 EFI_HANDLE IdeController; 501 UINT8 ByteBuffer; 502 UINTN HandleCount; 503 EFI_HANDLE *HandleBuffer; 504 505 Status = Private->LegacyBiosPlatform->GetPlatformHandle ( 506 Private->LegacyBiosPlatform, 507 EfiGetPlatformIdeHandle, 508 0, 509 &HandleBuffer, 510 &HandleCount, 511 NULL 512 ); 513 if (!EFI_ERROR (Status)) { 514 IdeController = HandleBuffer[0]; 515 Status = gBS->HandleProtocol ( 516 IdeController, 517 &gEfiPciIoProtocolGuid, 518 (VOID **) &PciIo 519 ); 520 ByteBuffer = 0x1f; 521 if (!EFI_ERROR (Status)) { 522 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer); 523 } 524 } 525} 526 527 528/** 529 Enable ide controller. This gets disabled when LegacyBoot.c is about 530 to run the Option ROMs. 531 532 @param Private Legacy BIOS Instance data 533 534 535**/ 536VOID 537EnableAllControllers ( 538 IN LEGACY_BIOS_INSTANCE *Private 539 ) 540{ 541 UINTN HandleCount; 542 EFI_HANDLE *HandleBuffer; 543 UINTN Index; 544 EFI_PCI_IO_PROTOCOL *PciIo; 545 PCI_TYPE01 PciConfigHeader; 546 EFI_STATUS Status; 547 548 // 549 // 550 // 551 EnableIdeController (Private); 552 553 // 554 // Assumption is table is built from low bus to high bus numbers. 555 // 556 Status = gBS->LocateHandleBuffer ( 557 ByProtocol, 558 &gEfiPciIoProtocolGuid, 559 NULL, 560 &HandleCount, 561 &HandleBuffer 562 ); 563 ASSERT_EFI_ERROR (Status); 564 565 for (Index = 0; Index < HandleCount; Index++) { 566 Status = gBS->HandleProtocol ( 567 HandleBuffer[Index], 568 &gEfiPciIoProtocolGuid, 569 (VOID **) &PciIo 570 ); 571 ASSERT_EFI_ERROR (Status); 572 573 PciIo->Pci.Read ( 574 PciIo, 575 EfiPciIoWidthUint32, 576 0, 577 sizeof (PciConfigHeader) / sizeof (UINT32), 578 &PciConfigHeader 579 ); 580 581 // 582 // We do not enable PPB here. This is for HotPlug Consideration. 583 // The Platform HotPlug Driver is responsible for Padding enough hot plug 584 // resources. It is also responsible for enable this bridge. If it 585 // does not pad it. It will cause some early Windows fail to installation. 586 // If the platform driver does not pad resource for PPB, PPB should be in 587 // un-enabled state to let Windows know that this PPB is not configured by 588 // BIOS. So Windows will allocate default resource for PPB. 589 // 590 // The reason for why we enable the command register is: 591 // The CSM will use the IO bar to detect some IRQ status, if the command 592 // is disabled, the IO resource will be out of scope. 593 // For example: 594 // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ 595 // comes up, the handle will check the IO space to identify is the 596 // controller generated the IRQ source. 597 // If the IO command is not enabled, the IRQ handler will has wrong 598 // information. It will cause IRQ storm when the correctly IRQ handler fails 599 // to run. 600 // 601 if (!(IS_PCI_VGA (&PciConfigHeader) || 602 IS_PCI_OLD_VGA (&PciConfigHeader) || 603 IS_PCI_IDE (&PciConfigHeader) || 604 IS_PCI_P2P (&PciConfigHeader) || 605 IS_PCI_P2P_SUB (&PciConfigHeader) || 606 IS_PCI_LPC (&PciConfigHeader) )) { 607 608 PciConfigHeader.Hdr.Command |= 0x1f; 609 610 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command); 611 } 612 } 613} 614 615/** 616 The following routines are identical in operation, so combine 617 for code compaction: 618 EfiGetPlatformBinaryGetMpTable 619 EfiGetPlatformBinaryGetOemIntData 620 EfiGetPlatformBinaryGetOem32Data 621 EfiGetPlatformBinaryGetOem16Data 622 623 @param This Protocol instance pointer. 624 @param Id Table/Data identifier 625 626 @retval EFI_SUCCESS Success 627 @retval EFI_INVALID_PARAMETER Invalid ID 628 @retval EFI_OUT_OF_RESOURCES no resource to get data or table 629 630**/ 631EFI_STATUS 632LegacyGetDataOrTable ( 633 IN EFI_LEGACY_BIOS_PROTOCOL *This, 634 IN EFI_GET_PLATFORM_INFO_MODE Id 635 ) 636{ 637 VOID *Table; 638 UINT32 TablePtr; 639 UINTN TableSize; 640 UINTN Alignment; 641 UINTN Location; 642 EFI_STATUS Status; 643 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; 644 EFI_COMPATIBILITY16_TABLE *Legacy16Table; 645 EFI_IA32_REGISTER_SET Regs; 646 LEGACY_BIOS_INSTANCE *Private; 647 648 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); 649 650 LegacyBiosPlatform = Private->LegacyBiosPlatform; 651 Legacy16Table = Private->Legacy16Table; 652 653 // 654 // Phase 1 - get an address allocated in 16-bit code 655 // 656 while (TRUE) { 657 switch (Id) { 658 case EfiGetPlatformBinaryMpTable: 659 case EfiGetPlatformBinaryOemIntData: 660 case EfiGetPlatformBinaryOem32Data: 661 case EfiGetPlatformBinaryOem16Data: 662 { 663 Status = LegacyBiosPlatform->GetPlatformInfo ( 664 LegacyBiosPlatform, 665 Id, 666 (VOID *) &Table, 667 &TableSize, 668 &Location, 669 &Alignment, 670 0, 671 0 672 ); 673 DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status)); 674 DEBUG ((EFI_D_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment)); 675 break; 676 } 677 678 default: 679 { 680 return EFI_INVALID_PARAMETER; 681 } 682 } 683 684 if (EFI_ERROR (Status)) { 685 return Status; 686 } 687 688 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); 689 Regs.X.AX = Legacy16GetTableAddress; 690 Regs.X.CX = (UINT16) TableSize; 691 Regs.X.BX = (UINT16) Location; 692 Regs.X.DX = (UINT16) Alignment; 693 Private->LegacyBios.FarCall86 ( 694 This, 695 Private->Legacy16CallSegment, 696 Private->Legacy16CallOffset, 697 &Regs, 698 NULL, 699 0 700 ); 701 702 if (Regs.X.AX != 0) { 703 DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id)); 704 return EFI_OUT_OF_RESOURCES; 705 } else { 706 break; 707 } 708 } 709 // 710 // Phase 2 Call routine second time with address to allow address adjustment 711 // 712 Status = LegacyBiosPlatform->GetPlatformInfo ( 713 LegacyBiosPlatform, 714 Id, 715 (VOID *) &Table, 716 &TableSize, 717 &Location, 718 &Alignment, 719 Regs.X.DS, 720 Regs.X.BX 721 ); 722 switch (Id) { 723 case EfiGetPlatformBinaryMpTable: 724 { 725 Legacy16Table->MpTablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); 726 Legacy16Table->MpTableLength = (UINT32)TableSize; 727 DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr)); 728 break; 729 } 730 731 case EfiGetPlatformBinaryOemIntData: 732 { 733 734 Legacy16Table->OemIntSegment = Regs.X.DS; 735 Legacy16Table->OemIntOffset = Regs.X.BX; 736 DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset)); 737 break; 738 } 739 740 case EfiGetPlatformBinaryOem32Data: 741 { 742 Legacy16Table->Oem32Segment = Regs.X.DS; 743 Legacy16Table->Oem32Offset = Regs.X.BX; 744 DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset)); 745 break; 746 } 747 748 case EfiGetPlatformBinaryOem16Data: 749 { 750 // 751 // Legacy16Table->Oem16Segment = Regs.X.DS; 752 // Legacy16Table->Oem16Offset = Regs.X.BX; 753 DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset)); 754 break; 755 } 756 757 default: 758 { 759 return EFI_INVALID_PARAMETER; 760 } 761 } 762 763 if (EFI_ERROR (Status)) { 764 return Status; 765 } 766 // 767 // Phase 3 Copy table to final location 768 // 769 TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); 770 771 CopyMem ( 772 (VOID *) (UINTN)TablePtr, 773 Table, 774 TableSize 775 ); 776 777 return EFI_SUCCESS; 778} 779 780 781/** 782 Assign drive number to legacy HDD drives prior to booting an EFI 783 aware OS so the OS can access drives without an EFI driver. 784 Note: BBS compliant drives ARE NOT available until this call by 785 either shell or EFI. 786 787 @param This Protocol instance pointer. 788 789 @retval EFI_SUCCESS Drive numbers assigned 790 791**/ 792EFI_STATUS 793GenericLegacyBoot ( 794 IN EFI_LEGACY_BIOS_PROTOCOL *This 795 ) 796{ 797 EFI_STATUS Status; 798 LEGACY_BIOS_INSTANCE *Private; 799 EFI_IA32_REGISTER_SET Regs; 800 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; 801 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; 802 UINTN CopySize; 803 VOID *AcpiPtr; 804 HDD_INFO *HddInfo; 805 HDD_INFO *LocalHddInfo; 806 UINTN Index; 807 EFI_COMPATIBILITY16_TABLE *Legacy16Table; 808 UINT32 *BdaPtr; 809 UINT16 HddCount; 810 UINT16 BbsCount; 811 BBS_TABLE *LocalBbsTable; 812 UINT32 *BaseVectorMaster; 813 EFI_TIME BootTime; 814 UINT32 LocalTime; 815 EFI_HANDLE IdeController; 816 UINTN HandleCount; 817 EFI_HANDLE *HandleBuffer; 818 VOID *SmbiosTable; 819 VOID *AcpiTable; 820 UINTN ShadowAddress; 821 UINT32 Granularity; 822 823 LocalHddInfo = NULL; 824 HddCount = 0; 825 BbsCount = 0; 826 LocalBbsTable = NULL; 827 828 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); 829 DEBUG_CODE ( 830 DEBUG ((EFI_D_ERROR, "Start of legacy boot\n")); 831 ); 832 833 Legacy16Table = Private->Legacy16Table; 834 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; 835 HddInfo = &EfiToLegacy16BootTable->HddInfo[0]; 836 837 LegacyBiosPlatform = Private->LegacyBiosPlatform; 838 839 EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION; 840 EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION; 841 842 // 843 // If booting to a legacy OS then force HDD drives to the appropriate 844 // boot mode by calling GetIdeHandle. 845 // A reconnect -r can force all HDDs back to native mode. 846 // 847 IdeController = NULL; 848 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { 849 Status = LegacyBiosPlatform->GetPlatformHandle ( 850 Private->LegacyBiosPlatform, 851 EfiGetPlatformIdeHandle, 852 0, 853 &HandleBuffer, 854 &HandleCount, 855 NULL 856 ); 857 if (!EFI_ERROR (Status)) { 858 IdeController = HandleBuffer[0]; 859 } 860 } 861 // 862 // Unlock the Legacy BIOS region 863 // 864 Private->LegacyRegion->UnLock ( 865 Private->LegacyRegion, 866 0xE0000, 867 0x20000, 868 &Granularity 869 ); 870 871 // 872 // Reconstruct the Legacy16 boot memory map 873 // 874 LegacyBiosBuildE820 (Private, &CopySize); 875 if (CopySize > Private->Legacy16Table->E820Length) { 876 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); 877 Regs.X.AX = Legacy16GetTableAddress; 878 Regs.X.CX = (UINT16) CopySize; 879 Private->LegacyBios.FarCall86 ( 880 &Private->LegacyBios, 881 Private->Legacy16Table->Compatibility16CallSegment, 882 Private->Legacy16Table->Compatibility16CallOffset, 883 &Regs, 884 NULL, 885 0 886 ); 887 888 Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); 889 Private->Legacy16Table->E820Length = (UINT32) CopySize; 890 if (Regs.X.AX != 0) { 891 DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n")); 892 } else { 893 CopyMem ( 894 (VOID *)(UINTN) Private->Legacy16Table->E820Pointer, 895 Private->E820Table, 896 CopySize 897 ); 898 } 899 } else { 900 CopyMem ( 901 (VOID *)(UINTN) Private->Legacy16Table->E820Pointer, 902 Private->E820Table, 903 CopySize 904 ); 905 Private->Legacy16Table->E820Length = (UINT32) CopySize; 906 } 907 // 908 // Get SMBIOS and ACPI table pointers 909 // 910 SmbiosTable = NULL; 911 EfiGetSystemConfigurationTable ( 912 &gEfiSmbiosTableGuid, 913 &SmbiosTable 914 ); 915 // 916 // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable. 917 // 918 if (SmbiosTable == NULL) { 919 DEBUG ((EFI_D_INFO, "Smbios table is not found!\n")); 920 } 921 EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)SmbiosTable; 922 923 AcpiTable = NULL; 924 Status = EfiGetSystemConfigurationTable ( 925 &gEfiAcpi20TableGuid, 926 &AcpiTable 927 ); 928 if (EFI_ERROR (Status)) { 929 Status = EfiGetSystemConfigurationTable ( 930 &gEfiAcpi10TableGuid, 931 &AcpiTable 932 ); 933 } 934 // 935 // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable. 936 // 937 if (AcpiTable == NULL) { 938 DEBUG ((EFI_D_INFO, "ACPI table is not found!\n")); 939 } 940 EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable; 941 942 // 943 // Get RSD Ptr table rev at offset 15 decimal 944 // Rev = 0 Length is 20 decimal 945 // Rev != 0 Length is UINT32 at offset 20 decimal 946 // 947 if (AcpiTable != NULL) { 948 949 AcpiPtr = AcpiTable; 950 if (*((UINT8 *) AcpiPtr + 15) == 0) { 951 CopySize = 20; 952 } else { 953 AcpiPtr = ((UINT8 *) AcpiPtr + 20); 954 CopySize = (*(UINT32 *) AcpiPtr); 955 } 956 957 CopyMem ( 958 (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer, 959 AcpiTable, 960 CopySize 961 ); 962 } 963 // 964 // Make sure all PCI Interrupt Line register are programmed to match 8259 965 // 966 PciProgramAllInterruptLineRegisters (Private); 967 968 // 969 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters 970 // can lock it. 971 // 972 Private->LegacyRegion->UnLock ( 973 Private->LegacyRegion, 974 Private->BiosStart, 975 Private->LegacyBiosImageSize, 976 &Granularity 977 ); 978 979 // 980 // Configure Legacy Device Magic 981 // 982 // Only do this code if booting legacy OS 983 // 984 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { 985 UpdateSioData (Private); 986 } 987 // 988 // Setup BDA and EBDA standard areas before Legacy Boot 989 // 990 LegacyBiosCompleteBdaBeforeBoot (Private); 991 LegacyBiosCompleteStandardCmosBeforeBoot (Private); 992 993 // 994 // We must build IDE data, if it hasn't been done, before PciShadowRoms 995 // to insure EFI drivers are connected. 996 // 997 LegacyBiosBuildIdeData (Private, &HddInfo, 1); 998 UpdateAllIdentifyDriveData (Private); 999 1000 // 1001 // Clear IO BAR, if IDE controller in legacy mode. 1002 // 1003 InitLegacyIdeController (IdeController); 1004 1005 // 1006 // Generate number of ticks since midnight for BDA. DOS requires this 1007 // for its time. We have to make assumptions as to how long following 1008 // code takes since after PciShadowRoms PciIo is gone. Place result in 1009 // 40:6C-6F 1010 // 1011 // Adjust value by 1 second. 1012 // 1013 gRT->GetTime (&BootTime, NULL); 1014 LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second; 1015 LocalTime += 1; 1016 1017 // 1018 // Multiply result by 18.2 for number of ticks since midnight. 1019 // Use 182/10 to avoid floating point math. 1020 // 1021 LocalTime = (LocalTime * 182) / 10; 1022 BdaPtr = (UINT32 *) (UINTN)0x46C; 1023 *BdaPtr = LocalTime; 1024 1025 // 1026 // Shadow PCI ROMs. We must do this near the end since this will kick 1027 // of Native EFI drivers that may be needed to collect info for Legacy16 1028 // 1029 // WARNING: PciIo is gone after this call. 1030 // 1031 PciShadowRoms (Private); 1032 1033 // 1034 // Shadow PXE base code, BIS etc. 1035 // 1036 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity); 1037 ShadowAddress = Private->OptionRom; 1038 Private->LegacyBiosPlatform->PlatformHooks ( 1039 Private->LegacyBiosPlatform, 1040 EfiPlatformHookShadowServiceRoms, 1041 0, 1042 0, 1043 &ShadowAddress, 1044 Legacy16Table, 1045 NULL 1046 ); 1047 Private->OptionRom = (UINT32)ShadowAddress; 1048 // 1049 // Register Legacy SMI Handler 1050 // 1051 LegacyBiosPlatform->SmmInit ( 1052 LegacyBiosPlatform, 1053 EfiToLegacy16BootTable 1054 ); 1055 1056 // 1057 // Let platform code know the boot options 1058 // 1059 LegacyBiosGetBbsInfo ( 1060 This, 1061 &HddCount, 1062 &LocalHddInfo, 1063 &BbsCount, 1064 &LocalBbsTable 1065 ); 1066 1067 DEBUG_CODE ( 1068 PrintPciInterruptRegister (); 1069 PrintBbsTable (LocalBbsTable); 1070 PrintHddInfo (LocalHddInfo); 1071 ); 1072 // 1073 // If drive wasn't spun up then BuildIdeData may have found new drives. 1074 // Need to update BBS boot priority. 1075 // 1076 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { 1077 if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) && 1078 (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY) 1079 ) { 1080 LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY; 1081 } 1082 1083 if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) && 1084 (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY) 1085 ) { 1086 LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY; 1087 } 1088 } 1089 1090 Private->LegacyRegion->UnLock ( 1091 Private->LegacyRegion, 1092 0xc0000, 1093 0x40000, 1094 &Granularity 1095 ); 1096 1097 LegacyBiosPlatform->PrepareToBoot ( 1098 LegacyBiosPlatform, 1099 mBbsDevicePathPtr, 1100 mBbsTable, 1101 mLoadOptionsSize, 1102 mLoadOptions, 1103 (VOID *) &Private->IntThunk->EfiToLegacy16BootTable 1104 ); 1105 1106 // 1107 // If no boot device return to BDS 1108 // 1109 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { 1110 for (Index = 0; Index < BbsCount; Index++){ 1111 if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) && 1112 (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) && 1113 (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) { 1114 break; 1115 } 1116 } 1117 if (Index == BbsCount) { 1118 return EFI_DEVICE_ERROR; 1119 } 1120 } 1121 // 1122 // Let the Legacy16 code know the device path type for legacy boot 1123 // 1124 EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType; 1125 1126 // 1127 // Copy MP table, if it exists. 1128 // 1129 LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable); 1130 1131 if (!Private->LegacyBootEntered) { 1132 // 1133 // Copy OEM INT Data, if it exists. Note: This code treats any data 1134 // as a bag of bits and knows nothing of the contents nor cares. 1135 // Contents are IBV specific. 1136 // 1137 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData); 1138 1139 // 1140 // Copy OEM16 Data, if it exists.Note: This code treats any data 1141 // as a bag of bits and knows nothing of the contents nor cares. 1142 // Contents are IBV specific. 1143 // 1144 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data); 1145 1146 // 1147 // Copy OEM32 Data, if it exists.Note: This code treats any data 1148 // as a bag of bits and knows nothing of the contents nor cares. 1149 // Contents are IBV specific. 1150 // 1151 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data); 1152 } 1153 1154 // 1155 // Call into Legacy16 code to prepare for INT 19h 1156 // 1157 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); 1158 Regs.X.AX = Legacy16PrepareToBoot; 1159 1160 // 1161 // Pass in handoff data 1162 // 1163 Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable); 1164 Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINTN)EfiToLegacy16BootTable); 1165 1166 Private->LegacyBios.FarCall86 ( 1167 This, 1168 Private->Legacy16CallSegment, 1169 Private->Legacy16CallOffset, 1170 &Regs, 1171 NULL, 1172 0 1173 ); 1174 1175 if (Regs.X.AX != 0) { 1176 return EFI_DEVICE_ERROR; 1177 } 1178 // 1179 // Lock the Legacy BIOS region 1180 // 1181 Private->LegacyRegion->Lock ( 1182 Private->LegacyRegion, 1183 0xc0000, 1184 0x40000, 1185 &Granularity 1186 ); 1187 // 1188 // Lock attributes of the Legacy Region if chipset supports 1189 // 1190 Private->LegacyRegion->BootLock ( 1191 Private->LegacyRegion, 1192 0xc0000, 1193 0x40000, 1194 &Granularity 1195 ); 1196 1197 // 1198 // Call into Legacy16 code to do the INT 19h 1199 // 1200 EnableAllControllers (Private); 1201 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { 1202 // 1203 // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT 1204 // 1205 EfiSignalEventLegacyBoot (); 1206 DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n")); 1207 1208 // 1209 // Disable DXE Timer while executing in real mode 1210 // 1211 Private->Timer->SetTimerPeriod (Private->Timer, 0); 1212 1213 // 1214 // Save and disable interrupt of debug timer 1215 // 1216 SaveAndSetDebugTimerInterrupt (FALSE); 1217 1218 1219 // 1220 // Put the 8259 into its legacy mode by reprogramming the vector bases 1221 // 1222 Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE); 1223 // 1224 // PC History 1225 // The original PC used INT8-F for master PIC. Since these mapped over 1226 // processor exceptions TIANO moved the master PIC to INT68-6F. 1227 // We need to set these back to the Legacy16 unexpected interrupt(saved 1228 // in LegacyBios.c) since some OS see that these have values different from 1229 // what is expected and invoke them. Since the legacy OS corrupts EFI 1230 // memory, there is no handler for these interrupts and OS blows up. 1231 // 1232 // We need to save the TIANO values for the rare case that the Legacy16 1233 // code cannot boot but knows memory hasn't been destroyed. 1234 // 1235 // To compound the problem, video takes over one of these INTS and must be 1236 // be left. 1237 // @bug - determine if video hooks INT(in which case we must find new 1238 // set of TIANO vectors) or takes it over. 1239 // 1240 // 1241 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); 1242 for (Index = 0; Index < 8; Index++) { 1243 Private->ThunkSavedInt[Index] = BaseVectorMaster[Index]; 1244 if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) { 1245 BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt); 1246 } 1247 } 1248 1249 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); 1250 Regs.X.AX = Legacy16Boot; 1251 1252 Private->LegacyBios.FarCall86 ( 1253 This, 1254 Private->Legacy16CallSegment, 1255 Private->Legacy16CallOffset, 1256 &Regs, 1257 NULL, 1258 0 1259 ); 1260 1261 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); 1262 for (Index = 0; Index < 8; Index++) { 1263 BaseVectorMaster[Index] = Private->ThunkSavedInt[Index]; 1264 } 1265 } 1266 Private->LegacyBootEntered = TRUE; 1267 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { 1268 // 1269 // Should never return unless never passed control to 0:7c00(first stage 1270 // OS loader) and only then if no bootable device found. 1271 // 1272 return EFI_DEVICE_ERROR; 1273 } else { 1274 // 1275 // If boot to EFI then expect to return to caller 1276 // 1277 return EFI_SUCCESS; 1278 } 1279} 1280 1281 1282/** 1283 Assign drive number to legacy HDD drives prior to booting an EFI 1284 aware OS so the OS can access drives without an EFI driver. 1285 Note: BBS compliant drives ARE NOT available until this call by 1286 either shell or EFI. 1287 1288 @param This Protocol instance pointer. 1289 @param BbsCount Number of BBS_TABLE structures 1290 @param BbsTable List BBS entries 1291 1292 @retval EFI_SUCCESS Drive numbers assigned 1293 1294**/ 1295EFI_STATUS 1296EFIAPI 1297LegacyBiosPrepareToBootEfi ( 1298 IN EFI_LEGACY_BIOS_PROTOCOL *This, 1299 OUT UINT16 *BbsCount, 1300 OUT BBS_TABLE **BbsTable 1301 ) 1302{ 1303 EFI_STATUS Status; 1304 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; 1305 LEGACY_BIOS_INSTANCE *Private; 1306 1307 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); 1308 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; 1309 mBootMode = BOOT_EFI_OS; 1310 mBbsDevicePathPtr = NULL; 1311 Status = GenericLegacyBoot (This); 1312 *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; 1313 *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); 1314 return Status; 1315} 1316 1317/** 1318 To boot from an unconventional device like parties and/or execute HDD diagnostics. 1319 1320 @param This Protocol instance pointer. 1321 @param Attributes How to interpret the other input parameters 1322 @param BbsEntry The 0-based index into the BbsTable for the parent 1323 device. 1324 @param BeerData Pointer to the 128 bytes of ram BEER data. 1325 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The 1326 caller must provide a pointer to the specific Service 1327 Area and not the start all Service Areas. 1328 1329 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error. 1330 1331***/ 1332EFI_STATUS 1333EFIAPI 1334LegacyBiosBootUnconventionalDevice ( 1335 IN EFI_LEGACY_BIOS_PROTOCOL *This, 1336 IN UDC_ATTRIBUTES Attributes, 1337 IN UINTN BbsEntry, 1338 IN VOID *BeerData, 1339 IN VOID *ServiceAreaData 1340 ) 1341{ 1342 EFI_STATUS Status; 1343 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; 1344 LEGACY_BIOS_INSTANCE *Private; 1345 UD_TABLE *UcdTable; 1346 UINTN Index; 1347 UINT16 BootPriority; 1348 BBS_TABLE *BbsTable; 1349 1350 BootPriority = 0; 1351 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); 1352 mBootMode = BOOT_UNCONVENTIONAL_DEVICE; 1353 mBbsDevicePathPtr = &mBbsDevicePathNode; 1354 mAttributes = Attributes; 1355 mBbsEntry = BbsEntry; 1356 mBeerData = BeerData, mServiceAreaData = ServiceAreaData; 1357 1358 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; 1359 1360 // 1361 // Do input parameter checking 1362 // 1363 if ((Attributes.DirectoryServiceValidity == 0) && 1364 (Attributes.RabcaUsedFlag == 0) && 1365 (Attributes.ExecuteHddDiagnosticsFlag == 0) 1366 ) { 1367 return EFI_INVALID_PARAMETER; 1368 } 1369 1370 if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) || 1371 (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL)) 1372 ) { 1373 return EFI_INVALID_PARAMETER; 1374 } 1375 1376 UcdTable = (UD_TABLE *) AllocatePool ( 1377 sizeof (UD_TABLE) 1378 ); 1379 if (NULL == UcdTable) { 1380 return EFI_OUT_OF_RESOURCES; 1381 } 1382 1383 EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable; 1384 UcdTable->Attributes = Attributes; 1385 UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry; 1386 // 1387 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM 1388 // to assign drive numbers but bot boot from. Only newly created entries 1389 // will be valid. 1390 // 1391 BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; 1392 for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) { 1393 BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM; 1394 } 1395 // 1396 // If parent is onboard IDE then assign controller & device number 1397 // else they are 0. 1398 // 1399 if (BbsEntry < MAX_IDE_CONTROLLER * 2) { 1400 UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2); 1401 } 1402 1403 if (BeerData != NULL) { 1404 CopyMem ( 1405 (VOID *) UcdTable->BeerData, 1406 BeerData, 1407 (UINTN) 128 1408 ); 1409 } 1410 1411 if (ServiceAreaData != NULL) { 1412 CopyMem ( 1413 (VOID *) UcdTable->ServiceAreaData, 1414 ServiceAreaData, 1415 (UINTN) 64 1416 ); 1417 } 1418 // 1419 // For each new entry do the following: 1420 // 1. Increment current number of BBS entries 1421 // 2. Copy parent entry to new entry. 1422 // 3. Zero out BootHandler Offset & segment 1423 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics 1424 // and Floppy(0x01) for PARTIES boot. 1425 // 5. Assign new priority. 1426 // 1427 if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) { 1428 EfiToLegacy16BootTable->NumberBbsEntries += 1; 1429 1430 CopyMem ( 1431 (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority, 1432 (VOID *) &BbsTable[BbsEntry].BootPriority, 1433 sizeof (BBS_TABLE) 1434 ); 1435 1436 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0; 1437 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0; 1438 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80; 1439 1440 UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1); 1441 1442 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority; 1443 BootPriority += 1; 1444 1445 // 1446 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic 1447 // 1448 mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV; 1449 } 1450 1451 if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) { 1452 EfiToLegacy16BootTable->NumberBbsEntries += 1; 1453 CopyMem ( 1454 (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority, 1455 (VOID *) &BbsTable[BbsEntry].BootPriority, 1456 sizeof (BBS_TABLE) 1457 ); 1458 1459 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0; 1460 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0; 1461 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01; 1462 UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1); 1463 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority; 1464 1465 // 1466 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy 1467 // 1468 mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY; 1469 } 1470 // 1471 // Build the BBS Device Path for this boot selection 1472 // 1473 mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH; 1474 mBbsDevicePathNode.Header.SubType = BBS_BBS_DP; 1475 SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH)); 1476 mBbsDevicePathNode.StatusFlag = 0; 1477 mBbsDevicePathNode.String[0] = 0; 1478 1479 Status = GenericLegacyBoot (This); 1480 return Status; 1481} 1482 1483/** 1484 Attempt to legacy boot the BootOption. If the EFI contexted has been 1485 compromised this function will not return. 1486 1487 @param This Protocol instance pointer. 1488 @param BbsDevicePath EFI Device Path from BootXXXX variable. 1489 @param LoadOptionsSize Size of LoadOption in size. 1490 @param LoadOptions LoadOption from BootXXXX variable 1491 1492 @retval EFI_SUCCESS Removable media not present 1493 1494**/ 1495EFI_STATUS 1496EFIAPI 1497LegacyBiosLegacyBoot ( 1498 IN EFI_LEGACY_BIOS_PROTOCOL *This, 1499 IN BBS_BBS_DEVICE_PATH *BbsDevicePath, 1500 IN UINT32 LoadOptionsSize, 1501 IN VOID *LoadOptions 1502 ) 1503{ 1504 EFI_STATUS Status; 1505 1506 mBbsDevicePathPtr = BbsDevicePath; 1507 mLoadOptionsSize = LoadOptionsSize; 1508 mLoadOptions = LoadOptions; 1509 mBootMode = BOOT_LEGACY_OS; 1510 Status = GenericLegacyBoot (This); 1511 1512 return Status; 1513} 1514 1515/** 1516 Convert EFI Memory Type to E820 Memory Type. 1517 1518 @param Type EFI Memory Type 1519 1520 @return ACPI Memory Type for EFI Memory Type 1521 1522**/ 1523EFI_ACPI_MEMORY_TYPE 1524EfiMemoryTypeToE820Type ( 1525 IN UINT32 Type 1526 ) 1527{ 1528 switch (Type) { 1529 case EfiLoaderCode: 1530 case EfiLoaderData: 1531 case EfiBootServicesCode: 1532 case EfiBootServicesData: 1533 case EfiConventionalMemory: 1534 case EfiRuntimeServicesCode: 1535 case EfiRuntimeServicesData: 1536 return EfiAcpiAddressRangeMemory; 1537 1538 case EfiACPIReclaimMemory: 1539 return EfiAcpiAddressRangeACPI; 1540 1541 case EfiACPIMemoryNVS: 1542 return EfiAcpiAddressRangeNVS; 1543 1544 // 1545 // All other types map to reserved. 1546 // Adding the code just waists FLASH space. 1547 // 1548 // case EfiReservedMemoryType: 1549 // case EfiUnusableMemory: 1550 // case EfiMemoryMappedIO: 1551 // case EfiMemoryMappedIOPortSpace: 1552 // case EfiPalCode: 1553 // 1554 default: 1555 return EfiAcpiAddressRangeReserved; 1556 } 1557} 1558 1559/** 1560 Build the E820 table. 1561 1562 @param Private Legacy BIOS Instance data 1563 @param Size Size of E820 Table 1564 1565 @retval EFI_SUCCESS It should always work. 1566 1567**/ 1568EFI_STATUS 1569LegacyBiosBuildE820 ( 1570 IN LEGACY_BIOS_INSTANCE *Private, 1571 OUT UINTN *Size 1572 ) 1573{ 1574 EFI_STATUS Status; 1575 EFI_E820_ENTRY64 *E820Table; 1576 EFI_MEMORY_DESCRIPTOR *EfiMemoryMap; 1577 EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd; 1578 EFI_MEMORY_DESCRIPTOR *EfiEntry; 1579 EFI_MEMORY_DESCRIPTOR *NextEfiEntry; 1580 EFI_MEMORY_DESCRIPTOR TempEfiEntry; 1581 UINTN EfiMemoryMapSize; 1582 UINTN EfiMapKey; 1583 UINTN EfiDescriptorSize; 1584 UINT32 EfiDescriptorVersion; 1585 UINTN Index; 1586 EFI_PEI_HOB_POINTERS Hob; 1587 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; 1588 UINTN TempIndex; 1589 UINTN IndexSort; 1590 UINTN TempNextIndex; 1591 EFI_E820_ENTRY64 TempE820; 1592 EFI_ACPI_MEMORY_TYPE TempType; 1593 BOOLEAN ChangedFlag; 1594 UINTN Above1MIndex; 1595 UINT64 MemoryBlockLength; 1596 1597 E820Table = (EFI_E820_ENTRY64 *) Private->E820Table; 1598 1599 // 1600 // Get the EFI memory map. 1601 // 1602 EfiMemoryMapSize = 0; 1603 EfiMemoryMap = NULL; 1604 Status = gBS->GetMemoryMap ( 1605 &EfiMemoryMapSize, 1606 EfiMemoryMap, 1607 &EfiMapKey, 1608 &EfiDescriptorSize, 1609 &EfiDescriptorVersion 1610 ); 1611 ASSERT (Status == EFI_BUFFER_TOO_SMALL); 1612 1613 do { 1614 // 1615 // Use size returned back plus 1 descriptor for the AllocatePool. 1616 // We don't just multiply by 2 since the "for" loop below terminates on 1617 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize 1618 // we process bogus entries and create bogus E820 entries. 1619 // 1620 EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize); 1621 ASSERT (EfiMemoryMap != NULL); 1622 Status = gBS->GetMemoryMap ( 1623 &EfiMemoryMapSize, 1624 EfiMemoryMap, 1625 &EfiMapKey, 1626 &EfiDescriptorSize, 1627 &EfiDescriptorVersion 1628 ); 1629 if (EFI_ERROR (Status)) { 1630 FreePool (EfiMemoryMap); 1631 } 1632 } while (Status == EFI_BUFFER_TOO_SMALL); 1633 1634 ASSERT_EFI_ERROR (Status); 1635 1636 // 1637 // Punch in the E820 table for memory less than 1 MB. 1638 // Assume ZeroMem () has been done on data structure. 1639 // 1640 // 1641 // First entry is 0 to (640k - EBDA) 1642 // 1643 E820Table[0].BaseAddr = 0; 1644 E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4); 1645 E820Table[0].Type = EfiAcpiAddressRangeMemory; 1646 1647 // 1648 // Second entry is (640k - EBDA) to 640k 1649 // 1650 E820Table[1].BaseAddr = E820Table[0].Length; 1651 E820Table[1].Length = (UINT64) ((640 * 1024) - E820Table[0].Length); 1652 E820Table[1].Type = EfiAcpiAddressRangeReserved; 1653 1654 // 1655 // Third Entry is legacy BIOS 1656 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas 1657 // to page in memory under 1MB. 1658 // Omit region from 0xE0000 to start of BIOS, if any. This can be 1659 // used for a multiple reasons including OPROMS. 1660 // 1661 1662 // 1663 // The CSM binary image size is not the actually size that CSM binary used, 1664 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary. 1665 // 1666 E820Table[2].BaseAddr = 0xE0000; 1667 E820Table[2].Length = 0x20000; 1668 E820Table[2].Type = EfiAcpiAddressRangeReserved; 1669 1670 Above1MIndex = 2; 1671 1672 // 1673 // Process the EFI map to produce E820 map; 1674 // 1675 1676 // 1677 // Sort memory map from low to high 1678 // 1679 EfiEntry = EfiMemoryMap; 1680 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); 1681 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); 1682 while (EfiEntry < EfiMemoryMapEnd) { 1683 while (NextEfiEntry < EfiMemoryMapEnd) { 1684 if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) { 1685 CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); 1686 CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); 1687 CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); 1688 } 1689 1690 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize); 1691 } 1692 1693 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); 1694 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); 1695 } 1696 1697 EfiEntry = EfiMemoryMap; 1698 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); 1699 for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) { 1700 MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12)); 1701 if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) { 1702 // 1703 // Skip the memory block is under 1MB 1704 // 1705 } else { 1706 if (EfiEntry->PhysicalStart < 0x100000) { 1707 // 1708 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB 1709 // 1710 MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart; 1711 EfiEntry->PhysicalStart = 0x100000; 1712 } 1713 1714 // 1715 // Convert memory type to E820 type 1716 // 1717 TempType = EfiMemoryTypeToE820Type (EfiEntry->Type); 1718 1719 if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) { 1720 // 1721 // Grow an existing entry 1722 // 1723 E820Table[Index].Length += MemoryBlockLength; 1724 } else { 1725 // 1726 // Make a new entry 1727 // 1728 ++Index; 1729 E820Table[Index].BaseAddr = EfiEntry->PhysicalStart; 1730 E820Table[Index].Length = MemoryBlockLength; 1731 E820Table[Index].Type = TempType; 1732 } 1733 } 1734 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); 1735 } 1736 1737 FreePool (EfiMemoryMap); 1738 1739 // 1740 // Process the reserved memory map to produce E820 map ; 1741 // 1742 for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { 1743 if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { 1744 ResourceHob = Hob.ResourceDescriptor; 1745 if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) || 1746 (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) || 1747 (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) ) && 1748 (ResourceHob->PhysicalStart > 0x100000) && 1749 (Index < EFI_MAX_E820_ENTRY - 1)) { 1750 ++Index; 1751 E820Table[Index].BaseAddr = ResourceHob->PhysicalStart; 1752 E820Table[Index].Length = ResourceHob->ResourceLength; 1753 E820Table[Index].Type = EfiAcpiAddressRangeReserved; 1754 } 1755 } 1756 } 1757 1758 Index ++; 1759 Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index; 1760 Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index; 1761 Private->NumberE820Entries = (UINT32)Index; 1762 *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64)); 1763 1764 // 1765 // Sort E820Table from low to high 1766 // 1767 for (TempIndex = 0; TempIndex < Index; TempIndex++) { 1768 ChangedFlag = FALSE; 1769 for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) { 1770 if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) { 1771 ChangedFlag = TRUE; 1772 TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr; 1773 TempE820.Length = E820Table[TempNextIndex - 1].Length; 1774 TempE820.Type = E820Table[TempNextIndex - 1].Type; 1775 1776 E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr; 1777 E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length; 1778 E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type; 1779 1780 E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr; 1781 E820Table[TempNextIndex].Length = TempE820.Length; 1782 E820Table[TempNextIndex].Type = TempE820.Type; 1783 } 1784 } 1785 1786 if (!ChangedFlag) { 1787 break; 1788 } 1789 } 1790 1791 // 1792 // Remove the overlap range 1793 // 1794 for (TempIndex = 1; TempIndex < Index; TempIndex++) { 1795 if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr && 1796 ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >= 1797 (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) { 1798 // 1799 //Overlap range is found 1800 // 1801 ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type); 1802 1803 if (TempIndex == Index - 1) { 1804 E820Table[TempIndex].BaseAddr = 0; 1805 E820Table[TempIndex].Length = 0; 1806 E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE) 0; 1807 Index--; 1808 break; 1809 } else { 1810 for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) { 1811 E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr; 1812 E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length; 1813 E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type; 1814 } 1815 Index--; 1816 } 1817 } 1818 } 1819 1820 1821 1822 Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index; 1823 Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index; 1824 Private->NumberE820Entries = (UINT32)Index; 1825 *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64)); 1826 1827 // 1828 // Determine OS usable memory above 1Mb 1829 // 1830 Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000; 1831 for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) { 1832 if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory 1833 // 1834 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables. 1835 // 1836 if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) { 1837 Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length); 1838 } else { 1839 break; // break at first not normal memory, because SMM may use reserved memory. 1840 } 1841 } 1842 } 1843 1844 Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb; 1845 1846 // 1847 // Print DEBUG information 1848 // 1849 for (TempIndex = 0; TempIndex < Index; TempIndex++) { 1850 DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n", 1851 TempIndex, 1852 E820Table[TempIndex].BaseAddr, 1853 (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length), 1854 E820Table[TempIndex].Type 1855 )); 1856 } 1857 1858 return EFI_SUCCESS; 1859} 1860 1861 1862/** 1863 Fill in the standard BDA and EBDA stuff prior to legacy Boot 1864 1865 @param Private Legacy BIOS Instance data 1866 1867 @retval EFI_SUCCESS It should always work. 1868 1869**/ 1870EFI_STATUS 1871LegacyBiosCompleteBdaBeforeBoot ( 1872 IN LEGACY_BIOS_INSTANCE *Private 1873 ) 1874{ 1875 BDA_STRUC *Bda; 1876 UINT16 MachineConfig; 1877 DEVICE_PRODUCER_DATA_HEADER *SioPtr; 1878 1879 Bda = (BDA_STRUC *) ((UINTN) 0x400); 1880 MachineConfig = 0; 1881 1882 SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData); 1883 Bda->Com1 = SioPtr->Serial[0].Address; 1884 Bda->Com2 = SioPtr->Serial[1].Address; 1885 Bda->Com3 = SioPtr->Serial[2].Address; 1886 Bda->Com4 = SioPtr->Serial[3].Address; 1887 1888 if (SioPtr->Serial[0].Address != 0x00) { 1889 MachineConfig += 0x200; 1890 } 1891 1892 if (SioPtr->Serial[1].Address != 0x00) { 1893 MachineConfig += 0x200; 1894 } 1895 1896 if (SioPtr->Serial[2].Address != 0x00) { 1897 MachineConfig += 0x200; 1898 } 1899 1900 if (SioPtr->Serial[3].Address != 0x00) { 1901 MachineConfig += 0x200; 1902 } 1903 1904 Bda->Lpt1 = SioPtr->Parallel[0].Address; 1905 Bda->Lpt2 = SioPtr->Parallel[1].Address; 1906 Bda->Lpt3 = SioPtr->Parallel[2].Address; 1907 1908 if (SioPtr->Parallel[0].Address != 0x00) { 1909 MachineConfig += 0x4000; 1910 } 1911 1912 if (SioPtr->Parallel[1].Address != 0x00) { 1913 MachineConfig += 0x4000; 1914 } 1915 1916 if (SioPtr->Parallel[2].Address != 0x00) { 1917 MachineConfig += 0x4000; 1918 } 1919 1920 Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount); 1921 if (SioPtr->Floppy.NumberOfFloppy != 0x00) { 1922 MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40); 1923 Bda->FloppyXRate = 0x07; 1924 } 1925 1926 Bda->Lpt1_2Timeout = 0x1414; 1927 Bda->Lpt3_4Timeout = 0x1414; 1928 Bda->Com1_2Timeout = 0x0101; 1929 Bda->Com3_4Timeout = 0x0101; 1930 1931 // 1932 // Force VGA and Coprocessor, indicate 101/102 keyboard 1933 // 1934 MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04)); 1935 Bda->MachineConfig = MachineConfig; 1936 1937 return EFI_SUCCESS; 1938} 1939 1940/** 1941 Fill in the standard BDA for Keyboard LEDs 1942 1943 @param This Protocol instance pointer. 1944 @param Leds Current LED status 1945 1946 @retval EFI_SUCCESS It should always work. 1947 1948**/ 1949EFI_STATUS 1950EFIAPI 1951LegacyBiosUpdateKeyboardLedStatus ( 1952 IN EFI_LEGACY_BIOS_PROTOCOL *This, 1953 IN UINT8 Leds 1954 ) 1955{ 1956 LEGACY_BIOS_INSTANCE *Private; 1957 BDA_STRUC *Bda; 1958 UINT8 LocalLeds; 1959 EFI_IA32_REGISTER_SET Regs; 1960 1961 Bda = (BDA_STRUC *) ((UINTN) 0x400); 1962 1963 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); 1964 LocalLeds = Leds; 1965 Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds); 1966 LocalLeds = (UINT8) (LocalLeds << 4); 1967 Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds); 1968 LocalLeds = (UINT8) (Leds & 0x20); 1969 Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds); 1970 // 1971 // Call into Legacy16 code to allow it to do any processing 1972 // 1973 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); 1974 Regs.X.AX = Legacy16SetKeyboardLeds; 1975 Regs.H.CL = Leds; 1976 1977 Private->LegacyBios.FarCall86 ( 1978 &Private->LegacyBios, 1979 Private->Legacy16Table->Compatibility16CallSegment, 1980 Private->Legacy16Table->Compatibility16CallOffset, 1981 &Regs, 1982 NULL, 1983 0 1984 ); 1985 1986 return EFI_SUCCESS; 1987} 1988 1989 1990/** 1991 Fill in the standard CMOS stuff prior to legacy Boot 1992 1993 @param Private Legacy BIOS Instance data 1994 1995 @retval EFI_SUCCESS It should always work. 1996 1997**/ 1998EFI_STATUS 1999LegacyBiosCompleteStandardCmosBeforeBoot ( 2000 IN LEGACY_BIOS_INSTANCE *Private 2001 ) 2002{ 2003 UINT8 Bda; 2004 UINT8 Floppy; 2005 UINT32 Size; 2006 2007 // 2008 // Update CMOS locations 2009 // 10 floppy 2010 // 12,19,1A - ignore as OS don't use them and there is no standard due 2011 // to large capacity drives 2012 // CMOS 14 = BDA 40:10 plus bit 3(display enabled) 2013 // 2014 Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3); 2015 2016 // 2017 // Force display enabled 2018 // 2019 Floppy = 0x00; 2020 if ((Bda & BIT0) != 0) { 2021 Floppy = BIT6; 2022 } 2023 2024 // 2025 // Check if 2.88MB floppy set 2026 // 2027 if ((Bda & (BIT7 | BIT6)) != 0) { 2028 Floppy = (UINT8)(Floppy | BIT1); 2029 } 2030 2031 LegacyWriteStandardCmos (CMOS_10, Floppy); 2032 LegacyWriteStandardCmos (CMOS_14, Bda); 2033 2034 // 2035 // Force Status Register A to set rate selection bits and divider 2036 // 2037 LegacyWriteStandardCmos (CMOS_0A, 0x26); 2038 2039 // 2040 // redo memory size since it can change 2041 // 2042 Size = 15 * SIZE_1MB; 2043 if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) { 2044 Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10; 2045 } 2046 2047 LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF)); 2048 LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF)); 2049 LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8)); 2050 LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8)); 2051 2052 LegacyCalculateWriteStandardCmosChecksum (); 2053 2054 return EFI_SUCCESS; 2055} 2056 2057/** 2058 Relocate this image under 4G memory for IPF. 2059 2060 @param ImageHandle Handle of driver image. 2061 @param SystemTable Pointer to system table. 2062 2063 @retval EFI_SUCCESS Image successfully relocated. 2064 @retval EFI_ABORTED Failed to relocate image. 2065 2066**/ 2067EFI_STATUS 2068RelocateImageUnder4GIfNeeded ( 2069 IN EFI_HANDLE ImageHandle, 2070 IN EFI_SYSTEM_TABLE *SystemTable 2071 ) 2072{ 2073 return EFI_SUCCESS; 2074} 2075