1 /** @file 2 3 Copyright (c) 2006 - 2013, 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 18 #define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address)) 19 20 // 21 // define maximum number of HDD system supports 22 // 23 #define MAX_HDD_ENTRIES 0x30 24 25 // 26 // Module Global: 27 // Since this driver will only ever produce one instance of the Private Data 28 // protocol you are not required to dynamically allocate the PrivateData. 29 // 30 LEGACY_BIOS_INSTANCE mPrivateData; 31 32 // 33 // The SMBIOS table in EfiRuntimeServicesData memory 34 // 35 VOID *mRuntimeSmbiosEntryPoint = NULL; 36 37 // 38 // The SMBIOS table in EfiReservedMemoryType memory 39 // 40 EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint = 0; 41 EFI_PHYSICAL_ADDRESS mStructureTableAddress = 0; 42 UINTN mStructureTablePages = 0; 43 44 /** 45 Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode 46 memory. 47 48 @param AllocateType Allocated Legacy Memory Type 49 @param StartPageAddress Start address of range 50 @param Pages Number of pages to allocate 51 @param Result Result of allocation 52 53 @retval EFI_SUCCESS Legacy16 code loaded 54 @retval Other No protocol installed, unload driver. 55 56 **/ 57 EFI_STATUS 58 AllocateLegacyMemory ( 59 IN EFI_ALLOCATE_TYPE AllocateType, 60 IN EFI_PHYSICAL_ADDRESS StartPageAddress, 61 IN UINTN Pages, 62 OUT EFI_PHYSICAL_ADDRESS *Result 63 ) 64 { 65 EFI_STATUS Status; 66 EFI_PHYSICAL_ADDRESS MemPage; 67 68 // 69 // Allocate Pages of memory less <= StartPageAddress 70 // 71 MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress; 72 Status = gBS->AllocatePages ( 73 AllocateType, 74 EfiBootServicesCode, 75 Pages, 76 &MemPage 77 ); 78 // 79 // Do not ASSERT on Status error but let caller decide since some cases 80 // memory is already taken but that is ok. 81 // 82 if (!EFI_ERROR (Status)) { 83 *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage; 84 } 85 // 86 // If reach here the status = EFI_SUCCESS 87 // 88 return Status; 89 } 90 91 92 /** 93 This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000 94 64 KB blocks. 95 96 Note: inconsistency with the Framework CSM spec. Per the spec, this function may be 97 invoked only once. This limitation is relaxed to allow multiple calls in this implemenation. 98 99 @param This Protocol instance pointer. 100 @param LegacyMemorySize Size of required region 101 @param Region Region to use. 00 = Either 0xE0000 or 0xF0000 102 block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000 103 block 104 @param Alignment Address alignment. Bit mapped. First non-zero 105 bit from right is alignment. 106 @param LegacyMemoryAddress Region Assigned 107 108 @retval EFI_SUCCESS Region assigned 109 @retval EFI_ACCESS_DENIED Procedure previously invoked 110 @retval Other Region not assigned 111 112 **/ 113 EFI_STATUS 114 EFIAPI 115 LegacyBiosGetLegacyRegion ( 116 IN EFI_LEGACY_BIOS_PROTOCOL *This, 117 IN UINTN LegacyMemorySize, 118 IN UINTN Region, 119 IN UINTN Alignment, 120 OUT VOID **LegacyMemoryAddress 121 ) 122 { 123 124 LEGACY_BIOS_INSTANCE *Private; 125 EFI_IA32_REGISTER_SET Regs; 126 EFI_STATUS Status; 127 UINT32 Granularity; 128 129 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); 130 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity); 131 132 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); 133 Regs.X.AX = Legacy16GetTableAddress; 134 Regs.X.BX = (UINT16) Region; 135 Regs.X.CX = (UINT16) LegacyMemorySize; 136 Regs.X.DX = (UINT16) Alignment; 137 Private->LegacyBios.FarCall86 ( 138 &Private->LegacyBios, 139 Private->Legacy16CallSegment, 140 Private->Legacy16CallOffset, 141 &Regs, 142 NULL, 143 0 144 ); 145 146 if (Regs.X.AX == 0) { 147 *LegacyMemoryAddress = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX); 148 Status = EFI_SUCCESS; 149 } else { 150 Status = EFI_OUT_OF_RESOURCES; 151 } 152 153 Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate); 154 Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity); 155 156 return Status; 157 } 158 159 160 /** 161 This function is called when copying data to the region assigned by 162 EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion(). 163 164 @param This Protocol instance pointer. 165 @param LegacyMemorySize Size of data to copy 166 @param LegacyMemoryAddress Legacy Region destination address Note: must 167 be in region assigned by 168 LegacyBiosGetLegacyRegion 169 @param LegacyMemorySourceAddress Source of data 170 171 @retval EFI_SUCCESS The data was copied successfully. 172 @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds. 173 **/ 174 EFI_STATUS 175 EFIAPI 176 LegacyBiosCopyLegacyRegion ( 177 IN EFI_LEGACY_BIOS_PROTOCOL *This, 178 IN UINTN LegacyMemorySize, 179 IN VOID *LegacyMemoryAddress, 180 IN VOID *LegacyMemorySourceAddress 181 ) 182 { 183 184 LEGACY_BIOS_INSTANCE *Private; 185 UINT32 Granularity; 186 187 if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) || 188 ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000) 189 ) { 190 return EFI_ACCESS_DENIED; 191 } 192 // 193 // There is no protection from writes over lapping if this function is 194 // called multiple times. 195 // 196 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); 197 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity); 198 CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize); 199 200 Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate); 201 Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity); 202 203 return EFI_SUCCESS; 204 } 205 206 207 /** 208 Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find 209 the $EFI table in the shadow area. Thunk into the Legacy16 code after it had 210 been shadowed. 211 212 @param Private Legacy BIOS context data 213 214 @retval EFI_SUCCESS Legacy16 code loaded 215 @retval Other No protocol installed, unload driver. 216 217 **/ 218 EFI_STATUS 219 ShadowAndStartLegacy16 ( 220 IN LEGACY_BIOS_INSTANCE *Private 221 ) 222 { 223 EFI_STATUS Status; 224 UINT8 *Ptr; 225 UINT8 *PtrEnd; 226 BOOLEAN Done; 227 EFI_COMPATIBILITY16_TABLE *Table; 228 UINT8 CheckSum; 229 EFI_IA32_REGISTER_SET Regs; 230 EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable; 231 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; 232 VOID *LegacyBiosImage; 233 UINTN LegacyBiosImageSize; 234 UINTN E820Size; 235 UINT32 *ClearPtr; 236 BBS_TABLE *BbsTable; 237 LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable; 238 UINTN Index; 239 UINT32 TpmPointer; 240 VOID *TpmBinaryImage; 241 UINTN TpmBinaryImageSize; 242 UINTN Location; 243 UINTN Alignment; 244 UINTN TempData; 245 EFI_PHYSICAL_ADDRESS Address; 246 UINT16 OldMask; 247 UINT16 NewMask; 248 UINT32 Granularity; 249 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; 250 251 Location = 0; 252 Alignment = 0; 253 254 // 255 // we allocate the C/D/E/F segment as RT code so no one will use it any more. 256 // 257 Address = 0xC0000; 258 gDS->GetMemorySpaceDescriptor (Address, &Descriptor); 259 if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { 260 // 261 // If it is already reserved, we should be safe, or else we allocate it. 262 // 263 Status = gBS->AllocatePages ( 264 AllocateAddress, 265 EfiRuntimeServicesCode, 266 0x40000/EFI_PAGE_SIZE, 267 &Address 268 ); 269 if (EFI_ERROR (Status)) { 270 // 271 // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory. 272 // 273 DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status)); 274 } 275 } 276 277 // 278 // start testtest 279 // GetTimerValue (&Ticker); 280 // 281 // gRT->SetVariable (L"StartLegacy", 282 // &gEfiGlobalVariableGuid, 283 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 284 // sizeof (UINT64), 285 // (VOID *)&Ticker 286 // ); 287 // end testtest 288 // 289 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; 290 Status = Private->LegacyBiosPlatform->GetPlatformInfo ( 291 Private->LegacyBiosPlatform, 292 EfiGetPlatformBinarySystemRom, 293 &LegacyBiosImage, 294 &LegacyBiosImageSize, 295 &Location, 296 &Alignment, 297 0, 298 0 299 ); 300 if (EFI_ERROR (Status)) { 301 return Status; 302 } 303 304 Private->BiosStart = (UINT32) (0x100000 - LegacyBiosImageSize); 305 Private->OptionRom = 0xc0000; 306 Private->LegacyBiosImageSize = (UINT32) LegacyBiosImageSize; 307 308 // 309 // Can only shadow into memory allocated for legacy useage. 310 // 311 ASSERT (Private->BiosStart > Private->OptionRom); 312 313 // 314 // Shadow Legacy BIOS. Turn on memory and copy image 315 // 316 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity); 317 318 ClearPtr = (VOID *) ((UINTN) 0xc0000); 319 320 // 321 // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused 322 // regions to be used by EMM386 etc. 323 // 324 SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff); 325 326 TempData = Private->BiosStart; 327 328 CopyMem ( 329 (VOID *) TempData, 330 LegacyBiosImage, 331 (UINTN) LegacyBiosImageSize 332 ); 333 334 Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate); 335 336 // 337 // Search for Legacy16 table in Shadowed ROM 338 // 339 Done = FALSE; 340 Table = NULL; 341 for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) { 342 if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) { 343 Table = (EFI_COMPATIBILITY16_TABLE *) Ptr; 344 PtrEnd = Ptr + Table->TableLength; 345 for (CheckSum = 0; Ptr < PtrEnd; Ptr++) { 346 CheckSum = (UINT8) (CheckSum +*Ptr); 347 } 348 349 Done = TRUE; 350 } 351 } 352 353 if (Table == NULL) { 354 DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n")); 355 return EFI_NOT_FOUND; 356 } 357 358 if (!Done) { 359 // 360 // Legacy16 table header checksum error. 361 // 362 DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n")); 363 } 364 365 // 366 // Remember location of the Legacy16 table 367 // 368 Private->Legacy16Table = Table; 369 Private->Legacy16CallSegment = Table->Compatibility16CallSegment; 370 Private->Legacy16CallOffset = Table->Compatibility16CallOffset; 371 EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable; 372 Private->Legacy16InitPtr = EfiToLegacy16InitTable; 373 Private->Legacy16BootPtr = &Private->IntThunk->EfiToLegacy16BootTable; 374 Private->InternalIrqRoutingTable = NULL; 375 Private->NumberIrqRoutingEntries = 0; 376 Private->BbsTablePtr = NULL; 377 Private->LegacyEfiHddTable = NULL; 378 Private->DiskEnd = 0; 379 Private->Disk4075 = 0; 380 Private->HddTablePtr = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo; 381 Private->NumberHddControllers = MAX_IDE_CONTROLLER; 382 Private->Dump[0] = 'D'; 383 Private->Dump[1] = 'U'; 384 Private->Dump[2] = 'M'; 385 Private->Dump[3] = 'P'; 386 387 ZeroMem ( 388 Private->Legacy16BootPtr, 389 sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE) 390 ); 391 392 // 393 // Store away a copy of the EFI System Table 394 // 395 Table->EfiSystemTable = (UINT32) (UINTN) gST; 396 397 // 398 // IPF CSM integration -Bug 399 // 400 // Construct the Legacy16 boot memory map. This sets up number of 401 // E820 entries. 402 // 403 LegacyBiosBuildE820 (Private, &E820Size); 404 // 405 // Initialize BDA and EBDA standard values needed to load Legacy16 code 406 // 407 LegacyBiosInitBda (Private); 408 LegacyBiosInitCmos (Private); 409 410 // 411 // All legacy interrupt should be masked when do initialization work from legacy 16 code. 412 // 413 Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL); 414 NewMask = 0xFFFF; 415 Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL); 416 417 // 418 // Call into Legacy16 code to do an INIT 419 // 420 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); 421 Regs.X.AX = Legacy16InitializeYourself; 422 Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable)); 423 Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable)); 424 425 Private->LegacyBios.FarCall86 ( 426 &Private->LegacyBios, 427 Table->Compatibility16CallSegment, 428 Table->Compatibility16CallOffset, 429 &Regs, 430 NULL, 431 0 432 ); 433 434 // 435 // Restore original legacy interrupt mask value 436 // 437 Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL); 438 439 if (Regs.X.AX != 0) { 440 return EFI_DEVICE_ERROR; 441 } 442 443 // 444 // start testtest 445 // GetTimerValue (&Ticker); 446 // 447 // gRT->SetVariable (L"BackFromInitYourself", 448 // &gEfiGlobalVariableGuid, 449 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 450 // sizeof (UINT64), 451 // (VOID *)&Ticker 452 // ); 453 // end testtest 454 // 455 // Copy E820 table after InitializeYourself is completed 456 // 457 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); 458 Regs.X.AX = Legacy16GetTableAddress; 459 Regs.X.CX = (UINT16) E820Size; 460 Regs.X.DX = 1; 461 Private->LegacyBios.FarCall86 ( 462 &Private->LegacyBios, 463 Table->Compatibility16CallSegment, 464 Table->Compatibility16CallOffset, 465 &Regs, 466 NULL, 467 0 468 ); 469 470 Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); 471 Table->E820Length = (UINT32) E820Size; 472 if (Regs.X.AX != 0) { 473 DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n")); 474 } else { 475 TempData = Table->E820Pointer; 476 CopyMem ((VOID *) TempData, Private->E820Table, E820Size); 477 } 478 // 479 // Get PnPInstallationCheck Info. 480 // 481 Private->PnPInstallationCheckSegment = Table->PnPInstallationCheckSegment; 482 Private->PnPInstallationCheckOffset = Table->PnPInstallationCheckOffset; 483 484 // 485 // Check if PCI Express is supported. If yes, Save base address. 486 // 487 Status = Private->LegacyBiosPlatform->GetPlatformInfo ( 488 Private->LegacyBiosPlatform, 489 EfiGetPlatformPciExpressBase, 490 NULL, 491 NULL, 492 &Location, 493 &Alignment, 494 0, 495 0 496 ); 497 if (!EFI_ERROR (Status)) { 498 Private->Legacy16Table->PciExpressBase = (UINT32)Location; 499 Location = 0; 500 } 501 // 502 // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it 503 // into, copy it and update pointer to binary image. This needs to be 504 // done prior to any OPROM for security purposes. 505 // 506 Status = Private->LegacyBiosPlatform->GetPlatformInfo ( 507 Private->LegacyBiosPlatform, 508 EfiGetPlatformBinaryTpmBinary, 509 &TpmBinaryImage, 510 &TpmBinaryImageSize, 511 &Location, 512 &Alignment, 513 0, 514 0 515 ); 516 if (!EFI_ERROR (Status)) { 517 518 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); 519 Regs.X.AX = Legacy16GetTableAddress; 520 Regs.X.CX = (UINT16) TpmBinaryImageSize; 521 Regs.X.DX = 1; 522 Private->LegacyBios.FarCall86 ( 523 &Private->LegacyBios, 524 Table->Compatibility16CallSegment, 525 Table->Compatibility16CallOffset, 526 &Regs, 527 NULL, 528 0 529 ); 530 531 TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); 532 if (Regs.X.AX != 0) { 533 DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n")); 534 } else { 535 CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize); 536 Table->TpmSegment = Regs.X.DS; 537 Table->TpmOffset = Regs.X.BX; 538 539 } 540 } 541 // 542 // Lock the Legacy BIOS region 543 // 544 Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate); 545 Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity); 546 547 // 548 // Get the BbsTable from LOW_MEMORY_THUNK 549 // 550 BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable; 551 ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable)); 552 553 EfiToLegacy16BootTable->BbsTable = (UINT32)(UINTN)BbsTable; 554 Private->BbsTablePtr = (VOID *) BbsTable; 555 // 556 // Skip Floppy and possible onboard IDE drives 557 // 558 EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER; 559 560 for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) { 561 BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY; 562 } 563 // 564 // Allocate space for Legacy HDD table 565 // 566 LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE)); 567 ASSERT (LegacyEfiHddTable); 568 569 Private->LegacyEfiHddTable = LegacyEfiHddTable; 570 Private->LegacyEfiHddTableIndex = 0x00; 571 572 // 573 // start testtest 574 // GetTimerValue (&Ticker); 575 // 576 // gRT->SetVariable (L"EndOfLoadFv", 577 // &gEfiGlobalVariableGuid, 578 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 579 // sizeof (UINT64), 580 // (VOID *)&Ticker 581 // ); 582 // end testtest 583 // 584 return EFI_SUCCESS; 585 } 586 587 /** 588 Shadow all legacy16 OPROMs that haven't been shadowed. 589 Warning: Use this with caution. This routine disconnects all EFI 590 drivers. If used externally then caller must re-connect EFI 591 drivers. 592 593 @param This Protocol instance pointer. 594 595 @retval EFI_SUCCESS OPROMs shadowed 596 597 **/ 598 EFI_STATUS 599 EFIAPI 600 LegacyBiosShadowAllLegacyOproms ( 601 IN EFI_LEGACY_BIOS_PROTOCOL *This 602 ) 603 { 604 LEGACY_BIOS_INSTANCE *Private; 605 606 // 607 // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; 608 // EFI_LEGACY16_TABLE *Legacy16Table; 609 // 610 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); 611 612 // 613 // LegacyBiosPlatform = Private->LegacyBiosPlatform; 614 // Legacy16Table = Private->Legacy16Table; 615 // 616 // Shadow PCI ROMs. We must do this near the end since this will kick 617 // of Native EFI drivers that may be needed to collect info for Legacy16 618 // 619 // WARNING: PciIo is gone after this call. 620 // 621 PciProgramAllInterruptLineRegisters (Private); 622 623 PciShadowRoms (Private); 624 625 // 626 // Shadow PXE base code, BIS etc. 627 // 628 // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform, 629 // &Private->OptionRom, 630 // Legacy16Table); 631 // 632 return EFI_SUCCESS; 633 } 634 635 /** 636 Get the PCI BIOS interface version. 637 638 @param Private Driver private data. 639 640 @return The PCI interface version number in Binary Coded Decimal (BCD) format. 641 E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00 642 643 **/ 644 UINT16 645 GetPciInterfaceVersion ( 646 IN LEGACY_BIOS_INSTANCE *Private 647 ) 648 { 649 EFI_IA32_REGISTER_SET Reg; 650 BOOLEAN ThunkFailed; 651 UINT16 PciInterfaceVersion; 652 653 PciInterfaceVersion = 0; 654 655 Reg.X.AX = 0xB101; 656 Reg.E.EDI = 0; 657 658 ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg); 659 if (!ThunkFailed) { 660 // 661 // From PCI Firmware 3.0 Specification: 662 // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the 663 // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the 664 // presence of the PCI function set. [BX] will further indicate the version level, with enough 665 // granularity to allow for incremental changes in the code that don't affect the function interface. 666 // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10 667 // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers. 668 // 669 if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) { 670 PciInterfaceVersion = Reg.X.BX; 671 } 672 } 673 return PciInterfaceVersion; 674 } 675 676 /** 677 Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table. 678 SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path. 679 680 @param Event Event whose notification function is being invoked. 681 @param Context The pointer to the notification function's context, 682 which is implementation-dependent. 683 684 **/ 685 VOID 686 EFIAPI 687 InstallSmbiosEventCallback ( 688 IN EFI_EVENT Event, 689 IN VOID *Context 690 ) 691 { 692 EFI_STATUS Status; 693 SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure; 694 695 // 696 // Get SMBIOS table from EFI configuration table 697 // 698 Status = EfiGetSystemConfigurationTable ( 699 &gEfiSmbiosTableGuid, 700 &mRuntimeSmbiosEntryPoint 701 ); 702 if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) { 703 return; 704 } 705 706 EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint; 707 708 // 709 // Allocate memory for SMBIOS Entry Point Structure. 710 // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE. 711 // 712 if (mReserveSmbiosEntryPoint == 0) { 713 // 714 // Entrypoint structure with fixed size is allocated only once. 715 // 716 mReserveSmbiosEntryPoint = SIZE_4GB - 1; 717 Status = gBS->AllocatePages ( 718 AllocateMaxAddress, 719 EfiReservedMemoryType, 720 EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)), 721 &mReserveSmbiosEntryPoint 722 ); 723 if (EFI_ERROR (Status)) { 724 mReserveSmbiosEntryPoint = 0; 725 return; 726 } 727 DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Entry Point Structure\n")); 728 } 729 730 if ((mStructureTableAddress != 0) && 731 (mStructureTablePages < (UINTN) EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength))) { 732 // 733 // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate 734 // 735 gBS->FreePages (mStructureTableAddress, mStructureTablePages); 736 mStructureTableAddress = 0; 737 mStructureTablePages = 0; 738 DEBUG ((EFI_D_INFO, "Original size is not enough. Re-allocate the memory.\n")); 739 } 740 741 if (mStructureTableAddress == 0) { 742 // 743 // Allocate reserved memory below 4GB. 744 // Smbios spec requires the structure table is below 4GB. 745 // 746 mStructureTableAddress = SIZE_4GB - 1; 747 mStructureTablePages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength); 748 Status = gBS->AllocatePages ( 749 AllocateMaxAddress, 750 EfiReservedMemoryType, 751 mStructureTablePages, 752 &mStructureTableAddress 753 ); 754 if (EFI_ERROR (Status)) { 755 gBS->FreePages ( 756 mReserveSmbiosEntryPoint, 757 EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)) 758 ); 759 mReserveSmbiosEntryPoint = 0; 760 mStructureTableAddress = 0; 761 mStructureTablePages = 0; 762 return; 763 } 764 DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Structure Table\n")); 765 } 766 } 767 768 /** 769 Install Driver to produce Legacy BIOS protocol. 770 771 @param ImageHandle Handle of driver image. 772 @param SystemTable Pointer to system table. 773 774 @retval EFI_SUCCESS Legacy BIOS protocol installed 775 @retval No protocol installed, unload driver. 776 777 **/ 778 EFI_STATUS 779 EFIAPI 780 LegacyBiosInstall ( 781 IN EFI_HANDLE ImageHandle, 782 IN EFI_SYSTEM_TABLE *SystemTable 783 ) 784 { 785 EFI_STATUS Status; 786 LEGACY_BIOS_INSTANCE *Private; 787 EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable; 788 EFI_PHYSICAL_ADDRESS MemoryAddress; 789 EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress; 790 VOID *MemoryPtr; 791 EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB; 792 UINTN Index; 793 UINT32 *BaseVectorMaster; 794 EFI_PHYSICAL_ADDRESS StartAddress; 795 UINT32 *ClearPtr; 796 EFI_PHYSICAL_ADDRESS MemStart; 797 UINT32 IntRedirCode; 798 UINT32 Granularity; 799 BOOLEAN DecodeOn; 800 UINT32 MemorySize; 801 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; 802 UINT64 Length; 803 UINT8 *SecureBoot; 804 EFI_EVENT InstallSmbiosEvent; 805 806 // 807 // Load this driver's image to memory 808 // 809 Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable); 810 if (EFI_ERROR (Status)) { 811 return Status; 812 } 813 814 // 815 // When UEFI Secure Boot is enabled, CSM module will not start any more. 816 // 817 SecureBoot = NULL; 818 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL); 819 if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) { 820 FreePool (SecureBoot); 821 return EFI_SECURITY_VIOLATION; 822 } 823 824 if (SecureBoot != NULL) { 825 FreePool (SecureBoot); 826 } 827 828 Private = &mPrivateData; 829 ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE)); 830 831 // 832 // Grab a copy of all the protocols we depend on. Any error would 833 // be a dispatcher bug!. 834 // 835 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu); 836 ASSERT_EFI_ERROR (Status); 837 838 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Private->Timer); 839 ASSERT_EFI_ERROR (Status); 840 841 Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion); 842 ASSERT_EFI_ERROR (Status); 843 844 Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform); 845 ASSERT_EFI_ERROR (Status); 846 847 Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259); 848 ASSERT_EFI_ERROR (Status); 849 850 Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt); 851 ASSERT_EFI_ERROR (Status); 852 853 // 854 // Locate Memory Test Protocol if exists 855 // 856 Status = gBS->LocateProtocol ( 857 &gEfiGenericMemTestProtocolGuid, 858 NULL, 859 (VOID **) &Private->GenericMemoryTest 860 ); 861 ASSERT_EFI_ERROR (Status); 862 863 // 864 // Make sure all memory from 0-640K is tested 865 // 866 for (StartAddress = 0; StartAddress < 0xa0000; ) { 867 gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor); 868 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) { 869 StartAddress = Descriptor.BaseAddress + Descriptor.Length; 870 continue; 871 } 872 Length = MIN (Descriptor.Length, 0xa0000 - StartAddress); 873 Private->GenericMemoryTest->CompatibleRangeTest ( 874 Private->GenericMemoryTest, 875 StartAddress, 876 Length 877 ); 878 StartAddress = StartAddress + Length; 879 } 880 // 881 // Make sure all memory from 1MB to 16MB is tested and added to memory map 882 // 883 for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) { 884 gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor); 885 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) { 886 StartAddress = Descriptor.BaseAddress + Descriptor.Length; 887 continue; 888 } 889 Length = MIN (Descriptor.Length, BASE_16MB - StartAddress); 890 Private->GenericMemoryTest->CompatibleRangeTest ( 891 Private->GenericMemoryTest, 892 StartAddress, 893 Length 894 ); 895 StartAddress = StartAddress + Length; 896 } 897 898 Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE; 899 900 Private->LegacyBios.Int86 = LegacyBiosInt86; 901 Private->LegacyBios.FarCall86 = LegacyBiosFarCall86; 902 Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom; 903 Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom; 904 Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot; 905 Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus; 906 Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo; 907 Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms; 908 Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi; 909 Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion; 910 Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion; 911 Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice; 912 913 Private->ImageHandle = ImageHandle; 914 915 // 916 // Enable read attribute of legacy region. 917 // 918 DecodeOn = TRUE; 919 Private->LegacyRegion->Decode ( 920 Private->LegacyRegion, 921 0xc0000, 922 0x40000, 923 &Granularity, 924 &DecodeOn 925 ); 926 // 927 // Set Cachebility for legacy region 928 // BUGBUG: Comments about this legacy region cacheability setting 929 // This setting will make D865GCHProduction CSM Unhappy 930 // 931 if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) { 932 gDS->SetMemorySpaceAttributes ( 933 0x0, 934 0xA0000, 935 EFI_MEMORY_WB 936 ); 937 gDS->SetMemorySpaceAttributes ( 938 0xc0000, 939 0x40000, 940 EFI_MEMORY_WB 941 ); 942 } 943 944 gDS->SetMemorySpaceAttributes ( 945 0xA0000, 946 0x20000, 947 EFI_MEMORY_UC 948 ); 949 950 // 951 // Allocate 0 - 4K for real mode interupt vectors and BDA. 952 // 953 AllocateLegacyMemory ( 954 AllocateAddress, 955 0, 956 1, 957 &MemoryAddress 958 ); 959 ASSERT (MemoryAddress == 0x000000000); 960 961 ClearPtr = (VOID *) ((UINTN) 0x0000); 962 963 // 964 // Initialize region from 0x0000 to 4k. This initializes interrupt vector 965 // range. 966 // 967 gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K); 968 ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00); 969 970 // 971 // Allocate pages for OPROM usage 972 // 973 MemorySize = PcdGet32 (PcdEbdaReservedMemorySize); 974 ASSERT ((MemorySize & 0xFFF) == 0); 975 976 Status = AllocateLegacyMemory ( 977 AllocateAddress, 978 CONVENTIONAL_MEMORY_TOP - MemorySize, 979 EFI_SIZE_TO_PAGES (MemorySize), 980 &MemoryAddress 981 ); 982 ASSERT_EFI_ERROR (Status); 983 984 ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize); 985 986 // 987 // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that 988 // don't use PMM but look for zeroed memory. Note that various non-BBS 989 // OpROMs expect different areas to be free 990 // 991 EbdaReservedBaseAddress = MemoryAddress; 992 MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase); 993 MemorySize = PcdGet32 (PcdOpromReservedMemorySize); 994 // 995 // Check if base address and size for reserved memory are 4KB aligned. 996 // 997 ASSERT ((MemoryAddress & 0xFFF) == 0); 998 ASSERT ((MemorySize & 0xFFF) == 0); 999 // 1000 // Check if the reserved memory is below EBDA reserved range. 1001 // 1002 ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress)); 1003 for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) { 1004 Status = AllocateLegacyMemory ( 1005 AllocateAddress, 1006 MemStart, 1007 1, 1008 &StartAddress 1009 ); 1010 if (!EFI_ERROR (Status)) { 1011 MemoryPtr = (VOID *) ((UINTN) StartAddress); 1012 ZeroMem (MemoryPtr, 0x1000); 1013 } else { 1014 DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart)); 1015 } 1016 } 1017 1018 // 1019 // Allocate low PMM memory and zero it out 1020 // 1021 MemorySize = PcdGet32 (PcdLowPmmMemorySize); 1022 ASSERT ((MemorySize & 0xFFF) == 0); 1023 Status = AllocateLegacyMemory ( 1024 AllocateMaxAddress, 1025 CONVENTIONAL_MEMORY_TOP, 1026 EFI_SIZE_TO_PAGES (MemorySize), 1027 &MemoryAddressUnder1MB 1028 ); 1029 ASSERT_EFI_ERROR (Status); 1030 1031 ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), MemorySize); 1032 1033 // 1034 // Allocate space for thunker and Init Thunker 1035 // 1036 Status = AllocateLegacyMemory ( 1037 AllocateMaxAddress, 1038 CONVENTIONAL_MEMORY_TOP, 1039 (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2, 1040 &MemoryAddress 1041 ); 1042 ASSERT_EFI_ERROR (Status); 1043 Private->IntThunk = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress; 1044 EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable; 1045 EfiToLegacy16InitTable->ThunkStart = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress; 1046 EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK)); 1047 1048 Status = LegacyBiosInitializeThunk (Private); 1049 ASSERT_EFI_ERROR (Status); 1050 1051 // 1052 // Init the legacy memory map in memory < 1 MB. 1053 // 1054 EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32) MemoryAddressUnder1MB; 1055 EfiToLegacy16InitTable->LowPmmMemory = (UINT32) MemoryAddressUnder1MB; 1056 EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize; 1057 1058 MemorySize = PcdGet32 (PcdHighPmmMemorySize); 1059 ASSERT ((MemorySize & 0xFFF) == 0); 1060 // 1061 // Allocate high PMM Memory under 16 MB 1062 // 1063 Status = AllocateLegacyMemory ( 1064 AllocateMaxAddress, 1065 0x1000000, 1066 EFI_SIZE_TO_PAGES (MemorySize), 1067 &MemoryAddress 1068 ); 1069 if (EFI_ERROR (Status)) { 1070 // 1071 // If it fails, allocate high PMM Memory under 4GB 1072 // 1073 Status = AllocateLegacyMemory ( 1074 AllocateMaxAddress, 1075 0xFFFFFFFF, 1076 EFI_SIZE_TO_PAGES (MemorySize), 1077 &MemoryAddress 1078 ); 1079 } 1080 if (!EFI_ERROR (Status)) { 1081 EfiToLegacy16InitTable->HiPmmMemory = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress; 1082 EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize; 1083 } 1084 1085 // 1086 // ShutdownAPs(); 1087 // 1088 // Start the Legacy BIOS; 1089 // 1090 Status = ShadowAndStartLegacy16 (Private); 1091 if (EFI_ERROR (Status)) { 1092 return Status; 1093 } 1094 // 1095 // Initialize interrupt redirection code and entries; 1096 // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f. 1097 // 1098 CopyMem ( 1099 Private->IntThunk->InterruptRedirectionCode, 1100 (VOID *) (UINTN) InterruptRedirectionTemplate, 1101 sizeof (Private->IntThunk->InterruptRedirectionCode) 1102 ); 1103 1104 // 1105 // Save Unexpected interrupt vector so can restore it just prior to boot 1106 // 1107 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); 1108 Private->BiosUnexpectedInt = BaseVectorMaster[0]; 1109 IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode; 1110 for (Index = 0; Index < 8; Index++) { 1111 BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4); 1112 } 1113 // 1114 // Save EFI value 1115 // 1116 Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode)); 1117 1118 // 1119 // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists 1120 // 1121 InstallSmbiosEventCallback (NULL, NULL); 1122 1123 // 1124 // Create callback function to update the size of reserved memory after LegacyBiosDxe starts 1125 // 1126 Status = gBS->CreateEventEx ( 1127 EVT_NOTIFY_SIGNAL, 1128 TPL_NOTIFY, 1129 InstallSmbiosEventCallback, 1130 NULL, 1131 &gEfiSmbiosTableGuid, 1132 &InstallSmbiosEvent 1133 ); 1134 ASSERT_EFI_ERROR (Status); 1135 1136 // 1137 // Make a new handle and install the protocol 1138 // 1139 Private->Handle = NULL; 1140 Status = gBS->InstallProtocolInterface ( 1141 &Private->Handle, 1142 &gEfiLegacyBiosProtocolGuid, 1143 EFI_NATIVE_INTERFACE, 1144 &Private->LegacyBios 1145 ); 1146 Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private); 1147 1148 DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n", 1149 (UINT8) (Private->Csm16PciInterfaceVersion >> 8), 1150 (UINT8) Private->Csm16PciInterfaceVersion 1151 )); 1152 ASSERT (Private->Csm16PciInterfaceVersion != 0); 1153 return Status; 1154 } 1155