summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c')
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c
new file mode 100644
index 0000000000..789f48370e
--- /dev/null
+++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c
@@ -0,0 +1,310 @@
+/** @file
+ Collect IDE information from Native EFI Driver
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+BOOLEAN mIdeDataBuiltFlag = FALSE;
+
+/**
+ Collect IDE Inquiry data from the IDE disks
+
+ @param Private Legacy BIOS Instance data
+ @param HddInfo Hdd Information
+ @param Flag Reconnect IdeController or not
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildIdeData (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN HDD_INFO **HddInfo,
+ IN UINT16 Flag
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE IdeController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_DISK_INFO_PROTOCOL *DiskInfo;
+ UINT32 IdeChannel;
+ UINT32 IdeDevice;
+ UINT32 Size;
+ UINT8 *InquiryData;
+ UINT32 InquiryDataSize;
+ HDD_INFO *LocalHddInfo;
+ UINT32 PciIndex;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
+ PCI_DEVICE_PATH *PciDevicePath;
+
+ //
+ // Only build data once
+ // We have a problem with GetBbsInfo in that it can be invoked two
+ // places. Once in BDS, when all EFI drivers are connected and once in
+ // LegacyBoot after all EFI drivers are disconnected causing this routine
+ // to hang. In LegacyBoot this function is also called before EFI drivers
+ // are disconnected.
+ // Cases covered
+ // GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored.
+ // GetBbsInfo not invoked in BDS. First invocation of this function
+ // proceeds normally and second via GetBbsInfo ignored.
+ //
+ PciDevicePath = NULL;
+ LocalHddInfo = *HddInfo;
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ (VOID *) &LocalHddInfo
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ //
+ // Force IDE drive spin up!
+ //
+ if (Flag != 0) {
+ gBS->DisconnectController (
+ IdeController,
+ NULL,
+ NULL
+ );
+ }
+
+ gBS->ConnectController (IdeController, NULL, NULL, FALSE);
+
+ //
+ // Do GetIdeHandle twice since disconnect/reconnect will switch to native mode
+ // And GetIdeHandle will switch to Legacy mode, if required.
+ //
+ Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ (VOID *) &LocalHddInfo
+ );
+ }
+
+ mIdeDataBuiltFlag = TRUE;
+
+ //
+ // Get Identity command from all drives
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDiskInfoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ Private->IdeDriveCount = (UINT8) HandleCount;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDiskInfoProtocolGuid,
+ (VOID **) &DiskInfo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
+ //
+ // Locate which PCI device
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &DevicePath
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ TempDevicePathNode = NextDevicePathNode (DevicePathNode);
+ if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
+ ( DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
+ ( DevicePathType(TempDevicePathNode) == MESSAGING_DEVICE_PATH) &&
+ ( DevicePathSubType(TempDevicePathNode) == MSG_ATAPI_DP) ) {
+ PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode;
+ break;
+ }
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ if (PciDevicePath == NULL) {
+ continue;
+ }
+
+ //
+ // Find start of PCI device in HddInfo. The assumption of the data
+ // structure is 2 controllers(channels) per PCI device and each
+ // controller can have 2 drives(devices).
+ // HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master
+ // HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave
+ // HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master
+ // HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave
+ // @bug eventually need to pass in max number of entries
+ // for end of for loop
+ //
+ for (PciIndex = 0; PciIndex < 8; PciIndex++) {
+ if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) &&
+ (PciDevicePath->Function == LocalHddInfo[PciIndex].Function)
+ ) {
+ break;
+ }
+ }
+
+ if (PciIndex == 8) {
+ continue;
+ }
+
+ Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice);
+ if (!EFI_ERROR (Status)) {
+ Size = sizeof (ATAPI_IDENTIFY);
+ DiskInfo->Identify (
+ DiskInfo,
+ &LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice],
+ &Size
+ );
+ if (IdeChannel == 0) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY;
+ } else if (IdeChannel == 1) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY;
+ }
+
+ InquiryData = NULL;
+ InquiryDataSize = 0;
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ NULL,
+ &InquiryDataSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ InquiryData = (UINT8 *) AllocatePool (
+ InquiryDataSize
+ );
+ if (InquiryData != NULL) {
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ InquiryData,
+ &InquiryDataSize
+ );
+ }
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If ATAPI device then Inquiry will pass and ATA fail.
+ //
+ if (!EFI_ERROR (Status)) {
+ ASSERT (InquiryData != NULL);
+ //
+ // If IdeDevice = 0 then set master bit, else slave bit
+ //
+ if (IdeDevice == 0) {
+ if ((InquiryData[0] & 0x1f) == 0x05) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM;
+ } else if ((InquiryData[0] & 0x1f) == 0x00) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK;
+ }
+ } else {
+ if ((InquiryData[0] & 0x1f) == 0x05) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM;
+ } else if ((InquiryData[0] & 0x1f) == 0x00) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK;
+ }
+ }
+ FreePool (InquiryData);
+ } else {
+ if (IdeDevice == 0) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE;
+ } else {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE;
+ }
+ }
+ }
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ If the IDE channel is in compatibility (legacy) mode, remove all
+ PCI I/O BAR addresses from the controller.
+
+ @param IdeController The handle of target IDE controller
+
+
+**/
+VOID
+InitLegacyIdeController (
+ IN EFI_HANDLE IdeController
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 IOBarClear;
+ EFI_STATUS Status;
+ PCI_TYPE00 PciData;
+
+ //
+ // If the IDE channel is in compatibility (legacy) mode, remove all
+ // PCI I/O BAR addresses from the controller. Some software gets
+ // confused if an IDE controller is in compatibility (legacy) mode
+ // and has PCI I/O resources allocated
+ //
+ Status = gBS->HandleProtocol (
+ IdeController,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (PciData), &PciData);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Check whether this is IDE
+ //
+ if ((PciData.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE) ||
+ (PciData.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
+ return ;
+ }
+
+ //
+ // Clear bar for legacy IDE
+ //
+ IOBarClear = 0x00;
+ if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_PNE) == 0) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear);
+ }
+ if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_SNE) == 0) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear);
+ }
+
+ return ;
+}