1 /** @file 2 3 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions 7 of the BSD License which accompanies this distribution. The 8 full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "LegacyBiosInterface.h" 17 #include <IndustryStandard/Pci.h> 18 19 #define BOOT_LEGACY_OS 0 20 #define BOOT_EFI_OS 1 21 #define BOOT_UNCONVENTIONAL_DEVICE 2 22 23 UINT32 mLoadOptionsSize = 0; 24 UINTN mBootMode = BOOT_LEGACY_OS; 25 VOID *mLoadOptions = NULL; 26 BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL; 27 BBS_BBS_DEVICE_PATH mBbsDevicePathNode; 28 UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 }; 29 UINTN mBbsEntry = 0; 30 VOID *mBeerData = NULL; 31 VOID *mServiceAreaData = NULL; 32 UINT64 mLowWater = 0xffffffffffffffffULL; 33 34 extern BBS_TABLE *mBbsTable; 35 36 extern VOID *mRuntimeSmbiosEntryPoint; 37 extern EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint; 38 extern EFI_PHYSICAL_ADDRESS mStructureTableAddress; 39 40 /** 41 Print the BBS Table. 42 43 @param BbsTable The BBS table. 44 45 46 **/ 47 VOID 48 PrintBbsTable ( 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 **/ 117 VOID 118 PrintHddInfo ( 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 **/ 145 VOID 146 PrintPciInterruptRegister ( 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 **/ 214 VOID 215 UpdateIdentifyDriveData ( 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 **/ 227 EFI_STATUS 228 UpdateSioData ( 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 **/ 368 EFI_STATUS 369 CalculateIdentifyDriveChecksum ( 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 **/ 398 VOID 399 UpdateIdentifyDriveData ( 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 **/ 465 VOID 466 UpdateAllIdentifyDriveData ( 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 **/ 497 VOID 498 EnableIdeController ( 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 **/ 540 VOID 541 EnableAllControllers ( 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 **/ 635 EFI_STATUS 636 LegacyGetDataOrTable ( 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 **/ 788 VOID 789 CreateSmbiosTableInReservedMemory ( 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 **/ 853 EFI_STATUS 854 GenericLegacyBoot ( 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 **/ 1377 EFI_STATUS 1378 EFIAPI 1379 LegacyBiosPrepareToBootEfi ( 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 ***/ 1414 EFI_STATUS 1415 EFIAPI 1416 LegacyBiosBootUnconventionalDevice ( 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 **/ 1577 EFI_STATUS 1578 EFIAPI 1579 LegacyBiosLegacyBoot ( 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 **/ 1605 EFI_ACPI_MEMORY_TYPE 1606 EfiMemoryTypeToE820Type ( 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 **/ 1659 EFI_STATUS 1660 LegacyBiosBuildE820 ( 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 **/ 1961 EFI_STATUS 1962 LegacyBiosCompleteBdaBeforeBoot ( 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 **/ 2040 EFI_STATUS 2041 EFIAPI 2042 LegacyBiosUpdateKeyboardLedStatus ( 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 **/ 2089 EFI_STATUS 2090 LegacyBiosCompleteStandardCmosBeforeBoot ( 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 **/ 2158 EFI_STATUS 2159 RelocateImageUnder4GIfNeeded ( 2160 IN EFI_HANDLE ImageHandle, 2161 IN EFI_SYSTEM_TABLE *SystemTable 2162 ) 2163 { 2164 return EFI_SUCCESS; 2165 } 2166