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