]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c
OvmfPkg/VirtioPciDeviceDxe: Implement VIRTIO_DEVICE_PROTOCOL for VirtIo Devices over PCI
[mirror_edk2.git] / OvmfPkg / VirtioPciDeviceDxe / VirtioPciDevice.c
diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c
new file mode 100644 (file)
index 0000000..2647bd3
--- /dev/null
@@ -0,0 +1,680 @@
+/** @file\r
+\r
+  This driver produces Virtio Device Protocol instances for Virtio PCI devices.\r
+\r
+  Copyright (C) 2012, Red Hat, Inc.\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (C) 2013, ARM Ltd.\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  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, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Pci.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include "VirtioPciDevice.h"\r
+\r
+STATIC VIRTIO_DEVICE_PROTOCOL mDeviceProtocolTemplate = {\r
+  0,                                    // Revision\r
+  0,                                    // SubSystemDeviceId\r
+  VirtioPciGetDeviceFeatures,           // GetDeviceFeatures\r
+  VirtioPciSetGuestFeatures,            // SetGuestFeatures\r
+  VirtioPciGetQueueAddress,             // GetQueueAddress\r
+  VirtioPciSetQueueAddress,             // SetQueueAddress\r
+  VirtioPciSetQueueSel,                 // SetQueueSel\r
+  VirtioPciSetQueueNotify,              // SetQueueNotify\r
+  VirtioPciSetQueueAlignment,           // SetQueueAlignment\r
+  VirtioPciSetPageSize,                 // SetPageSize\r
+  VirtioPciGetQueueSize,                // GetQueueNumMax\r
+  VirtioPciSetQueueSize,                // SetQueueNum\r
+  VirtioPciGetDeviceStatus,             // GetDeviceStatus\r
+  VirtioPciSetDeviceStatus,             // SetDeviceStatus\r
+  VirtioPciDeviceWrite,                 // WriteDevice\r
+  VirtioPciDeviceRead                   // ReadDevice\r
+};\r
+\r
+/**\r
+\r
+  Read a word from Region 0 of the device specified by PciIo.\r
+\r
+  Region 0 must be an iomem region. This is an internal function for the PCI\r
+  implementation of the protocol.\r
+\r
+  @param[in] Dev          Virtio PCI device.\r
+\r
+  @param[in] FieldOffset  Source offset.\r
+\r
+  @param[in] FieldSize    Source field size, must be in { 1, 2, 4, 8 }.\r
+\r
+  @param[in] BufferSize   Number of bytes available in the target buffer. Must\r
+                          equal FieldSize.\r
+\r
+  @param[out] Buffer      Target buffer.\r
+\r
+\r
+  @return  Status code returned by PciIo->Io.Read().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciIoRead (\r
+  IN  VIRTIO_PCI_DEVICE         *Dev,\r
+  IN  UINTN                     FieldOffset,\r
+  IN  UINTN                     FieldSize,\r
+  IN  UINTN                     BufferSize,\r
+  OUT VOID                      *Buffer\r
+  )\r
+{\r
+  UINTN                     Count;\r
+  EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+\r
+  ASSERT (FieldSize == BufferSize);\r
+\r
+  PciIo = Dev->PciIo;\r
+  Count = 1;\r
+\r
+  switch (FieldSize) {\r
+    case 1:\r
+      Width = EfiPciIoWidthUint8;\r
+      break;\r
+\r
+    case 2:\r
+      Width = EfiPciIoWidthUint16;\r
+      break;\r
+\r
+    case 8:\r
+      //\r
+      // The 64bit PCI I/O is broken down into two 32bit reads to prevent\r
+      // any alignment or width issues.\r
+      // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():\r
+      //\r
+      // The I/O operations are carried out exactly as requested. The caller\r
+      // is responsible for any alignment and I/O width issues which the\r
+      // bus, device, platform, or type of I/O might require. For example on\r
+      // some platforms, width requests of EfiPciIoWidthUint64 do not work.\r
+      //\r
+      Count = 2;\r
+\r
+      //\r
+      // fall through\r
+      //\r
+    case 4:\r
+      Width = EfiPciIoWidthUint32;\r
+      break;\r
+\r
+    default:\r
+      ASSERT (FALSE);\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return PciIo->Io.Read (\r
+                     PciIo,\r
+                     Width,\r
+                     PCI_BAR_IDX0,\r
+                     FieldOffset,\r
+                     Count,\r
+                     Buffer\r
+                     );\r
+}\r
+\r
+/**\r
+\r
+  Write a word into Region 0 of the device specified by PciIo.\r
+\r
+  Region 0 must be an iomem region. This is an internal function for the PCI\r
+  implementation of the protocol.\r
+\r
+  @param[in] Dev          Virtio PCI device.\r
+\r
+  @param[in] FieldOffset  Destination offset.\r
+\r
+  @param[in] FieldSize    Destination field size, must be in { 1, 2, 4, 8 }.\r
+\r
+  @param[in] Value        Little endian value to write, converted to UINT64.\r
+                          The least significant FieldSize bytes will be used.\r
+\r
+\r
+  @return  Status code returned by PciIo->Io.Write().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciIoWrite (\r
+  IN  VIRTIO_PCI_DEVICE         *Dev,\r
+  IN UINTN                      FieldOffset,\r
+  IN UINTN                      FieldSize,\r
+  IN UINT64                     Value\r
+  )\r
+{\r
+  UINTN                     Count;\r
+  EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+\r
+  PciIo = Dev->PciIo;\r
+  Count = 1;\r
+\r
+  switch (FieldSize) {\r
+    case 1:\r
+      Width = EfiPciIoWidthUint8;\r
+      break;\r
+\r
+    case 2:\r
+      Width = EfiPciIoWidthUint16;\r
+      break;\r
+\r
+    case 8:\r
+      //\r
+      // The 64bit PCI I/O is broken down into two 32bit writes to prevent\r
+      // any alignment or width issues.\r
+      // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():\r
+      //\r
+      // The I/O operations are carried out exactly as requested. The caller\r
+      // is responsible for any alignment and I/O width issues which the\r
+      // bus, device, platform, or type of I/O might require. For example on\r
+      // some platforms, width requests of EfiPciIoWidthUint64 do not work\r
+      //\r
+      Count = Count * 2;\r
+\r
+      //\r
+      // fall through\r
+      //\r
+    case 4:\r
+      Width = EfiPciIoWidthUint32;\r
+      break;\r
+\r
+    default:\r
+      ASSERT (FALSE);\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return PciIo->Io.Write (\r
+                     PciIo,\r
+                     Width,\r
+                     PCI_BAR_IDX0,\r
+                     FieldOffset,\r
+                     Count,\r
+                     &Value\r
+                     );\r
+}\r
+\r
+/**\r
+\r
+  Device probe function for this driver.\r
+\r
+  The DXE core calls this function for any given device in order to see if the\r
+  driver can drive the device.\r
+\r
+  @param[in]  This                The EFI_DRIVER_BINDING_PROTOCOL object\r
+                                  incorporating this driver (independently of\r
+                                  any device).\r
+\r
+  @param[in] DeviceHandle         The device to probe.\r
+\r
+  @param[in] RemainingDevicePath  Relevant only for bus drivers, ignored.\r
+\r
+\r
+  @retval EFI_SUCCESS      The driver supports the device being probed.\r
+\r
+  @retval EFI_UNSUPPORTED  Based on virtio-pci discovery, we do not support\r
+                           the device.\r
+\r
+  @return                  Error codes from the OpenProtocol() boot service or\r
+                           the PciIo protocol.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciDeviceBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  DeviceHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  PCI_TYPE00          Pci;\r
+\r
+  //\r
+  // Attempt to open the device with the PciIo set of interfaces. On success,\r
+  // the protocol is "instantiated" for the PCI device. Covers duplicate open\r
+  // attempts (EFI_ALREADY_STARTED).\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  DeviceHandle,               // candidate device\r
+                  &gEfiPciIoProtocolGuid,     // for generic PCI access\r
+                  (VOID **)&PciIo,            // handle to instantiate\r
+                  This->DriverBindingHandle,  // requestor driver identity\r
+                  DeviceHandle,               // ControllerHandle, according to\r
+                                              // the UEFI Driver Model\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to\r
+                                              // the device; to be released\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Read entire PCI configuration header for more extensive check ahead.\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,                        // (protocol, device)\r
+                                                      // handle\r
+                        EfiPciIoWidthUint32,          // access width & copy\r
+                                                      // mode\r
+                        0,                            // Offset\r
+                        sizeof Pci / sizeof (UINT32), // Count\r
+                        &Pci                          // target buffer\r
+                        );\r
+\r
+  if (Status == EFI_SUCCESS) {\r
+    //\r
+    // virtio-0.9.5, 2.1 PCI Discovery\r
+    //\r
+    if ((Pci.Hdr.VendorId == VIRTIO_VENDOR_ID) &&\r
+        (Pci.Hdr.DeviceId >= 0x1000) &&\r
+        (Pci.Hdr.DeviceId <= 0x103F) &&\r
+        (Pci.Hdr.RevisionID == 0x00)) {\r
+      Status = EFI_SUCCESS;\r
+    } else {\r
+      Status = EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  //\r
+  // We needed PCI IO access only transitorily, to see whether we support the\r
+  // device or not.\r
+  //\r
+  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle, DeviceHandle);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Initialize the VirtIo PCI Device\r
+\r
+  @param[in, out] Dev      The driver instance to configure. The caller is\r
+                           responsible for Device->PciIo's validity (ie. working IO\r
+                           access to the underlying virtio-pci device).\r
+\r
+  @retval EFI_SUCCESS      Setup complete.\r
+\r
+  @retval EFI_UNSUPPORTED  The underlying IO device doesn't support the\r
+                           provided address offset and read size.\r
+\r
+  @return                  Error codes from PciIo->Pci.Read().\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciInit (\r
+  IN OUT VIRTIO_PCI_DEVICE *Device\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  PCI_TYPE00            Pci;\r
+\r
+  ASSERT (Device != NULL);\r
+  PciIo = Device->PciIo;\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (PciIo->Pci.Read != NULL);\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,                        // (protocol, device)\r
+                                                      // handle\r
+                        EfiPciIoWidthUint32,          // access width & copy\r
+                                                      // mode\r
+                        0,                            // Offset\r
+                        sizeof (Pci) / sizeof (UINT32), // Count\r
+                        &Pci                          // target buffer\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Copy protocol template\r
+  //\r
+  CopyMem (&Device->VirtioDevice, &mDeviceProtocolTemplate,\r
+      sizeof (VIRTIO_DEVICE_PROTOCOL));\r
+\r
+  //\r
+  // Initialize the protocol interface attributes\r
+  //\r
+  Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5);\r
+  Device->VirtioDevice.SubSystemDeviceId = Pci.Device.SubsystemID;\r
+\r
+  //\r
+  // Note: We don't support the MSI-X capability.  If we did,\r
+  //       the offset would become 24 after enabling MSI-X.\r
+  //\r
+  Device->DeviceSpecificConfigurationOffset =\r
+      VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Uninitialize the internals of a virtio-pci device that has been successfully\r
+  set up with VirtioPciInit().\r
+\r
+  @param[in, out]  Dev  The device to clean up.\r
+\r
+**/\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+VirtioPciUninit (\r
+  IN OUT VIRTIO_PCI_DEVICE *Device\r
+  )\r
+{\r
+  // Note: This function mirrors VirtioPciInit() that does not allocate any\r
+  //       resources - there's nothing to free here.\r
+}\r
+\r
+/**\r
+\r
+  After we've pronounced support for a specific device in\r
+  DriverBindingSupported(), we start managing said device (passed in by the\r
+  Driver Exeuction Environment) with the following service.\r
+\r
+  See DriverBindingSupported() for specification references.\r
+\r
+  @param[in]  This                The EFI_DRIVER_BINDING_PROTOCOL object\r
+                                  incorporating this driver (independently of\r
+                                  any device).\r
+\r
+  @param[in] DeviceHandle         The supported device to drive.\r
+\r
+  @param[in] RemainingDevicePath  Relevant only for bus drivers, ignored.\r
+\r
+\r
+  @retval EFI_SUCCESS           Driver instance has been created and\r
+                                initialized  for the virtio-pci device, it\r
+                                is now accessible via VIRTIO_DEVICE_PROTOCOL.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
+\r
+  @return                       Error codes from the OpenProtocol() boot\r
+                                service, the PciIo protocol, VirtioPciInit(),\r
+                                or the InstallProtocolInterface() boot service.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciDeviceBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  DeviceHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  )\r
+{\r
+  VIRTIO_PCI_DEVICE   *Device;\r
+  EFI_STATUS           Status;\r
+\r
+  Device = (VIRTIO_PCI_DEVICE *) AllocateZeroPool (sizeof *Device);\r
+  if (Device == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
+                  (VOID **)&Device->PciIo, This->DriverBindingHandle,\r
+                  DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeVirtioPci;\r
+  }\r
+\r
+  //\r
+  // We must retain and ultimately restore the original PCI attributes of the\r
+  // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /\r
+  // 18.3.2 Start() and Stop().\r
+  //\r
+  // The third parameter ("Attributes", input) is ignored by the Get operation.\r
+  // The fourth parameter ("Result", output) is ignored by the Enable and Set\r
+  // operations.\r
+  //\r
+  // For virtio-pci we only need IO space access.\r
+  //\r
+  Status = Device->PciIo->Attributes (Device->PciIo,\r
+      EfiPciIoAttributeOperationGet, 0, &Device->OriginalPciAttributes);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ClosePciIo;\r
+  }\r
+\r
+  Status = Device->PciIo->Attributes (Device->PciIo,\r
+                         EfiPciIoAttributeOperationEnable,\r
+                         EFI_PCI_IO_ATTRIBUTE_IO, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ClosePciIo;\r
+  }\r
+\r
+  //\r
+  // PCI IO access granted, configure protocol instance\r
+  //\r
+\r
+  Status = VirtioPciInit (Device);\r
+  if (EFI_ERROR (Status)) {\r
+    goto RestorePciAttributes;\r
+  }\r
+\r
+  //\r
+  // Setup complete, attempt to export the driver instance's VirtioDevice\r
+  // interface.\r
+  //\r
+  Device->Signature = VIRTIO_PCI_DEVICE_SIGNATURE;\r
+  Status = gBS->InstallProtocolInterface (&DeviceHandle,\r
+                  &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE,\r
+                  &Device->VirtioDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    goto UninitDev;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+UninitDev:\r
+  VirtioPciUninit (Device);\r
+\r
+RestorePciAttributes:\r
+  Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,\r
+                Device->OriginalPciAttributes, NULL);\r
+\r
+ClosePciIo:\r
+  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle, DeviceHandle);\r
+\r
+FreeVirtioPci:\r
+  FreePool (Device);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Stop driving the Virtio PCI device\r
+\r
+  @param[in] This               The EFI_DRIVER_BINDING_PROTOCOL object\r
+                                incorporating this driver (independently of any\r
+                                device).\r
+\r
+  @param[in] DeviceHandle       Stop driving this device.\r
+\r
+  @param[in] NumberOfChildren   Since this function belongs to a device driver\r
+                                only (as opposed to a bus driver), the caller\r
+                                environment sets NumberOfChildren to zero, and\r
+                                we ignore it.\r
+\r
+  @param[in] ChildHandleBuffer  Ignored (corresponding to NumberOfChildren).\r
+\r
+  @retval EFI_SUCCESS           Driver instance has been stopped and the PCI\r
+                                configuration attributes have been restored.\r
+\r
+  @return                       Error codes from the OpenProtocol() or\r
+                                CloseProtocol(), UninstallProtocolInterface()\r
+                                boot services.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciDeviceBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  DeviceHandle,\r
+  IN UINTN                       NumberOfChildren,\r
+  IN EFI_HANDLE                  *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  VIRTIO_DEVICE_PROTOCOL  *VirtioDevice;\r
+  VIRTIO_PCI_DEVICE       *Device;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  DeviceHandle,                  // candidate device\r
+                  &gVirtioDeviceProtocolGuid,    // retrieve the VirtIo iface\r
+                  (VOID **)&VirtioDevice,        // target pointer\r
+                  This->DriverBindingHandle,     // requestor driver identity\r
+                  DeviceHandle,                  // requesting lookup for dev.\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Device = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice);\r
+\r
+  //\r
+  // Handle Stop() requests for in-use driver instances gracefully.\r
+  //\r
+  Status = gBS->UninstallProtocolInterface (DeviceHandle,\r
+                  &gVirtioDeviceProtocolGuid, &Device->VirtioDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  VirtioPciUninit (Device);\r
+\r
+  Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,\r
+                Device->OriginalPciAttributes, NULL);\r
+\r
+  Status = gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle, DeviceHandle);\r
+\r
+  FreePool (Device);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+//\r
+// The static object that groups the Supported() (ie. probe), Start() and\r
+// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata\r
+// C, 10.1 EFI Driver Binding Protocol.\r
+//\r
+STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r
+  &VirtioPciDeviceBindingSupported,\r
+  &VirtioPciDeviceBindingStart,\r
+  &VirtioPciDeviceBindingStop,\r
+  0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers\r
+  NULL, // ImageHandle, to be overwritten by\r
+        // EfiLibInstallDriverBindingComponentName2() in VirtioPciEntryPoint()\r
+  NULL  // DriverBindingHandle, ditto\r
+};\r
+\r
+\r
+//\r
+// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and\r
+// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name\r
+// in English, for display on standard console devices. This is recommended for\r
+// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's\r
+// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.\r
+//\r
+STATIC\r
+EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
+  { "eng;en", L"Virtio PCI Driver" },\r
+  { NULL,     NULL                   }\r
+};\r
+\r
+STATIC\r
+EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,\r
+  IN  CHAR8                       *Language,\r
+  OUT CHAR16                      **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gComponentName) // Iso639Language\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetDeviceName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,\r
+  IN  EFI_HANDLE                  DeviceHandle,\r
+  IN  EFI_HANDLE                  ChildHandle,\r
+  IN  CHAR8                       *Language,\r
+  OUT CHAR16                      **ControllerName\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+STATIC\r
+EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r
+  &VirtioPciGetDriverName,\r
+  &VirtioPciGetDeviceName,\r
+  "eng" // SupportedLanguages, ISO 639-2 language codes\r
+};\r
+\r
+STATIC\r
+EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &VirtioPciGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioPciGetDeviceName,\r
+  "en" // SupportedLanguages, RFC 4646 language codes\r
+};\r
+\r
+\r
+//\r
+// Entry point of this driver.\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciDeviceEntryPoint (\r
+  IN EFI_HANDLE       ImageHandle,\r
+  IN EFI_SYSTEM_TABLE *SystemTable\r
+  )\r
+{\r
+  return EfiLibInstallDriverBindingComponentName2 (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &gDriverBinding,\r
+           ImageHandle,\r
+           &gComponentName,\r
+           &gComponentName2\r
+           );\r
+}\r