/** @file Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "LegacyBiosInterface.h" #include // Give floppy 3 states // FLOPPY_PRESENT_WITH_MEDIA = Floppy controller present and media is inserted // FLOPPY_NOT_PRESENT = No floppy controller present // FLOPPY_PRESENT_NO_MEDIA = Floppy controller present but no media inserted // #define FLOPPY_NOT_PRESENT 0 #define FLOPPY_PRESENT_WITH_MEDIA 1 #define FLOPPY_PRESENT_NO_MEDIA 2 BBS_TABLE *mBbsTable; BOOLEAN mBbsTableDoneFlag = FALSE; BOOLEAN IsHaveMediaInFloppy = TRUE; /** Checks the state of the floppy and if media is inserted. This routine checks the state of the floppy and if media is inserted. There are 3 cases: No floppy present - Set BBS entry to ignore Floppy present & no media - Set BBS entry to lowest priority. We cannot set it to ignore since 16-bit CSM will indicate no floppy and thus drive A: is unusable. CSM-16 will not try floppy since lowest priority and thus not incur boot time penality. Floppy present & media - Set BBS entry to some priority. @return State of floppy media **/ UINT8 HasMediaInFloppy ( VOID ) { EFI_STATUS Status; UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINTN Index; EFI_ISA_IO_PROTOCOL *IsaIo; EFI_BLOCK_IO_PROTOCOL *BlkIo; HandleBuffer = NULL; HandleCount = 0; gBS->LocateHandleBuffer ( ByProtocol, &gEfiIsaIoProtocolGuid, NULL, &HandleCount, &HandleBuffer ); // // If don't find any ISA/IO protocol assume no floppy. Need for floppy // free system // if (HandleCount == 0) { return FLOPPY_NOT_PRESENT; } ASSERT (HandleBuffer != NULL); for (Index = 0; Index < HandleCount; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo ); if (EFI_ERROR (Status)) { continue; } if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) { continue; } // // Update blockio in case the floppy is inserted in during BdsTimeout // Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); if (EFI_ERROR (Status)) { continue; } Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); if (EFI_ERROR (Status)) { continue; } Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlkIo ); if (EFI_ERROR (Status)) { continue; } if (BlkIo->Media->MediaPresent) { FreePool (HandleBuffer); return FLOPPY_PRESENT_WITH_MEDIA; } else { FreePool (HandleBuffer); return FLOPPY_PRESENT_NO_MEDIA; } } FreePool (HandleBuffer); return FLOPPY_NOT_PRESENT; } /** Complete build of BBS TABLE. @param Private Legacy BIOS Instance data @param BbsTable BBS Table passed to 16-bit code @retval EFI_SUCCESS Removable media not present **/ EFI_STATUS LegacyBiosBuildBbs ( IN LEGACY_BIOS_INSTANCE *Private, IN BBS_TABLE *BbsTable ) { UINTN BbsIndex; HDD_INFO *HddInfo; UINTN HddIndex; UINTN Index; EFI_HANDLE *BlockIoHandles; UINTN NumberBlockIoHandles; UINTN BlockIndex; EFI_STATUS Status; // // First entry is floppy. // Next 2*MAX_IDE_CONTROLLER entries are for onboard IDE. // Next n entries are filled in after each ROM is dispatched. // Entry filled in if follow BBS spec. See LegacyPci.c // Next entries are for non-BBS compliant ROMS. They are filled in by // 16-bit code during Legacy16UpdateBbs invocation. Final BootPriority // occurs after that invocation. // // Floppy // Set default state. // IsHaveMediaInFloppy = HasMediaInFloppy (); if (IsHaveMediaInFloppy == FLOPPY_PRESENT_WITH_MEDIA) { BbsTable[0].BootPriority = BBS_UNPRIORITIZED_ENTRY; } else { if (IsHaveMediaInFloppy == FLOPPY_PRESENT_NO_MEDIA) { BbsTable[0].BootPriority = BBS_LOWEST_PRIORITY; } else { BbsTable[0].BootPriority = BBS_IGNORE_ENTRY; } } BbsTable[0].Bus = 0xff; BbsTable[0].Device = 0xff; BbsTable[0].Function = 0xff; BbsTable[0].DeviceType = BBS_FLOPPY; BbsTable[0].Class = 01; BbsTable[0].SubClass = 02; BbsTable[0].StatusFlags.OldPosition = 0; BbsTable[0].StatusFlags.Reserved1 = 0; BbsTable[0].StatusFlags.Enabled = 0; BbsTable[0].StatusFlags.Failed = 0; BbsTable[0].StatusFlags.MediaPresent = 0; BbsTable[0].StatusFlags.Reserved2 = 0; // // Onboard HDD - Note Each HDD controller controls 2 drives // Master & Slave // HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0]; // // Get IDE Drive Info // LegacyBiosBuildIdeData (Private, &HddInfo, 0); for (HddIndex = 0; HddIndex < MAX_IDE_CONTROLLER; HddIndex++) { BbsIndex = HddIndex * 2 + 1; for (Index = 0; Index < 2; ++Index) { BbsTable[BbsIndex + Index].Bus = HddInfo[HddIndex].Bus; BbsTable[BbsIndex + Index].Device = HddInfo[HddIndex].Device; BbsTable[BbsIndex + Index].Function = HddInfo[HddIndex].Function; BbsTable[BbsIndex + Index].Class = 01; BbsTable[BbsIndex + Index].SubClass = 01; BbsTable[BbsIndex + Index].StatusFlags.OldPosition = 0; BbsTable[BbsIndex + Index].StatusFlags.Reserved1 = 0; BbsTable[BbsIndex + Index].StatusFlags.Enabled = 0; BbsTable[BbsIndex + Index].StatusFlags.Failed = 0; BbsTable[BbsIndex + Index].StatusFlags.MediaPresent = 0; BbsTable[BbsIndex + Index].StatusFlags.Reserved2 = 0; // // If no controller found or no device found set to ignore // else set to unprioritized and set device type // if (HddInfo[HddIndex].CommandBaseAddress == 0) { BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY; } else { if (Index == 0) { if ((HddInfo[HddIndex].Status & (HDD_MASTER_IDE | HDD_MASTER_ATAPI_CDROM | HDD_MASTER_ATAPI_ZIPDISK)) != 0) { BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY; if ((HddInfo[HddIndex].Status & HDD_MASTER_IDE) != 0) { BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK; } else if ((HddInfo[HddIndex].Status & HDD_MASTER_ATAPI_CDROM) != 0) { BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM; } else { // // for ZIPDISK // BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK; } } else { BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY; } } else { if ((HddInfo[HddIndex].Status & (HDD_SLAVE_IDE | HDD_SLAVE_ATAPI_CDROM | HDD_SLAVE_ATAPI_ZIPDISK)) != 0) { BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY; if ((HddInfo[HddIndex].Status & HDD_SLAVE_IDE) != 0) { BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK; } else if ((HddInfo[HddIndex].Status & HDD_SLAVE_ATAPI_CDROM) != 0) { BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM; } else { // // for ZIPDISK // BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK; } } else { BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY; } } } } } // // Add non-IDE block devices // BbsIndex = HddIndex * 2 + 1; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &NumberBlockIoHandles, &BlockIoHandles ); if (!EFI_ERROR (Status)) { UINTN Removable; EFI_BLOCK_IO_PROTOCOL *BlkIo; EFI_PCI_IO_PROTOCOL *PciIo; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; EFI_HANDLE PciHandle; UINTN SegNum; UINTN BusNum; UINTN DevNum; UINTN FuncNum; for (Removable = 0; Removable < 2; Removable++) { for (BlockIndex = 0; BlockIndex < NumberBlockIoHandles; BlockIndex++) { Status = gBS->HandleProtocol ( BlockIoHandles[BlockIndex], &gEfiBlockIoProtocolGuid, (VOID **) &BlkIo ); if (EFI_ERROR (Status)) { continue; } // // Skip the logical partitions // if (BlkIo->Media->LogicalPartition) { continue; } // // Skip the fixed block io then the removable block io // if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) { continue; } // // Get Device Path // Status = gBS->HandleProtocol ( BlockIoHandles[BlockIndex], &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath ); if (EFI_ERROR (Status)) { continue; } // // Skip ATA devices as they have already been handled // DevicePathNode = DevicePath; while (!IsDevicePathEnd (DevicePathNode)) { if (DevicePathType (DevicePathNode) == MESSAGING_DEVICE_PATH && DevicePathSubType (DevicePathNode) == MSG_ATAPI_DP) { break; } DevicePathNode = NextDevicePathNode (DevicePathNode); } if (!IsDevicePathEnd (DevicePathNode)) { continue; } // // Locate which PCI device // Status = gBS->LocateDevicePath ( &gEfiPciIoProtocolGuid, &DevicePath, &PciHandle ); if (EFI_ERROR (Status)) { continue; } Status = gBS->HandleProtocol ( PciHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo ); if (EFI_ERROR (Status)) { continue; } Status = PciIo->GetLocation ( PciIo, &SegNum, &BusNum, &DevNum, &FuncNum ); if (EFI_ERROR (Status)) { continue; } if (SegNum != 0) { DEBUG ((DEBUG_WARN, "CSM cannot use PCI devices in segment %Lu\n", (UINT64) SegNum)); continue; } DEBUG ((DEBUG_INFO, "Add Legacy Bbs entry for PCI %d/%d/%d\n", BusNum, DevNum, FuncNum)); BbsTable[BbsIndex].Bus = BusNum; BbsTable[BbsIndex].Device = DevNum; BbsTable[BbsIndex].Function = FuncNum; BbsTable[BbsIndex].Class = 1; BbsTable[BbsIndex].SubClass = 0x80; BbsTable[BbsIndex].StatusFlags.OldPosition = 0; BbsTable[BbsIndex].StatusFlags.Reserved1 = 0; BbsTable[BbsIndex].StatusFlags.Enabled = 0; BbsTable[BbsIndex].StatusFlags.Failed = 0; BbsTable[BbsIndex].StatusFlags.MediaPresent = 0; BbsTable[BbsIndex].StatusFlags.Reserved2 = 0; BbsTable[BbsIndex].DeviceType = BBS_HARDDISK; BbsTable[BbsIndex].BootPriority = BBS_UNPRIORITIZED_ENTRY; BbsIndex++; if (BbsIndex == MAX_BBS_ENTRIES) { Removable = 2; break; } } } FreePool (BlockIoHandles); } return EFI_SUCCESS; } /** Get all BBS info @param This Protocol instance pointer. @param HddCount Number of HDD_INFO structures @param HddInfo Onboard IDE controller information @param BbsCount Number of BBS_TABLE structures @param BbsTable List BBS entries @retval EFI_SUCCESS Tables returned @retval EFI_NOT_FOUND resource not found @retval EFI_DEVICE_ERROR can not get BBS table **/ EFI_STATUS EFIAPI LegacyBiosGetBbsInfo ( IN EFI_LEGACY_BIOS_PROTOCOL *This, OUT UINT16 *HddCount, OUT HDD_INFO **HddInfo, OUT UINT16 *BbsCount, OUT BBS_TABLE **BbsTable ) { LEGACY_BIOS_INSTANCE *Private; EFI_IA32_REGISTER_SET Regs; EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; // HDD_INFO *LocalHddInfo; // IN BBS_TABLE *LocalBbsTable; UINTN NumHandles; EFI_HANDLE *HandleBuffer; UINTN Index; UINTN TempData; UINT32 Granularity; HandleBuffer = NULL; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; // LocalHddInfo = EfiToLegacy16BootTable->HddInfo; // LocalBbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; if (!mBbsTableDoneFlag) { mBbsTable = Private->BbsTablePtr; // // Always enable disk controllers so 16-bit CSM code has valid information for all // drives. // // // Get PciRootBridgeIO protocol // gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciRootBridgeIoProtocolGuid, NULL, &NumHandles, &HandleBuffer ); if (NumHandles == 0) { return EFI_NOT_FOUND; } mBbsTableDoneFlag = TRUE; for (Index = 0; Index < NumHandles; Index++) { // // Connect PciRootBridgeIO protocol handle with FALSE parameter to let // PCI bus driver enumerate all subsequent handles // gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE); } LegacyBiosBuildBbs (Private, mBbsTable); Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity); // // Call into Legacy16 code to add to BBS table for non BBS compliant OPROMs. // ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16UpdateBbs; // // Pass in handoff data // TempData = (UINTN) EfiToLegacy16BootTable; Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINT32) TempData); Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINT32) TempData); Private->LegacyBios.FarCall86 ( This, Private->Legacy16CallSegment, Private->Legacy16CallOffset, &Regs, NULL, 0 ); Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate); Private->LegacyRegion->Lock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity); if (Regs.X.AX != 0) { return EFI_DEVICE_ERROR; } } if (HandleBuffer != NULL) { FreePool (HandleBuffer); } *HddCount = MAX_IDE_CONTROLLER; *HddInfo = EfiToLegacy16BootTable->HddInfo; *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); return EFI_SUCCESS; }