]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/QemuVideoDxe/Driver.c
OvmfPkg/QemuVideoDxe: Shouldn't assume system in VGA alias mode.
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Driver.c
index d7716ce6a9df969b259fa096bca4215c926a7aa6..522110ef4e098b5b60527036bec60f326bad1df8 100644 (file)
@@ -2,15 +2,9 @@
   This driver is a sample implementation of the Graphics Output Protocol for\r
   the QEMU (Cirrus Logic 5446) video controller.\r
 \r
-  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
 \r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution. The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -28,30 +22,53 @@ EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
 \r
 QEMU_VIDEO_CARD gQemuVideoCardList[] = {\r
     {\r
+        PCI_CLASS_DISPLAY_VGA,\r
         CIRRUS_LOGIC_VENDOR_ID,\r
         CIRRUS_LOGIC_5430_DEVICE_ID,\r
         QEMU_VIDEO_CIRRUS_5430,\r
         L"Cirrus 5430"\r
     },{\r
+        PCI_CLASS_DISPLAY_VGA,\r
         CIRRUS_LOGIC_VENDOR_ID,\r
         CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,\r
         QEMU_VIDEO_CIRRUS_5430,\r
         L"Cirrus 5430"\r
     },{\r
+        PCI_CLASS_DISPLAY_VGA,\r
         CIRRUS_LOGIC_VENDOR_ID,\r
         CIRRUS_LOGIC_5446_DEVICE_ID,\r
         QEMU_VIDEO_CIRRUS_5446,\r
         L"Cirrus 5446"\r
     },{\r
+        PCI_CLASS_DISPLAY_VGA,\r
         0x1234,\r
         0x1111,\r
         QEMU_VIDEO_BOCHS_MMIO,\r
         L"QEMU Standard VGA"\r
     },{\r
+        PCI_CLASS_DISPLAY_OTHER,\r
+        0x1234,\r
+        0x1111,\r
+        QEMU_VIDEO_BOCHS_MMIO,\r
+        L"QEMU Standard VGA (secondary)"\r
+    },{\r
+        PCI_CLASS_DISPLAY_VGA,\r
         0x1b36,\r
         0x0100,\r
         QEMU_VIDEO_BOCHS,\r
         L"QEMU QXL VGA"\r
+    },{\r
+        PCI_CLASS_DISPLAY_VGA,\r
+        0x1af4,\r
+        0x1050,\r
+        QEMU_VIDEO_BOCHS_MMIO,\r
+        L"QEMU VirtIO VGA"\r
+    },{\r
+        PCI_CLASS_DISPLAY_VGA,\r
+        0x15ad,\r
+        0x0405,\r
+        QEMU_VIDEO_VMWARE_SVGA,\r
+        L"QEMU VMWare SVGA"\r
     },{\r
         0 /* end of list */\r
     }\r
@@ -59,6 +76,7 @@ QEMU_VIDEO_CARD gQemuVideoCardList[] = {
 \r
 static QEMU_VIDEO_CARD*\r
 QemuVideoDetect(\r
+  IN UINT8 SubClass,\r
   IN UINT16 VendorId,\r
   IN UINT16 DeviceId\r
   )\r
@@ -66,7 +84,8 @@ QemuVideoDetect(
   UINTN Index = 0;\r
 \r
   while (gQemuVideoCardList[Index].VendorId != 0) {\r
-    if (gQemuVideoCardList[Index].VendorId == VendorId &&\r
+    if (gQemuVideoCardList[Index].SubClass == SubClass &&\r
+        gQemuVideoCardList[Index].VendorId == VendorId &&\r
         gQemuVideoCardList[Index].DeviceId == DeviceId) {\r
       return gQemuVideoCardList + Index;\r
     }\r
@@ -97,7 +116,6 @@ QemuVideoControllerDriverSupported (
   EFI_STATUS          Status;\r
   EFI_PCI_IO_PROTOCOL *PciIo;\r
   PCI_TYPE00          Pci;\r
-  EFI_DEV_PATH        *Node;\r
   QEMU_VIDEO_CARD     *Card;\r
 \r
   //\r
@@ -130,40 +148,13 @@ QemuVideoControllerDriverSupported (
   }\r
 \r
   Status = EFI_UNSUPPORTED;\r
-  //\r
-  // See if the I/O enable is on.  Most systems only allow one VGA device to be turned on\r
-  // at a time, so see if this is one that is turned on.\r
-  //\r
-  //  if (((Pci.Hdr.Command & 0x01) == 0x01)) {\r
-  //\r
-  // See if this is a Cirrus Logic PCI controller\r
-  //\r
-  Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
+  if (!IS_PCI_DISPLAY (&Pci)) {\r
+    goto Done;\r
+  }\r
+  Card = QemuVideoDetect(Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
   if (Card != NULL) {\r
     DEBUG ((EFI_D_INFO, "QemuVideo: %s detected\n", Card->Name));\r
     Status = EFI_SUCCESS;\r
-    //\r
-    // If this is an Intel 945 graphics controller,\r
-    // go further check RemainingDevicePath validation\r
-    //\r
-    if (RemainingDevicePath != NULL) {\r
-      Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
-      //\r
-      // Check if RemainingDevicePath is the End of Device Path Node, \r
-      // if yes, return EFI_SUCCESS\r
-      //\r
-      if (!IsDevicePathEnd (Node)) {\r
-        //\r
-        // If RemainingDevicePath isn't the End of Device Path Node,\r
-        // check its validation\r
-        //\r
-        if (Node->DevPath.Type != ACPI_DEVICE_PATH ||\r
-            Node->DevPath.SubType != ACPI_ADR_DP ||\r
-            DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {\r
-          Status = EFI_UNSUPPORTED;\r
-        }\r
-      }\r
-    }\r
   }\r
 \r
 Done:\r
@@ -201,19 +192,26 @@ QemuVideoControllerDriverStart (
   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
   )\r
 {\r
+  EFI_TPL                           OldTpl;\r
   EFI_STATUS                        Status;\r
   QEMU_VIDEO_PRIVATE_DATA           *Private;\r
+  BOOLEAN                           IsQxl;\r
   EFI_DEVICE_PATH_PROTOCOL          *ParentDevicePath;\r
+  ACPI_ADR_DEVICE_PATH              AcpiDeviceNode;\r
   PCI_TYPE00                        Pci;\r
   QEMU_VIDEO_CARD                   *Card;\r
   EFI_PCI_IO_PROTOCOL               *ChildPciIo;\r
+  UINT64                            SupportedVgaIo;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
 \r
   //\r
   // Allocate Private context data for GOP inteface.\r
   //\r
   Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));\r
   if (Private == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto RestoreTpl;\r
   }\r
 \r
   //\r
@@ -253,13 +251,19 @@ QemuVideoControllerDriverStart (
   //\r
   // Determine card variant.\r
   //\r
-  Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
+  Card = QemuVideoDetect(Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
   if (Card == NULL) {\r
     Status = EFI_DEVICE_ERROR;\r
     goto ClosePciIo;\r
   }\r
   Private->Variant = Card->Variant;\r
 \r
+  //\r
+  // IsQxl is based on the detected Card->Variant, which at a later point might\r
+  // not match Private->Variant.\r
+  //\r
+  IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS);\r
+\r
   //\r
   // Save original PCI attributes\r
   //\r
@@ -274,13 +278,32 @@ QemuVideoControllerDriverStart (
     goto ClosePciIo;\r
   }\r
 \r
+  //\r
+  // Get supported PCI attributes\r
+  //\r
+  Status = Private->PciIo->Attributes (\r
+                             Private->PciIo,\r
+                             EfiPciIoAttributeOperationSupported,\r
+                             0,\r
+                             &SupportedVgaIo\r
+                             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ClosePciIo;\r
+  }\r
+\r
+  SupportedVgaIo &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);\r
+  if (SupportedVgaIo == 0) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ClosePciIo;\r
+  }\r
+\r
   //\r
   // Set new PCI attributes\r
   //\r
   Status = Private->PciIo->Attributes (\r
                             Private->PciIo,\r
                             EfiPciIoAttributeOperationEnable,\r
-                            EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,\r
+                            EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | SupportedVgaIo,\r
                             NULL\r
                             );\r
   if (EFI_ERROR (Status)) {\r
@@ -313,6 +336,14 @@ QemuVideoControllerDriverStart (
     }\r
   }\r
 \r
+  //\r
+  // VMWare SVGA is handled like Bochs (with port IO only).\r
+  //\r
+  if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {\r
+    Private->Variant = QEMU_VIDEO_BOCHS;\r
+    Private->FrameBufferVramBarIndex = PCI_BAR_IDX1;\r
+  }\r
+\r
   //\r
   // Check if accessing the bochs interface works.\r
   //\r
@@ -342,50 +373,32 @@ QemuVideoControllerDriverStart (
   //\r
   // Set Gop Device Path\r
   //\r
-  if (RemainingDevicePath == NULL) {\r
-    ACPI_ADR_DEVICE_PATH AcpiDeviceNode;\r
-\r
-    ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));\r
-    AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
-    AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
-    AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);\r
-    SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));\r
-\r
-    Private->GopDevicePath = AppendDevicePathNode (\r
-                                        ParentDevicePath,\r
-                                        (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode\r
-                                        );\r
-    if (Private->GopDevicePath == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto RestoreAttributes;\r
-    }\r
-  } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
-    //\r
-    // If RemainingDevicePath isn't the End of Device Path Node, \r
-    // only scan the specified device by RemainingDevicePath\r
-    //\r
-    Private->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);\r
-    if (Private->GopDevicePath == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto RestoreAttributes;\r
-    }\r
+  ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));\r
+  AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
+  AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
+  AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);\r
+  SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));\r
+\r
+  Private->GopDevicePath = AppendDevicePathNode (\r
+                                      ParentDevicePath,\r
+                                      (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode\r
+                                      );\r
+  if (Private->GopDevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto RestoreAttributes;\r
   }\r
 \r
   //\r
-  // Create new child handle and install the device path protocol on it only if\r
-  // RemainingDevicePath equals NULL, or doesn't point to the End of Device\r
-  // Path Node.\r
+  // Create new child handle and install the device path protocol on it.\r
   //\r
-  if (Private->GopDevicePath != NULL) {\r
-    Status = gBS->InstallMultipleProtocolInterfaces (\r
-                    &Private->Handle,\r
-                    &gEfiDevicePathProtocolGuid,\r
-                    Private->GopDevicePath,\r
-                    NULL\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      goto FreeGopDevicePath;\r
-    }\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Private->Handle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  Private->GopDevicePath,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeGopDevicePath;\r
   }\r
 \r
   //\r
@@ -398,7 +411,7 @@ QemuVideoControllerDriverStart (
     break;\r
   case QEMU_VIDEO_BOCHS_MMIO:\r
   case QEMU_VIDEO_BOCHS:\r
-    Status = QemuVideoBochsModeSetup (Private);\r
+    Status = QemuVideoBochsModeSetup (Private, IsQxl);\r
     break;\r
   default:\r
     ASSERT (FALSE);\r
@@ -409,14 +422,6 @@ QemuVideoControllerDriverStart (
     goto UninstallGopDevicePath;\r
   }\r
 \r
-  //\r
-  // If RemainingDevicePath points to the End of Device Path Node, then we\r
-  // haven't created a child handle, and we're done.\r
-  //\r
-  if (Private->GopDevicePath == NULL) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
   //\r
   // Start the GOP software stack.\r
   //\r
@@ -450,6 +455,14 @@ QemuVideoControllerDriverStart (
     goto UninstallGop;\r
   }\r
 \r
+#if defined MDE_CPU_IA32 || defined MDE_CPU_X64\r
+  if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||\r
+      Private->Variant == QEMU_VIDEO_BOCHS) {\r
+    InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase);\r
+  }\r
+#endif\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
   return EFI_SUCCESS;\r
 \r
 UninstallGop:\r
@@ -463,17 +476,11 @@ FreeModeData:
   FreePool (Private->ModeData);\r
 \r
 UninstallGopDevicePath:\r
-  //\r
-  // Handles the case transparently when Private->Handle and\r
-  // Private->GopDevicePath are NULL.\r
-  //\r
   gBS->UninstallProtocolInterface (Private->Handle,\r
          &gEfiDevicePathProtocolGuid, Private->GopDevicePath);\r
 \r
 FreeGopDevicePath:\r
-  if (Private->GopDevicePath != NULL) {\r
-    FreePool (Private->GopDevicePath);\r
-  }\r
+  FreePool (Private->GopDevicePath);\r
 \r
 RestoreAttributes:\r
   Private->PciIo->Attributes (Private->PciIo, EfiPciIoAttributeOperationSet,\r
@@ -486,6 +493,9 @@ ClosePciIo:
 FreePrivate:\r
   FreePool (Private);\r
 \r
+RestoreTpl:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
   return Status;\r
 }\r
 \r
@@ -516,8 +526,26 @@ QemuVideoControllerDriverStop (
   EFI_STATUS                      Status;\r
   QEMU_VIDEO_PRIVATE_DATA  *Private;\r
 \r
+  if (NumberOfChildren == 0) {\r
+    //\r
+    // Close the PCI I/O Protocol\r
+    //\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiPciIoProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // free all resources for whose access we need the child handle, because the\r
+  // child handle is going away\r
+  //\r
+  ASSERT (NumberOfChildren == 1);\r
   Status = gBS->OpenProtocol (\r
-                  Controller,\r
+                  ChildHandleBuffer[0],\r
                   &gEfiGraphicsOutputProtocolGuid,\r
                   (VOID **) &GraphicsOutput,\r
                   This->DriverBindingHandle,\r
@@ -532,6 +560,7 @@ QemuVideoControllerDriverStop (
   // Get our private context information\r
   //\r
   Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);\r
+  ASSERT (Private->Handle == ChildHandleBuffer[0]);\r
 \r
   QemuVideoGraphicsOutputDestructor (Private);\r
   //\r
@@ -558,16 +587,6 @@ QemuVideoControllerDriverStop (
                   NULL\r
                   );\r
 \r
-  //\r
-  // Close the PCI I/O Protocol\r
-  //\r
-  gBS->CloseProtocol (\r
-        Controller,\r
-        &gEfiPciIoProtocolGuid,\r
-        This->DriverBindingHandle,\r
-        Controller\r
-        );\r
-\r
   gBS->CloseProtocol (\r
         Controller,\r
         &gEfiPciIoProtocolGuid,\r
@@ -575,6 +594,11 @@ QemuVideoControllerDriverStop (
         Private->Handle\r
         );\r
 \r
+  FreePool (Private->ModeData);\r
+  gBS->UninstallProtocolInterface (Private->Handle,\r
+         &gEfiDevicePathProtocolGuid, Private->GopDevicePath);\r
+  FreePool (Private->GopDevicePath);\r
+\r
   //\r
   // Free our instance data\r
   //\r
@@ -768,7 +792,7 @@ ClearScreen (
   Private->PciIo->Mem.Write (\r
                         Private->PciIo,\r
                         EfiPciIoWidthFillUint32,\r
-                        0,\r
+                        Private->FrameBufferVramBarIndex,\r
                         0,\r
                         0x400000 >> 2,\r
                         &Color\r
@@ -978,18 +1002,5 @@ InitializeQemuVideo (
              );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  //\r
-  // Install EFI Driver Supported EFI Version Protocol required for\r
-  // EFI drivers that are on PCI and other plug in cards.\r
-  //\r
-  gQemuVideoDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);\r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &ImageHandle,\r
-                  &gEfiDriverSupportedEfiVersionProtocolGuid,\r
-                  &gQemuVideoDriverSupportedEfiVersion,\r
-                  NULL\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
   return Status;\r
 }\r