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