]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
OvmfPkg/VirtioMmioDeviceLib: Implement VIRTIO_DEVICE_PROTOCOL for VirtIo Devices...
[mirror_edk2.git] / OvmfPkg / Library / VirtioMmioDeviceLib / VirtioMmioDevice.c
diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
new file mode 100644 (file)
index 0000000..4af9dd0
--- /dev/null
@@ -0,0 +1,224 @@
+/** @file\r
+\r
+  This driver produces Virtio Device Protocol instances for Virtio Mmio devices.\r
+\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 <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include "VirtioMmioDevice.h"\r
+\r
+static VIRTIO_DEVICE_PROTOCOL mMmioDeviceProtocolTemplate = {\r
+    0,                                     // Revision\r
+    0,                                     // SubSystemDeviceId\r
+    VirtioMmioGetDeviceFeatures,           // GetDeviceFeatures\r
+    VirtioMmioSetGuestFeatures,            // SetGuestFeatures\r
+    VirtioMmioGetQueueAddress,             // GetQueueAddress\r
+    VirtioMmioSetQueueAddress,             // SetQueueAddress\r
+    VirtioMmioSetQueueSel,                 // SetQueueSel\r
+    VirtioMmioSetQueueNotify,              // SetQueueNotify\r
+    VirtioMmioSetQueueAlignment,           // SetQueueAlign\r
+    VirtioMmioSetPageSize,                 // SetPageSize\r
+    VirtioMmioGetQueueSize,                // GetQueueNumMax\r
+    VirtioMmioSetQueueSize,                // SetQueueNum\r
+    VirtioMmioGetDeviceStatus,             // GetDeviceStatus\r
+    VirtioMmioSetDeviceStatus,             // SetDeviceStatus\r
+    VirtioMmioDeviceWrite,                 // WriteDevice\r
+    VirtioMmioDeviceRead                   // ReadDevice\r
+};\r
+\r
+/**\r
+\r
+  Initialize the VirtIo MMIO Device\r
+\r
+  @param[in] BaseAddress   Base Address of the VirtIo MMIO Device\r
+\r
+  @param[in, out] Device   The driver instance to configure.\r
+\r
+  @retval EFI_SUCCESS      Setup complete.\r
+\r
+  @retval EFI_UNSUPPORTED  The driver is not a VirtIo MMIO device.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioMmioInit (\r
+  IN PHYSICAL_ADDRESS        BaseAddress,\r
+  IN OUT VIRTIO_MMIO_DEVICE *Device\r
+  )\r
+{\r
+  UINT32     MagicValue;\r
+  UINT32     VendorId;\r
+  UINT32     Version;\r
+\r
+  //\r
+  // Initialize VirtIo Mmio Device\r
+  //\r
+  CopyMem (&Device->VirtioDevice, &mMmioDeviceProtocolTemplate,\r
+        sizeof (VIRTIO_DEVICE_PROTOCOL));\r
+  Device->BaseAddress = BaseAddress;\r
+  Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5);\r
+  Device->VirtioDevice.SubSystemDeviceId =\r
+          MmioRead32 (BaseAddress + VIRTIO_MMIO_OFFSET_DEVICE_ID);\r
+\r
+  //\r
+  // Double-check MMIO-specific values\r
+  //\r
+  MagicValue = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_MAGIC);\r
+  if (MagicValue != VIRTIO_MMIO_MAGIC) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Version = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VERSION);\r
+  if (Version != 1) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Double-check MMIO-specific values\r
+  //\r
+  VendorId = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VENDOR_ID);\r
+  if (VendorId != VIRTIO_VENDOR_ID) {\r
+    //\r
+    // The ARM Base and Foundation Models do not report a valid VirtIo VendorId.\r
+    // They return a value of 0x0 for the VendorId.\r
+    //\r
+    DEBUG((EFI_D_WARN, "VirtioMmioInit: Warning: The VendorId (0x%X) does not "\r
+                       "match the VirtIo VendorId (0x%X).\n",\r
+                       VendorId, VIRTIO_VENDOR_ID));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+  Uninitialize the internals of a virtio-mmio device that has been successfully\r
+  set up with VirtioMmioInit().\r
+\r
+  @param[in, out]  Device  The device to clean up.\r
+\r
+**/\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+VirtioMmioUninit (\r
+  IN VIRTIO_MMIO_DEVICE *Device\r
+  )\r
+{\r
+  //\r
+  // Note: This function mirrors VirtioMmioInit() that does not allocate any\r
+  //       resources - there's nothing to free here.\r
+  //\r
+}\r
+\r
+EFI_STATUS\r
+VirtioMmioInstallDevice (\r
+  IN PHYSICAL_ADDRESS       BaseAddress,\r
+  IN EFI_HANDLE             Handle\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  VIRTIO_MMIO_DEVICE *VirtIo;\r
+\r
+  if (!BaseAddress) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (Handle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Allocate VIRTIO_MMIO_DEVICE\r
+  //\r
+  VirtIo = AllocateZeroPool (sizeof (VIRTIO_MMIO_DEVICE));\r
+  if (VirtIo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  VirtIo->Signature = VIRTIO_MMIO_DEVICE_SIGNATURE;\r
+\r
+  Status = VirtioMmioInit (BaseAddress, VirtIo);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeVirtioMem;\r
+  }\r
+\r
+  //\r
+  // Install VIRTIO_DEVICE_PROTOCOL to Handle\r
+  //\r
+  Status = gBS->InstallProtocolInterface (&Handle,\r
+                  &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE,\r
+                  &VirtIo->VirtioDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    goto UninitVirtio;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+UninitVirtio:\r
+  VirtioMmioUninit (VirtIo);\r
+\r
+FreeVirtioMem:\r
+  FreePool (VirtIo);\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+VirtioMmioUninstallDevice (\r
+  IN EFI_HANDLE             DeviceHandle\r
+  )\r
+{\r
+  VIRTIO_DEVICE_PROTOCOL  *VirtioDevice;\r
+  VIRTIO_MMIO_DEVICE      *MmioDevice;\r
+  EFI_STATUS              Status;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  DeviceHandle,                  // candidate device\r
+                  &gVirtioDeviceProtocolGuid,    // retrieve the VirtIo iface\r
+                  (VOID **)&VirtioDevice,        // target pointer\r
+                  DeviceHandle,                  // 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
+  //\r
+  // Get the MMIO device from the VirtIo Device instance\r
+  //\r
+  MmioDevice = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice);\r
+\r
+  //\r
+  // Uninstall the protocol interface\r
+  //\r
+  Status = gBS->UninstallProtocolInterface (DeviceHandle,\r
+      &gVirtioDeviceProtocolGuid, &MmioDevice->VirtioDevice\r
+      );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Uninitialize the VirtIo Device\r
+  //\r
+  VirtioMmioUninit (MmioDevice);\r
+  FreePool (MmioDevice);\r
+\r
+  return EFI_SUCCESS;\r
+}\r