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