--- /dev/null
+/** @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
--- /dev/null
+/** @file\r
+\r
+ Internal definitions for the VirtIo PCI Device driver\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
+#ifndef _VIRTIO_PCI_DEVICE_DXE_H_\r
+#define _VIRTIO_PCI_DEVICE_DXE_H_\r
+\r
+#include <Protocol/ComponentName.h>\r
+#include <Protocol/DriverBinding.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/VirtioDevice.h>\r
+\r
+#include <IndustryStandard/Virtio.h>\r
+\r
+#define VIRTIO_PCI_DEVICE_SIGNATURE SIGNATURE_32 ('V', 'P', 'C', 'I')\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ VIRTIO_DEVICE_PROTOCOL VirtioDevice;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT64 OriginalPciAttributes;\r
+ UINT32 DeviceSpecificConfigurationOffset;\r
+} VIRTIO_PCI_DEVICE;\r
+\r
+#define VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE(Device) \\r
+ CR (Device, VIRTIO_PCI_DEVICE, VirtioDevice, VIRTIO_PCI_DEVICE_SIGNATURE)\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
+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
+/********************************************\r
+ * PCI Functions for VIRTIO_DEVICE_PROTOCOL\r
+ *******************************************/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciDeviceRead (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ IN UINTN FieldOffset,\r
+ IN UINTN FieldSize,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciDeviceWrite (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ IN UINTN FieldOffset,\r
+ IN UINTN FieldSize,\r
+ IN UINT64 Value\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetDeviceFeatures (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ OUT UINT32 *DeviceFeatures\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetQueueAddress (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ OUT UINT32 *QueueAddress\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetQueueSize (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ OUT UINT16 *QueueNumMax\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueAlignment (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT32 Alignment\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetPageSize (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT32 PageSize\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetDeviceStatus (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ OUT UINT8 *DeviceStatus\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetGuestFeatures (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ IN UINT32 Features\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueAddress (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT32 Address\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueSel (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT16 Sel\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueNotify (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT16 Index\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueSize (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT16 Size\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetDeviceStatus (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT8 DeviceStatus\r
+ );\r
+\r
+#endif // _VIRTIO_PCI_DEVICE_DXE_H_\r
--- /dev/null
+/** @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
+#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
+#include "VirtioPciDevice.h"\r
+\r
+/**\r
+\r
+ Read a word from Region 0 of the device specified by VirtIo Device protocol.\r
+\r
+ The function implements the ReadDevice protocol member of\r
+ VIRTIO_DEVICE_PROTOCOL.\r
+\r
+ @param[in] This VirtIo Device protocol.\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
+VirtioPciDeviceRead (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ IN UINTN FieldOffset,\r
+ IN UINTN FieldSize,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoRead (Dev,\r
+ Dev->DeviceSpecificConfigurationOffset + FieldOffset,\r
+ FieldSize, BufferSize, Buffer);\r
+}\r
+\r
+/**\r
+\r
+ Write a word into Region 0 of the device specified by VirtIo Device protocol.\r
+\r
+ @param[in] This VirtIo Device protocol.\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
+VirtioPciDeviceWrite (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ IN UINTN FieldOffset,\r
+ IN UINTN FieldSize,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoWrite (Dev,\r
+ Dev->DeviceSpecificConfigurationOffset + FieldOffset, FieldSize, Value);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetDeviceFeatures (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ OUT UINT32 *DeviceFeatures\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ if (DeviceFeatures == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_DEVICE_FEATURES, sizeof (UINT32),\r
+ sizeof (UINT32), DeviceFeatures);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetQueueAddress (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ OUT UINT32 *QueueAddress\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ if (QueueAddress == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_ADDRESS, sizeof (UINT32),\r
+ sizeof (UINT32), QueueAddress);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetQueueSize (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ OUT UINT16 *QueueNumMax\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ if (QueueNumMax == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_SIZE, sizeof (UINT16),\r
+ sizeof (UINT16), QueueNumMax);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciGetDeviceStatus (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ OUT UINT8 *DeviceStatus\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ if (DeviceStatus == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS,\r
+ sizeof (UINT8), sizeof (UINT8), DeviceStatus);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetGuestFeatures (\r
+ IN VIRTIO_DEVICE_PROTOCOL *This,\r
+ IN UINT32 Features\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_GUEST_FEATURES,\r
+ sizeof (UINT32), Features);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueAddress (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT32 Address\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_ADDRESS, sizeof (UINT32),\r
+ Address);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueSel (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT16 Sel\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_SELECT, sizeof (UINT16),\r
+ Sel);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueAlignment (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT32 Alignment\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetPageSize (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT32 PageSize\r
+ )\r
+{\r
+ return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueNotify (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT16 Index\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_NOTIFY, sizeof (UINT16),\r
+ Index);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetQueueSize (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT16 Size\r
+ )\r
+{\r
+ //\r
+ // This function is only applicable in Virtio-MMIO.\r
+ // (The QueueSize field is read-only in Virtio proper (PCI))\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioPciSetDeviceStatus (\r
+ VIRTIO_DEVICE_PROTOCOL *This,\r
+ UINT8 DeviceStatus\r
+ )\r
+{\r
+ VIRTIO_PCI_DEVICE *Dev;\r
+\r
+ Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);\r
+\r
+ return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS,\r
+ sizeof (UINT8), DeviceStatus);\r
+}\r