/** @file Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "LegacyBiosInterface.h" #include #define BOOT_LEGACY_OS 0 #define BOOT_EFI_OS 1 #define BOOT_UNCONVENTIONAL_DEVICE 2 UINT32 mLoadOptionsSize = 0; UINTN mBootMode = BOOT_LEGACY_OS; VOID *mLoadOptions = NULL; BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL; BBS_BBS_DEVICE_PATH mBbsDevicePathNode; UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 }; UINTN mBbsEntry = 0; VOID *mBeerData = NULL; VOID *mServiceAreaData = NULL; UINT64 mLowWater = 0xffffffffffffffffULL; extern BBS_TABLE *mBbsTable; extern VOID *mRuntimeSmbiosEntryPoint; extern EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint; extern EFI_PHYSICAL_ADDRESS mStructureTableAddress; /** Print the BBS Table. @param BbsTable The BBS table. **/ VOID PrintBbsTable ( IN BBS_TABLE *BbsTable ) { UINT16 Index; UINT16 SubIndex; CHAR8 *String; DEBUG ((DEBUG_INFO, "\n")); DEBUG ((DEBUG_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n")); DEBUG ((DEBUG_INFO, "=================================================================\n")); for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) { // // Filter // if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { continue; } DEBUG (( DEBUG_INFO, " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x", (UINTN) Index, (UINTN) BbsTable[Index].BootPriority, (UINTN) BbsTable[Index].Bus, (UINTN) BbsTable[Index].Device, (UINTN) BbsTable[Index].Function, (UINTN) BbsTable[Index].Class, (UINTN) BbsTable[Index].SubClass, (UINTN) BbsTable[Index].DeviceType, (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags )); DEBUG (( DEBUG_INFO, " %04x:%04x %04x:%04x %04x:%04x", (UINTN) BbsTable[Index].BootHandlerSegment, (UINTN) BbsTable[Index].BootHandlerOffset, (UINTN) BbsTable[Index].MfgStringSegment, (UINTN) BbsTable[Index].MfgStringOffset, (UINTN) BbsTable[Index].DescStringSegment, (UINTN) BbsTable[Index].DescStringOffset )); // // Print DescString // String = (CHAR8 *)(((UINTN)BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset); if (String != NULL) { DEBUG ((DEBUG_INFO," (")); for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) { DEBUG ((DEBUG_INFO, "%c", String[SubIndex])); } DEBUG ((DEBUG_INFO,")")); } DEBUG ((DEBUG_INFO,"\n")); } DEBUG ((DEBUG_INFO, "\n")); return ; } /** Print the BBS Table. @param HddInfo The HddInfo table. **/ VOID PrintHddInfo ( IN HDD_INFO *HddInfo ) { UINTN Index; DEBUG ((DEBUG_INFO, "\n")); for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { DEBUG ((DEBUG_INFO, "Index - %04x\n", Index)); DEBUG ((DEBUG_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status)); DEBUG ((DEBUG_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function)); DEBUG ((DEBUG_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress)); DEBUG ((DEBUG_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress)); DEBUG ((DEBUG_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress)); DEBUG ((DEBUG_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq)); DEBUG ((DEBUG_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0])); DEBUG ((DEBUG_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0])); } DEBUG ((DEBUG_INFO, "\n")); return ; } /** Print the PCI Interrupt Line and Interrupt Pin registers. **/ VOID PrintPciInterruptRegister ( VOID ) { EFI_STATUS Status; UINTN Index; EFI_HANDLE *Handles; UINTN HandleNum; EFI_PCI_IO_PROTOCOL *PciIo; UINT8 Interrupt[2]; UINTN Segment; UINTN Bus; UINTN Device; UINTN Function; gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleNum, &Handles ); Bus = 0; Device = 0; Function = 0; DEBUG ((DEBUG_INFO, "\n")); DEBUG ((DEBUG_INFO, " bb/dd/ff interrupt line interrupt pin\n")); DEBUG ((DEBUG_INFO, "======================================\n")); for (Index = 0; Index < HandleNum; Index++) { Status = gBS->HandleProtocol (Handles[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo); if (!EFI_ERROR (Status)) { Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint8, PCI_INT_LINE_OFFSET, 2, Interrupt ); } if (!EFI_ERROR (Status)) { Status = PciIo->GetLocation ( PciIo, &Segment, &Bus, &Device, &Function ); } if (!EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, " %02x/%02x/%02x 0x%02x 0x%02x\n", Bus, Device, Function, Interrupt[0], Interrupt[1])); } } DEBUG ((DEBUG_INFO, "\n")); if (Handles != NULL) { FreePool (Handles); } } /** Identify drive data must be updated to actual parameters before boot. @param IdentifyDriveData ATA Identify Data **/ VOID UpdateIdentifyDriveData ( IN UINT8 *IdentifyDriveData ); /** Update SIO data. @param Private Legacy BIOS Instance data @retval EFI_SUCCESS Removable media not present **/ EFI_STATUS UpdateSioData ( IN LEGACY_BIOS_INSTANCE *Private ) { EFI_STATUS Status; UINTN Index; UINTN Index1; UINT8 LegacyInterrupts[16]; EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable; UINTN RoutingTableEntries; EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable; UINTN NumberPriorityEntries; EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; UINT8 HddIrq; UINT16 LegacyInt; UINT16 LegMask; UINT32 Register; UINTN HandleCount; EFI_HANDLE *HandleBuffer; EFI_ISA_IO_PROTOCOL *IsaIo; LegacyInt = 0; HandleBuffer = NULL; EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; LegacyBiosBuildSioData (Private); SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0); // // Create list of legacy interrupts. // for (Index = 0; Index < 4; Index++) { LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq; } for (Index = 4; Index < 7; Index++) { LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq; } LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq; // // Get Legacy Hdd IRQs. If native mode treat as PCI // for (Index = 0; Index < 2; Index++) { HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq; if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) { LegacyInterrupts[Index + 8] = HddIrq; } } Private->LegacyBiosPlatform->GetRoutingTable ( Private->LegacyBiosPlatform, (VOID *) &RoutingTable, &RoutingTableEntries, NULL, NULL, (VOID **) &IrqPriorityTable, &NumberPriorityEntries ); // // Remove legacy interrupts from the list of PCI interrupts available. // for (Index = 0; Index <= 0x0b; Index++) { for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) { if (LegacyInterrupts[Index] != 0) { LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index])); if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) { IrqPriorityTable[Index1].Used = LEGACY_USED; } } } } Private->Legacy8259->GetMask ( Private->Legacy8259, &LegMask, NULL, NULL, NULL ); // // Set SIO interrupts and disable mouse. Let mouse driver // re-enable it. // LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000); Private->Legacy8259->SetMask ( Private->Legacy8259, &LegMask, NULL, NULL, NULL ); // // Disable mouse in keyboard controller // Register = 0xA7; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiIsaIoProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return Status; } for (Index = 0; Index < HandleCount; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo ); ASSERT_EFI_ERROR (Status); IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register); } if (HandleBuffer != NULL) { FreePool (HandleBuffer); } return EFI_SUCCESS; } /** Identify drive data must be updated to actual parameters before boot. This requires updating the checksum, if it exists. @param IdentifyDriveData ATA Identify Data @param Checksum checksum of the ATA Identify Data @retval EFI_SUCCESS checksum calculated @retval EFI_SECURITY_VIOLATION IdentifyData invalid **/ EFI_STATUS CalculateIdentifyDriveChecksum ( IN UINT8 *IdentifyDriveData, OUT UINT8 *Checksum ) { UINTN Index; UINT8 LocalChecksum; LocalChecksum = 0; *Checksum = 0; if (IdentifyDriveData[510] != 0xA5) { return EFI_SECURITY_VIOLATION; } for (Index = 0; Index < 512; Index++) { LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]); } *Checksum = LocalChecksum; return EFI_SUCCESS; } /** Identify drive data must be updated to actual parameters before boot. @param IdentifyDriveData ATA Identify Data **/ VOID UpdateIdentifyDriveData ( IN UINT8 *IdentifyDriveData ) { UINT16 NumberCylinders; UINT16 NumberHeads; UINT16 NumberSectorsTrack; UINT32 CapacityInSectors; UINT8 OriginalChecksum; UINT8 FinalChecksum; EFI_STATUS Status; ATAPI_IDENTIFY *ReadInfo; // // Status indicates if Integrity byte is correct. Checksum should be // 0 if valid. // ReadInfo = (ATAPI_IDENTIFY *) IdentifyDriveData; Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum); if (OriginalChecksum != 0) { Status = EFI_SECURITY_VIOLATION; } // // If NumberCylinders = 0 then do data(Controller present but don drive attached). // NumberCylinders = ReadInfo->Raw[1]; if (NumberCylinders != 0) { ReadInfo->Raw[54] = NumberCylinders; NumberHeads = ReadInfo->Raw[3]; ReadInfo->Raw[55] = NumberHeads; NumberSectorsTrack = ReadInfo->Raw[6]; ReadInfo->Raw[56] = NumberSectorsTrack; // // Copy Multisector info and set valid bit. // ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100); CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack)); ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16); ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff); if (Status == EFI_SUCCESS) { // // Forece checksum byte to 0 and get new checksum. // ReadInfo->Raw[255] &= 0xff; CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum); // // Force new checksum such that sum is 0. // FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum); ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8)); } } } /** Identify drive data must be updated to actual parameters before boot. Do for all drives. @param Private Legacy BIOS Instance data **/ VOID UpdateAllIdentifyDriveData ( IN LEGACY_BIOS_INSTANCE *Private ) { UINTN Index; HDD_INFO *HddInfo; HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0]; for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { // // Each controller can have 2 devices. Update for each device // if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) { UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0])); } if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) { UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0])); } } } /** Enable ide controller. This gets disabled when LegacyBoot.c is about to run the Option ROMs. @param Private Legacy BIOS Instance data **/ VOID EnableIdeController ( IN LEGACY_BIOS_INSTANCE *Private ) { EFI_PCI_IO_PROTOCOL *PciIo; EFI_STATUS Status; EFI_HANDLE IdeController; UINT8 ByteBuffer; UINTN HandleCount; EFI_HANDLE *HandleBuffer; Status = Private->LegacyBiosPlatform->GetPlatformHandle ( Private->LegacyBiosPlatform, EfiGetPlatformIdeHandle, 0, &HandleBuffer, &HandleCount, NULL ); if (!EFI_ERROR (Status)) { IdeController = HandleBuffer[0]; Status = gBS->HandleProtocol ( IdeController, &gEfiPciIoProtocolGuid, (VOID **) &PciIo ); ByteBuffer = 0x1f; if (!EFI_ERROR (Status)) { PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer); } } } /** Enable ide controller. This gets disabled when LegacyBoot.c is about to run the Option ROMs. @param Private Legacy BIOS Instance data **/ VOID EnableAllControllers ( IN LEGACY_BIOS_INSTANCE *Private ) { UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINTN Index; EFI_PCI_IO_PROTOCOL *PciIo; PCI_TYPE01 PciConfigHeader; EFI_STATUS Status; // // // EnableIdeController (Private); // // Assumption is table is built from low bus to high bus numbers. // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &HandleBuffer ); ASSERT_EFI_ERROR (Status); for (Index = 0; Index < HandleCount; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo ); ASSERT_EFI_ERROR (Status); PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint32, 0, sizeof (PciConfigHeader) / sizeof (UINT32), &PciConfigHeader ); // // We do not enable PPB here. This is for HotPlug Consideration. // The Platform HotPlug Driver is responsible for Padding enough hot plug // resources. It is also responsible for enable this bridge. If it // does not pad it. It will cause some early Windows fail to installation. // If the platform driver does not pad resource for PPB, PPB should be in // un-enabled state to let Windows know that this PPB is not configured by // BIOS. So Windows will allocate default resource for PPB. // // The reason for why we enable the command register is: // The CSM will use the IO bar to detect some IRQ status, if the command // is disabled, the IO resource will be out of scope. // For example: // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ // comes up, the handle will check the IO space to identify is the // controller generated the IRQ source. // If the IO command is not enabled, the IRQ handler will has wrong // information. It will cause IRQ storm when the correctly IRQ handler fails // to run. // if (!(IS_PCI_VGA (&PciConfigHeader) || IS_PCI_OLD_VGA (&PciConfigHeader) || IS_PCI_IDE (&PciConfigHeader) || IS_PCI_P2P (&PciConfigHeader) || IS_PCI_P2P_SUB (&PciConfigHeader) || IS_PCI_LPC (&PciConfigHeader) )) { PciConfigHeader.Hdr.Command |= 0x1f; PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command); } } } /** The following routines are identical in operation, so combine for code compaction: EfiGetPlatformBinaryGetMpTable EfiGetPlatformBinaryGetOemIntData EfiGetPlatformBinaryGetOem32Data EfiGetPlatformBinaryGetOem16Data @param This Protocol instance pointer. @param Id Table/Data identifier @retval EFI_SUCCESS Success @retval EFI_INVALID_PARAMETER Invalid ID @retval EFI_OUT_OF_RESOURCES no resource to get data or table **/ EFI_STATUS LegacyGetDataOrTable ( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN EFI_GET_PLATFORM_INFO_MODE Id ) { VOID *Table; UINT32 TablePtr; UINTN TableSize; UINTN Alignment; UINTN Location; EFI_STATUS Status; EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; EFI_COMPATIBILITY16_TABLE *Legacy16Table; EFI_IA32_REGISTER_SET Regs; LEGACY_BIOS_INSTANCE *Private; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); LegacyBiosPlatform = Private->LegacyBiosPlatform; Legacy16Table = Private->Legacy16Table; // // Phase 1 - get an address allocated in 16-bit code // while (TRUE) { switch (Id) { case EfiGetPlatformBinaryMpTable: case EfiGetPlatformBinaryOemIntData: case EfiGetPlatformBinaryOem32Data: case EfiGetPlatformBinaryOem16Data: { Status = LegacyBiosPlatform->GetPlatformInfo ( LegacyBiosPlatform, Id, (VOID *) &Table, &TableSize, &Location, &Alignment, 0, 0 ); DEBUG ((DEBUG_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status)); DEBUG ((DEBUG_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment)); break; } default: { return EFI_INVALID_PARAMETER; } } if (EFI_ERROR (Status)) { return Status; } ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16GetTableAddress; Regs.X.CX = (UINT16) TableSize; Regs.X.BX = (UINT16) Location; Regs.X.DX = (UINT16) Alignment; Private->LegacyBios.FarCall86 ( This, Private->Legacy16CallSegment, Private->Legacy16CallOffset, &Regs, NULL, 0 ); if (Regs.X.AX != 0) { DEBUG ((DEBUG_ERROR, "Table ID %x length insufficient\n", Id)); return EFI_OUT_OF_RESOURCES; } else { break; } } // // Phase 2 Call routine second time with address to allow address adjustment // Status = LegacyBiosPlatform->GetPlatformInfo ( LegacyBiosPlatform, Id, (VOID *) &Table, &TableSize, &Location, &Alignment, Regs.X.DS, Regs.X.BX ); switch (Id) { case EfiGetPlatformBinaryMpTable: { Legacy16Table->MpTablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); Legacy16Table->MpTableLength = (UINT32)TableSize; DEBUG ((DEBUG_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr)); break; } case EfiGetPlatformBinaryOemIntData: { Legacy16Table->OemIntSegment = Regs.X.DS; Legacy16Table->OemIntOffset = Regs.X.BX; DEBUG ((DEBUG_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset)); break; } case EfiGetPlatformBinaryOem32Data: { Legacy16Table->Oem32Segment = Regs.X.DS; Legacy16Table->Oem32Offset = Regs.X.BX; DEBUG ((DEBUG_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset)); break; } case EfiGetPlatformBinaryOem16Data: { // // Legacy16Table->Oem16Segment = Regs.X.DS; // Legacy16Table->Oem16Offset = Regs.X.BX; DEBUG ((DEBUG_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset)); break; } default: { return EFI_INVALID_PARAMETER; } } if (EFI_ERROR (Status)) { return Status; } // // Phase 3 Copy table to final location // TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); CopyMem ( (VOID *) (UINTN)TablePtr, Table, TableSize ); return EFI_SUCCESS; } /** Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot. **/ VOID CreateSmbiosTableInReservedMemory ( VOID ) { SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure; if ((mRuntimeSmbiosEntryPoint == NULL) || (mReserveSmbiosEntryPoint == 0) || (mStructureTableAddress == 0)) { return; } EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint; // // Copy SMBIOS Entry Point Structure // CopyMem ( (VOID *)(UINTN) mReserveSmbiosEntryPoint, EntryPointStructure, EntryPointStructure->EntryPointLength ); // // Copy SMBIOS Structure Table into EfiReservedMemoryType memory // CopyMem ( (VOID *)(UINTN) mStructureTableAddress, (VOID *)(UINTN) EntryPointStructure->TableAddress, EntryPointStructure->TableLength ); // // Update TableAddress in Entry Point Structure // EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN) mReserveSmbiosEntryPoint; EntryPointStructure->TableAddress = (UINT32)(UINTN) mStructureTableAddress; // // Fixup checksums in the Entry Point Structure // EntryPointStructure->IntermediateChecksum = 0; EntryPointStructure->EntryPointStructureChecksum = 0; EntryPointStructure->IntermediateChecksum = CalculateCheckSum8 ( (UINT8 *) EntryPointStructure + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString), EntryPointStructure->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString) ); EntryPointStructure->EntryPointStructureChecksum = CalculateCheckSum8 ((UINT8 *) EntryPointStructure, EntryPointStructure->EntryPointLength); } /** Assign drive number to legacy HDD drives prior to booting an EFI aware OS so the OS can access drives without an EFI driver. Note: BBS compliant drives ARE NOT available until this call by either shell or EFI. @param This Protocol instance pointer. @retval EFI_SUCCESS Drive numbers assigned **/ EFI_STATUS GenericLegacyBoot ( IN EFI_LEGACY_BIOS_PROTOCOL *This ) { EFI_STATUS Status; LEGACY_BIOS_INSTANCE *Private; EFI_IA32_REGISTER_SET Regs; EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; UINTN CopySize; VOID *AcpiPtr; HDD_INFO *HddInfo; HDD_INFO *LocalHddInfo; UINTN Index; EFI_COMPATIBILITY16_TABLE *Legacy16Table; UINT32 *BdaPtr; UINT16 HddCount; UINT16 BbsCount; BBS_TABLE *LocalBbsTable; UINT32 *BaseVectorMaster; EFI_TIME BootTime; UINT32 LocalTime; EFI_HANDLE IdeController; UINTN HandleCount; EFI_HANDLE *HandleBuffer; VOID *AcpiTable; UINTN ShadowAddress; UINT32 Granularity; LocalHddInfo = NULL; HddCount = 0; BbsCount = 0; LocalBbsTable = NULL; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); DEBUG_CODE ( DEBUG ((DEBUG_ERROR, "Start of legacy boot\n")); ); Legacy16Table = Private->Legacy16Table; EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; HddInfo = &EfiToLegacy16BootTable->HddInfo[0]; LegacyBiosPlatform = Private->LegacyBiosPlatform; EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION; EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION; // // If booting to a legacy OS then force HDD drives to the appropriate // boot mode by calling GetIdeHandle. // A reconnect -r can force all HDDs back to native mode. // IdeController = NULL; if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { Status = LegacyBiosPlatform->GetPlatformHandle ( Private->LegacyBiosPlatform, EfiGetPlatformIdeHandle, 0, &HandleBuffer, &HandleCount, NULL ); if (!EFI_ERROR (Status)) { IdeController = HandleBuffer[0]; } } // // Unlock the Legacy BIOS region // Private->LegacyRegion->UnLock ( Private->LegacyRegion, 0xE0000, 0x20000, &Granularity ); // // Reconstruct the Legacy16 boot memory map // LegacyBiosBuildE820 (Private, &CopySize); if (CopySize > Private->Legacy16Table->E820Length) { ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16GetTableAddress; Regs.X.BX = (UINT16) 0x0; // Any region Regs.X.CX = (UINT16) CopySize; Regs.X.DX = (UINT16) 0x4; // Alignment Private->LegacyBios.FarCall86 ( &Private->LegacyBios, Private->Legacy16Table->Compatibility16CallSegment, Private->Legacy16Table->Compatibility16CallOffset, &Regs, NULL, 0 ); Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); Private->Legacy16Table->E820Length = (UINT32) CopySize; if (Regs.X.AX != 0) { DEBUG ((DEBUG_ERROR, "Legacy16 E820 length insufficient\n")); return EFI_OUT_OF_RESOURCES; } else { CopyMem ( (VOID *)(UINTN) Private->Legacy16Table->E820Pointer, Private->E820Table, CopySize ); } } else { CopyMem ( (VOID *)(UINTN) Private->Legacy16Table->E820Pointer, Private->E820Table, CopySize ); Private->Legacy16Table->E820Length = (UINT32) CopySize; } // // We do not ASSERT if SmbiosTable not found. It is possible that a platform does not produce SmbiosTable. // if (mReserveSmbiosEntryPoint == 0) { DEBUG ((DEBUG_INFO, "Smbios table is not found!\n")); } CreateSmbiosTableInReservedMemory (); EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)mReserveSmbiosEntryPoint; AcpiTable = NULL; Status = EfiGetSystemConfigurationTable ( &gEfiAcpi20TableGuid, &AcpiTable ); if (EFI_ERROR (Status)) { Status = EfiGetSystemConfigurationTable ( &gEfiAcpi10TableGuid, &AcpiTable ); } // // We do not ASSERT if AcpiTable not found. It is possible that a platform does not produce AcpiTable. // if (AcpiTable == NULL) { DEBUG ((DEBUG_INFO, "ACPI table is not found!\n")); } EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable; // // Get RSD Ptr table rev at offset 15 decimal // Rev = 0 Length is 20 decimal // Rev != 0 Length is UINT32 at offset 20 decimal // if (AcpiTable != NULL) { AcpiPtr = AcpiTable; if (*((UINT8 *) AcpiPtr + 15) == 0) { CopySize = 20; } else { AcpiPtr = ((UINT8 *) AcpiPtr + 20); CopySize = (*(UINT32 *) AcpiPtr); } CopyMem ( (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer, AcpiTable, CopySize ); } // // Make sure all PCI Interrupt Line register are programmed to match 8259 // PciProgramAllInterruptLineRegisters (Private); // // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters // can lock it. // Private->LegacyRegion->UnLock ( Private->LegacyRegion, Private->BiosStart, Private->LegacyBiosImageSize, &Granularity ); // // Configure Legacy Device Magic // // Only do this code if booting legacy OS // if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { UpdateSioData (Private); } // // Setup BDA and EBDA standard areas before Legacy Boot // ACCESS_PAGE0_CODE ( LegacyBiosCompleteBdaBeforeBoot (Private); ); LegacyBiosCompleteStandardCmosBeforeBoot (Private); // // We must build IDE data, if it hasn't been done, before PciShadowRoms // to insure EFI drivers are connected. // LegacyBiosBuildIdeData (Private, &HddInfo, 1); UpdateAllIdentifyDriveData (Private); // // Clear IO BAR, if IDE controller in legacy mode. // InitLegacyIdeController (IdeController); // // Generate number of ticks since midnight for BDA. DOS requires this // for its time. We have to make assumptions as to how long following // code takes since after PciShadowRoms PciIo is gone. Place result in // 40:6C-6F // // Adjust value by 1 second. // gRT->GetTime (&BootTime, NULL); LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second; LocalTime += 1; // // Multiply result by 18.2 for number of ticks since midnight. // Use 182/10 to avoid floating point math. // LocalTime = (LocalTime * 182) / 10; ACCESS_PAGE0_CODE ( BdaPtr = (UINT32 *) (UINTN)0x46C; *BdaPtr = LocalTime; ); // // Shadow PCI ROMs. We must do this near the end since this will kick // of Native EFI drivers that may be needed to collect info for Legacy16 // // WARNING: PciIo is gone after this call. // PciShadowRoms (Private); // // Shadow PXE base code, BIS etc. // Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity); ShadowAddress = Private->OptionRom; Private->LegacyBiosPlatform->PlatformHooks ( Private->LegacyBiosPlatform, EfiPlatformHookShadowServiceRoms, 0, 0, &ShadowAddress, Legacy16Table, NULL ); Private->OptionRom = (UINT32)ShadowAddress; // // Register Legacy SMI Handler // LegacyBiosPlatform->SmmInit ( LegacyBiosPlatform, EfiToLegacy16BootTable ); // // Let platform code know the boot options // LegacyBiosGetBbsInfo ( This, &HddCount, &LocalHddInfo, &BbsCount, &LocalBbsTable ); DEBUG_CODE ( PrintPciInterruptRegister (); PrintBbsTable (LocalBbsTable); PrintHddInfo (LocalHddInfo); ); // // If drive wasn't spun up then BuildIdeData may have found new drives. // Need to update BBS boot priority. // for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) && (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY) ) { LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY; } if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) && (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY) ) { LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY; } } Private->LegacyRegion->UnLock ( Private->LegacyRegion, 0xc0000, 0x40000, &Granularity ); LegacyBiosPlatform->PrepareToBoot ( LegacyBiosPlatform, mBbsDevicePathPtr, mBbsTable, mLoadOptionsSize, mLoadOptions, (VOID *) &Private->IntThunk->EfiToLegacy16BootTable ); // // If no boot device return to BDS // if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { for (Index = 0; Index < BbsCount; Index++){ if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) && (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) && (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) { break; } } if (Index == BbsCount) { return EFI_DEVICE_ERROR; } } // // Let the Legacy16 code know the device path type for legacy boot // EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType; // // Copy MP table, if it exists. // LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable); if (!Private->LegacyBootEntered) { // // Copy OEM INT Data, if it exists. Note: This code treats any data // as a bag of bits and knows nothing of the contents nor cares. // Contents are IBV specific. // LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData); // // Copy OEM16 Data, if it exists.Note: This code treats any data // as a bag of bits and knows nothing of the contents nor cares. // Contents are IBV specific. // LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data); // // Copy OEM32 Data, if it exists.Note: This code treats any data // as a bag of bits and knows nothing of the contents nor cares. // Contents are IBV specific. // LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data); } // // Call into Legacy16 code to prepare for INT 19h // ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16PrepareToBoot; // // Pass in handoff data // Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable); Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINTN)EfiToLegacy16BootTable); Private->LegacyBios.FarCall86 ( This, Private->Legacy16CallSegment, Private->Legacy16CallOffset, &Regs, NULL, 0 ); if (Regs.X.AX != 0) { return EFI_DEVICE_ERROR; } // // Lock the Legacy BIOS region // Private->LegacyRegion->Lock ( Private->LegacyRegion, 0xc0000, 0x40000, &Granularity ); if ((Private->Legacy16Table->TableLength >= OFFSET_OF (EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) && ((Private->Legacy16Table->UmaAddress != 0) && (Private->Legacy16Table->UmaSize != 0))) { // // Here we could reduce UmaAddress down as far as Private->OptionRom, taking into // account the granularity of the access control. // DEBUG((DEBUG_INFO, "Unlocking UMB RAM region 0x%x-0x%x\n", Private->Legacy16Table->UmaAddress, Private->Legacy16Table->UmaAddress + Private->Legacy16Table->UmaSize)); Private->LegacyRegion->UnLock ( Private->LegacyRegion, Private->Legacy16Table->UmaAddress, Private->Legacy16Table->UmaSize, &Granularity ); } // // Lock attributes of the Legacy Region if chipset supports // Private->LegacyRegion->BootLock ( Private->LegacyRegion, 0xc0000, 0x40000, &Granularity ); // // Call into Legacy16 code to do the INT 19h // EnableAllControllers (Private); if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { // // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT // EfiSignalEventLegacyBoot (); // // Report Status Code to indicate legacy boot event was signalled // REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT) ); DEBUG ((DEBUG_INFO, "Legacy INT19 Boot...\n")); // // Disable DXE Timer while executing in real mode // Private->Timer->SetTimerPeriod (Private->Timer, 0); // // Save and disable interrupt of debug timer // SaveAndSetDebugTimerInterrupt (FALSE); // // Put the 8259 into its legacy mode by reprogramming the vector bases // Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE); // // PC History // The original PC used INT8-F for master PIC. Since these mapped over // processor exceptions TIANO moved the master PIC to INT68-6F. // We need to set these back to the Legacy16 unexpected interrupt(saved // in LegacyBios.c) since some OS see that these have values different from // what is expected and invoke them. Since the legacy OS corrupts EFI // memory, there is no handler for these interrupts and OS blows up. // // We need to save the TIANO values for the rare case that the Legacy16 // code cannot boot but knows memory hasn't been destroyed. // // To compound the problem, video takes over one of these INTS and must be // be left. // @bug - determine if video hooks INT(in which case we must find new // set of TIANO vectors) or takes it over. // // ACCESS_PAGE0_CODE ( BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); for (Index = 0; Index < 8; Index++) { Private->ThunkSavedInt[Index] = BaseVectorMaster[Index]; if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) { BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt); } } ); ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16Boot; Private->LegacyBios.FarCall86 ( This, Private->Legacy16CallSegment, Private->Legacy16CallOffset, &Regs, NULL, 0 ); ACCESS_PAGE0_CODE ( BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); for (Index = 0; Index < 8; Index++) { BaseVectorMaster[Index] = Private->ThunkSavedInt[Index]; } ); } Private->LegacyBootEntered = TRUE; if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { // // Should never return unless never passed control to 0:7c00(first stage // OS loader) and only then if no bootable device found. // return EFI_DEVICE_ERROR; } else { // // If boot to EFI then expect to return to caller // return EFI_SUCCESS; } } /** Assign drive number to legacy HDD drives prior to booting an EFI aware OS so the OS can access drives without an EFI driver. Note: BBS compliant drives ARE NOT available until this call by either shell or EFI. @param This Protocol instance pointer. @param BbsCount Number of BBS_TABLE structures @param BbsTable List BBS entries @retval EFI_SUCCESS Drive numbers assigned **/ EFI_STATUS EFIAPI LegacyBiosPrepareToBootEfi ( IN EFI_LEGACY_BIOS_PROTOCOL *This, OUT UINT16 *BbsCount, OUT BBS_TABLE **BbsTable ) { EFI_STATUS Status; EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; LEGACY_BIOS_INSTANCE *Private; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; mBootMode = BOOT_EFI_OS; mBbsDevicePathPtr = NULL; Status = GenericLegacyBoot (This); *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); return Status; } /** To boot from an unconventional device like parties and/or execute HDD diagnostics. @param This Protocol instance pointer. @param Attributes How to interpret the other input parameters @param BbsEntry The 0-based index into the BbsTable for the parent device. @param BeerData Pointer to the 128 bytes of ram BEER data. @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The caller must provide a pointer to the specific Service Area and not the start all Service Areas. @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error. ***/ EFI_STATUS EFIAPI LegacyBiosBootUnconventionalDevice ( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UDC_ATTRIBUTES Attributes, IN UINTN BbsEntry, IN VOID *BeerData, IN VOID *ServiceAreaData ) { EFI_STATUS Status; EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; LEGACY_BIOS_INSTANCE *Private; UD_TABLE *UcdTable; UINTN Index; UINT16 BootPriority; BBS_TABLE *BbsTable; BootPriority = 0; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); mBootMode = BOOT_UNCONVENTIONAL_DEVICE; mBbsDevicePathPtr = &mBbsDevicePathNode; mAttributes = Attributes; mBbsEntry = BbsEntry; mBeerData = BeerData, mServiceAreaData = ServiceAreaData; EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; // // Do input parameter checking // if ((Attributes.DirectoryServiceValidity == 0) && (Attributes.RabcaUsedFlag == 0) && (Attributes.ExecuteHddDiagnosticsFlag == 0) ) { return EFI_INVALID_PARAMETER; } if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) || (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL)) ) { return EFI_INVALID_PARAMETER; } UcdTable = (UD_TABLE *) AllocatePool ( sizeof (UD_TABLE) ); if (NULL == UcdTable) { return EFI_OUT_OF_RESOURCES; } EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable; UcdTable->Attributes = Attributes; UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry; // // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM // to assign drive numbers but bot boot from. Only newly created entries // will be valid. // BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) { BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM; } // // If parent is onboard IDE then assign controller & device number // else they are 0. // if (BbsEntry < MAX_IDE_CONTROLLER * 2) { UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2); } if (BeerData != NULL) { CopyMem ( (VOID *) UcdTable->BeerData, BeerData, (UINTN) 128 ); } if (ServiceAreaData != NULL) { CopyMem ( (VOID *) UcdTable->ServiceAreaData, ServiceAreaData, (UINTN) 64 ); } // // For each new entry do the following: // 1. Increment current number of BBS entries // 2. Copy parent entry to new entry. // 3. Zero out BootHandler Offset & segment // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics // and Floppy(0x01) for PARTIES boot. // 5. Assign new priority. // if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) { EfiToLegacy16BootTable->NumberBbsEntries += 1; CopyMem ( (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority, (VOID *) &BbsTable[BbsEntry].BootPriority, sizeof (BBS_TABLE) ); BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0; BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0; BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80; UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1); BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority; BootPriority += 1; // // Set device type as BBS_TYPE_DEV for PARTIES diagnostic // mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV; } if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) { EfiToLegacy16BootTable->NumberBbsEntries += 1; CopyMem ( (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority, (VOID *) &BbsTable[BbsEntry].BootPriority, sizeof (BBS_TABLE) ); BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0; BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0; BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01; UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1); BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority; // // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy // mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY; } // // Build the BBS Device Path for this boot selection // mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH; mBbsDevicePathNode.Header.SubType = BBS_BBS_DP; SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH)); mBbsDevicePathNode.StatusFlag = 0; mBbsDevicePathNode.String[0] = 0; Status = GenericLegacyBoot (This); return Status; } /** Attempt to legacy boot the BootOption. If the EFI contexted has been compromised this function will not return. @param This Protocol instance pointer. @param BbsDevicePath EFI Device Path from BootXXXX variable. @param LoadOptionsSize Size of LoadOption in size. @param LoadOptions LoadOption from BootXXXX variable @retval EFI_SUCCESS Removable media not present **/ EFI_STATUS EFIAPI LegacyBiosLegacyBoot ( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN BBS_BBS_DEVICE_PATH *BbsDevicePath, IN UINT32 LoadOptionsSize, IN VOID *LoadOptions ) { EFI_STATUS Status; mBbsDevicePathPtr = BbsDevicePath; mLoadOptionsSize = LoadOptionsSize; mLoadOptions = LoadOptions; mBootMode = BOOT_LEGACY_OS; Status = GenericLegacyBoot (This); return Status; } /** Convert EFI Memory Type to E820 Memory Type. @param Type EFI Memory Type @return ACPI Memory Type for EFI Memory Type **/ EFI_ACPI_MEMORY_TYPE EfiMemoryTypeToE820Type ( IN UINT32 Type ) { switch (Type) { case EfiLoaderCode: case EfiLoaderData: case EfiBootServicesCode: case EfiBootServicesData: case EfiConventionalMemory: // // The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are // usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept. // In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData // should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS. // case EfiRuntimeServicesCode: case EfiRuntimeServicesData: return EfiAcpiAddressRangeMemory; case EfiPersistentMemory: return EfiAddressRangePersistentMemory; case EfiACPIReclaimMemory: return EfiAcpiAddressRangeACPI; case EfiACPIMemoryNVS: return EfiAcpiAddressRangeNVS; // // All other types map to reserved. // Adding the code just waists FLASH space. // // case EfiReservedMemoryType: // case EfiUnusableMemory: // case EfiMemoryMappedIO: // case EfiMemoryMappedIOPortSpace: // case EfiPalCode: // default: return EfiAcpiAddressRangeReserved; } } /** Build the E820 table. @param Private Legacy BIOS Instance data @param Size Size of E820 Table @retval EFI_SUCCESS It should always work. **/ EFI_STATUS LegacyBiosBuildE820 ( IN LEGACY_BIOS_INSTANCE *Private, OUT UINTN *Size ) { EFI_STATUS Status; EFI_E820_ENTRY64 *E820Table; EFI_MEMORY_DESCRIPTOR *EfiMemoryMap; EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd; EFI_MEMORY_DESCRIPTOR *EfiEntry; EFI_MEMORY_DESCRIPTOR *NextEfiEntry; EFI_MEMORY_DESCRIPTOR TempEfiEntry; UINTN EfiMemoryMapSize; UINTN EfiMapKey; UINTN EfiDescriptorSize; UINT32 EfiDescriptorVersion; UINTN Index; EFI_PEI_HOB_POINTERS Hob; EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; UINTN TempIndex; UINTN IndexSort; UINTN TempNextIndex; EFI_E820_ENTRY64 TempE820; EFI_ACPI_MEMORY_TYPE TempType; BOOLEAN ChangedFlag; UINTN Above1MIndex; UINT64 MemoryBlockLength; E820Table = (EFI_E820_ENTRY64 *) Private->E820Table; // // Get the EFI memory map. // EfiMemoryMapSize = 0; EfiMemoryMap = NULL; Status = gBS->GetMemoryMap ( &EfiMemoryMapSize, EfiMemoryMap, &EfiMapKey, &EfiDescriptorSize, &EfiDescriptorVersion ); ASSERT (Status == EFI_BUFFER_TOO_SMALL); do { // // Use size returned for the AllocatePool. // We don't just multiply by 2 since the "for" loop below terminates on // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwise // we process bogus entries and create bogus E820 entries. // EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize); ASSERT (EfiMemoryMap != NULL); Status = gBS->GetMemoryMap ( &EfiMemoryMapSize, EfiMemoryMap, &EfiMapKey, &EfiDescriptorSize, &EfiDescriptorVersion ); if (EFI_ERROR (Status)) { FreePool (EfiMemoryMap); } } while (Status == EFI_BUFFER_TOO_SMALL); ASSERT_EFI_ERROR (Status); // // Punch in the E820 table for memory less than 1 MB. // Assume ZeroMem () has been done on data structure. // // // First entry is 0 to (640k - EBDA) // ACCESS_PAGE0_CODE ( E820Table[0].BaseAddr = 0; E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4); E820Table[0].Type = EfiAcpiAddressRangeMemory; ); // // Second entry is (640k - EBDA) to 640k // E820Table[1].BaseAddr = E820Table[0].Length; E820Table[1].Length = (UINT64) ((640 * 1024) - E820Table[0].Length); E820Table[1].Type = EfiAcpiAddressRangeReserved; // // Third Entry is legacy BIOS // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas // to page in memory under 1MB. // Omit region from 0xE0000 to start of BIOS, if any. This can be // used for a multiple reasons including OPROMS. // // // The CSM binary image size is not the actually size that CSM binary used, // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary. // E820Table[2].BaseAddr = 0xE0000; E820Table[2].Length = 0x20000; E820Table[2].Type = EfiAcpiAddressRangeReserved; Above1MIndex = 2; // // Process the EFI map to produce E820 map; // // // Sort memory map from low to high // EfiEntry = EfiMemoryMap; NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); while (EfiEntry < EfiMemoryMapEnd) { while (NextEfiEntry < EfiMemoryMapEnd) { if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) { CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); } NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize); } EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); } EfiEntry = EfiMemoryMap; EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) { MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12)); if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) { // // Skip the memory block if under 1MB // } else { if (EfiEntry->PhysicalStart < 0x100000) { // // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB // MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart; EfiEntry->PhysicalStart = 0x100000; } // // Convert memory type to E820 type // TempType = EfiMemoryTypeToE820Type (EfiEntry->Type); if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) { // // Grow an existing entry // E820Table[Index].Length += MemoryBlockLength; } else { // // Make a new entry // ++Index; E820Table[Index].BaseAddr = EfiEntry->PhysicalStart; E820Table[Index].Length = MemoryBlockLength; E820Table[Index].Type = TempType; } } EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); } FreePool (EfiMemoryMap); // // Process the reserved memory map to produce E820 map ; // for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { ResourceHob = Hob.ResourceDescriptor; if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) || (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) || (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) ) && (ResourceHob->PhysicalStart > 0x100000) && (Index < EFI_MAX_E820_ENTRY - 1)) { ++Index; E820Table[Index].BaseAddr = ResourceHob->PhysicalStart; E820Table[Index].Length = ResourceHob->ResourceLength; E820Table[Index].Type = EfiAcpiAddressRangeReserved; } } } Index ++; Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index; Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index; Private->NumberE820Entries = (UINT32)Index; *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64)); // // Sort E820Table from low to high // for (TempIndex = 0; TempIndex < Index; TempIndex++) { ChangedFlag = FALSE; for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) { if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) { ChangedFlag = TRUE; TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr; TempE820.Length = E820Table[TempNextIndex - 1].Length; TempE820.Type = E820Table[TempNextIndex - 1].Type; E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr; E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length; E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type; E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr; E820Table[TempNextIndex].Length = TempE820.Length; E820Table[TempNextIndex].Type = TempE820.Type; } } if (!ChangedFlag) { break; } } // // Remove the overlap range // for (TempIndex = 1; TempIndex < Index; TempIndex++) { if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr && ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >= (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) { // //Overlap range is found // ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type); if (TempIndex == Index - 1) { E820Table[TempIndex].BaseAddr = 0; E820Table[TempIndex].Length = 0; E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE) 0; Index--; break; } else { for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) { E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr; E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length; E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type; } Index--; } } } Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index; Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index; Private->NumberE820Entries = (UINT32)Index; *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64)); // // Determine OS usable memory above 1MB // Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000; for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) { if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory // // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables. // if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) { Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length); } else { break; // break at first not normal memory, because SMM may use reserved memory. } } } Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb; // // Print DEBUG information // for (TempIndex = 0; TempIndex < Index; TempIndex++) { DEBUG((DEBUG_INFO, "E820[%2d]: 0x%016lx - 0x%016lx, Type = %d\n", TempIndex, E820Table[TempIndex].BaseAddr, (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length), E820Table[TempIndex].Type )); } return EFI_SUCCESS; } /** Fill in the standard BDA and EBDA stuff prior to legacy Boot @param Private Legacy BIOS Instance data @retval EFI_SUCCESS It should always work. **/ EFI_STATUS LegacyBiosCompleteBdaBeforeBoot ( IN LEGACY_BIOS_INSTANCE *Private ) { BDA_STRUC *Bda; UINT16 MachineConfig; DEVICE_PRODUCER_DATA_HEADER *SioPtr; Bda = (BDA_STRUC *) ((UINTN) 0x400); MachineConfig = 0; SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData); Bda->Com1 = SioPtr->Serial[0].Address; Bda->Com2 = SioPtr->Serial[1].Address; Bda->Com3 = SioPtr->Serial[2].Address; Bda->Com4 = SioPtr->Serial[3].Address; if (SioPtr->Serial[0].Address != 0x00) { MachineConfig += 0x200; } if (SioPtr->Serial[1].Address != 0x00) { MachineConfig += 0x200; } if (SioPtr->Serial[2].Address != 0x00) { MachineConfig += 0x200; } if (SioPtr->Serial[3].Address != 0x00) { MachineConfig += 0x200; } Bda->Lpt1 = SioPtr->Parallel[0].Address; Bda->Lpt2 = SioPtr->Parallel[1].Address; Bda->Lpt3 = SioPtr->Parallel[2].Address; if (SioPtr->Parallel[0].Address != 0x00) { MachineConfig += 0x4000; } if (SioPtr->Parallel[1].Address != 0x00) { MachineConfig += 0x4000; } if (SioPtr->Parallel[2].Address != 0x00) { MachineConfig += 0x4000; } Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount); if (SioPtr->Floppy.NumberOfFloppy != 0x00) { MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40); Bda->FloppyXRate = 0x07; } Bda->Lpt1_2Timeout = 0x1414; Bda->Lpt3_4Timeout = 0x1414; Bda->Com1_2Timeout = 0x0101; Bda->Com3_4Timeout = 0x0101; // // Force VGA and Coprocessor, indicate 101/102 keyboard // MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04)); Bda->MachineConfig = MachineConfig; return EFI_SUCCESS; } /** Fill in the standard BDA for Keyboard LEDs @param This Protocol instance pointer. @param Leds Current LED status @retval EFI_SUCCESS It should always work. **/ EFI_STATUS EFIAPI LegacyBiosUpdateKeyboardLedStatus ( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UINT8 Leds ) { LEGACY_BIOS_INSTANCE *Private; BDA_STRUC *Bda; UINT8 LocalLeds; EFI_IA32_REGISTER_SET Regs; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); ACCESS_PAGE0_CODE ( Bda = (BDA_STRUC *) ((UINTN) 0x400); LocalLeds = Leds; Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds); LocalLeds = (UINT8) (LocalLeds << 4); Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds); LocalLeds = (UINT8) (Leds & 0x20); Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds); ); // // Call into Legacy16 code to allow it to do any processing // ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16SetKeyboardLeds; Regs.H.CL = Leds; Private->LegacyBios.FarCall86 ( &Private->LegacyBios, Private->Legacy16Table->Compatibility16CallSegment, Private->Legacy16Table->Compatibility16CallOffset, &Regs, NULL, 0 ); return EFI_SUCCESS; } /** Fill in the standard CMOS stuff prior to legacy Boot @param Private Legacy BIOS Instance data @retval EFI_SUCCESS It should always work. **/ EFI_STATUS LegacyBiosCompleteStandardCmosBeforeBoot ( IN LEGACY_BIOS_INSTANCE *Private ) { UINT8 Bda; UINT8 Floppy; UINT32 Size; // // Update CMOS locations // 10 floppy // 12,19,1A - ignore as OS don't use them and there is no standard due // to large capacity drives // CMOS 14 = BDA 40:10 plus bit 3(display enabled) // ACCESS_PAGE0_CODE ( Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3); ); // // Force display enabled // Floppy = 0x00; if ((Bda & BIT0) != 0) { Floppy = BIT6; } // // Check if 2.88MB floppy set // if ((Bda & (BIT7 | BIT6)) != 0) { Floppy = (UINT8)(Floppy | BIT1); } LegacyWriteStandardCmos (CMOS_10, Floppy); LegacyWriteStandardCmos (CMOS_14, Bda); // // Force Status Register A to set rate selection bits and divider // LegacyWriteStandardCmos (CMOS_0A, 0x26); // // redo memory size since it can change // Size = (15 * SIZE_1MB) >> 10; if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) { Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10; } LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF)); LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF)); LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8)); LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8)); LegacyCalculateWriteStandardCmosChecksum (); return EFI_SUCCESS; } /** Relocate this image under 4G memory for IPF. @param ImageHandle Handle of driver image. @param SystemTable Pointer to system table. @retval EFI_SUCCESS Image successfully relocated. @retval EFI_ABORTED Failed to relocate image. **/ EFI_STATUS RelocateImageUnder4GIfNeeded ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { return EFI_SUCCESS; }