From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c | 682 +++++++++++++++++++++ .../OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h | 188 ++++++ .../VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf | 38 ++ .../VirtioPciDeviceDxe/VirtioPciFunctions.c | 328 ++++++++++ 4 files changed, 1236 insertions(+) create mode 100644 roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c create mode 100644 roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h create mode 100644 roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf create mode 100644 roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c (limited to 'roms/edk2/OvmfPkg/VirtioPciDeviceDxe') diff --git a/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c b/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c new file mode 100644 index 000000000..c5c8d5ebe --- /dev/null +++ b/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c @@ -0,0 +1,682 @@ +/** @file + + This driver produces Virtio Device Protocol instances for Virtio PCI devices. + + Copyright (C) 2012, Red Hat, Inc. + Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
+ Copyright (C) 2013, ARM Ltd. + Copyright (C) 2017, AMD Inc, All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#include "VirtioPciDevice.h" + +STATIC VIRTIO_DEVICE_PROTOCOL mDeviceProtocolTemplate = { + 0, // Revision + 0, // SubSystemDeviceId + VirtioPciGetDeviceFeatures, // GetDeviceFeatures + VirtioPciSetGuestFeatures, // SetGuestFeatures + VirtioPciSetQueueAddress, // SetQueueAddress + VirtioPciSetQueueSel, // SetQueueSel + VirtioPciSetQueueNotify, // SetQueueNotify + VirtioPciSetQueueAlignment, // SetQueueAlignment + VirtioPciSetPageSize, // SetPageSize + VirtioPciGetQueueSize, // GetQueueNumMax + VirtioPciSetQueueSize, // SetQueueNum + VirtioPciGetDeviceStatus, // GetDeviceStatus + VirtioPciSetDeviceStatus, // SetDeviceStatus + VirtioPciDeviceWrite, // WriteDevice + VirtioPciDeviceRead, // ReadDevice + VirtioPciAllocateSharedPages, // AllocateSharedPages + VirtioPciFreeSharedPages, // FreeSharedPages + VirtioPciMapSharedBuffer, // MapSharedBuffer + VirtioPciUnmapSharedBuffer, // UnmapSharedBuffer +}; + +/** + + Read a word from Region 0 of the device specified by PciIo. + + Region 0 must be an iomem region. This is an internal function for the PCI + implementation of the protocol. + + @param[in] Dev Virtio PCI device. + + @param[in] FieldOffset Source offset. + + @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }. + + @param[in] BufferSize Number of bytes available in the target buffer. Must + equal FieldSize. + + @param[out] Buffer Target buffer. + + + @return Status code returned by PciIo->Io.Read(). + +**/ +EFI_STATUS +EFIAPI +VirtioPciIoRead ( + IN VIRTIO_PCI_DEVICE *Dev, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + UINTN Count; + EFI_PCI_IO_PROTOCOL_WIDTH Width; + EFI_PCI_IO_PROTOCOL *PciIo; + + ASSERT (FieldSize == BufferSize); + + PciIo = Dev->PciIo; + Count = 1; + + switch (FieldSize) { + case 1: + Width = EfiPciIoWidthUint8; + break; + + case 2: + Width = EfiPciIoWidthUint16; + break; + + case 8: + // + // The 64bit PCI I/O is broken down into two 32bit reads to prevent + // any alignment or width issues. + // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write(): + // + // The I/O operations are carried out exactly as requested. The caller + // is responsible for any alignment and I/O width issues which the + // bus, device, platform, or type of I/O might require. For example on + // some platforms, width requests of EfiPciIoWidthUint64 do not work. + // + Count = 2; + + // + // fall through + // + case 4: + Width = EfiPciIoWidthUint32; + break; + + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return PciIo->Io.Read ( + PciIo, + Width, + PCI_BAR_IDX0, + FieldOffset, + Count, + Buffer + ); +} + +/** + + Write a word into Region 0 of the device specified by PciIo. + + Region 0 must be an iomem region. This is an internal function for the PCI + implementation of the protocol. + + @param[in] Dev Virtio PCI device. + + @param[in] FieldOffset Destination offset. + + @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }. + + @param[in] Value Little endian value to write, converted to UINT64. + The least significant FieldSize bytes will be used. + + + @return Status code returned by PciIo->Io.Write(). + +**/ +EFI_STATUS +EFIAPI +VirtioPciIoWrite ( + IN VIRTIO_PCI_DEVICE *Dev, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINT64 Value + ) +{ + UINTN Count; + EFI_PCI_IO_PROTOCOL_WIDTH Width; + EFI_PCI_IO_PROTOCOL *PciIo; + + PciIo = Dev->PciIo; + Count = 1; + + switch (FieldSize) { + case 1: + Width = EfiPciIoWidthUint8; + break; + + case 2: + Width = EfiPciIoWidthUint16; + break; + + case 8: + // + // The 64bit PCI I/O is broken down into two 32bit writes to prevent + // any alignment or width issues. + // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write(): + // + // The I/O operations are carried out exactly as requested. The caller + // is responsible for any alignment and I/O width issues which the + // bus, device, platform, or type of I/O might require. For example on + // some platforms, width requests of EfiPciIoWidthUint64 do not work + // + Count = Count * 2; + + // + // fall through + // + case 4: + Width = EfiPciIoWidthUint32; + break; + + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return PciIo->Io.Write ( + PciIo, + Width, + PCI_BAR_IDX0, + FieldOffset, + Count, + &Value + ); +} + +/** + + Device probe function for this driver. + + The DXE core calls this function for any given device in order to see if the + driver can drive the device. + + @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object + incorporating this driver (independently of + any device). + + @param[in] DeviceHandle The device to probe. + + @param[in] RemainingDevicePath Relevant only for bus drivers, ignored. + + + @retval EFI_SUCCESS The driver supports the device being probed. + + @retval EFI_UNSUPPORTED Based on virtio-pci discovery, we do not support + the device. + + @return Error codes from the OpenProtocol() boot service or + the PciIo protocol. + +**/ +STATIC +EFI_STATUS +EFIAPI +VirtioPciDeviceBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE DeviceHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + // + // Attempt to open the device with the PciIo set of interfaces. On success, + // the protocol is "instantiated" for the PCI device. Covers duplicate open + // attempts (EFI_ALREADY_STARTED). + // + Status = gBS->OpenProtocol ( + DeviceHandle, // candidate device + &gEfiPciIoProtocolGuid, // for generic PCI access + (VOID **)&PciIo, // handle to instantiate + This->DriverBindingHandle, // requestor driver identity + DeviceHandle, // ControllerHandle, according to + // the UEFI Driver Model + EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to + // the device; to be released + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Read entire PCI configuration header for more extensive check ahead. + // + Status = PciIo->Pci.Read ( + PciIo, // (protocol, device) + // handle + EfiPciIoWidthUint32, // access width & copy + // mode + 0, // Offset + sizeof Pci / sizeof (UINT32), // Count + &Pci // target buffer + ); + + if (Status == EFI_SUCCESS) { + // + // virtio-0.9.5, 2.1 PCI Discovery + // + if ((Pci.Hdr.VendorId == VIRTIO_VENDOR_ID) && + (Pci.Hdr.DeviceId >= 0x1000) && + (Pci.Hdr.DeviceId <= 0x103F) && + (Pci.Hdr.RevisionID == 0x00)) { + Status = EFI_SUCCESS; + } else { + Status = EFI_UNSUPPORTED; + } + } + + // + // We needed PCI IO access only transitorily, to see whether we support the + // device or not. + // + gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, DeviceHandle); + + return Status; +} + +/** + + Initialize the VirtIo PCI Device + + @param[in, out] Dev The driver instance to configure. The caller is + responsible for Device->PciIo's validity (ie. working IO + access to the underlying virtio-pci device). + + @retval EFI_SUCCESS Setup complete. + + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and read size. + + @return Error codes from PciIo->Pci.Read(). + +**/ +STATIC +EFI_STATUS +EFIAPI +VirtioPciInit ( + IN OUT VIRTIO_PCI_DEVICE *Device + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + ASSERT (Device != NULL); + PciIo = Device->PciIo; + ASSERT (PciIo != NULL); + ASSERT (PciIo->Pci.Read != NULL); + + Status = PciIo->Pci.Read ( + PciIo, // (protocol, device) + // handle + EfiPciIoWidthUint32, // access width & copy + // mode + 0, // Offset + sizeof (Pci) / sizeof (UINT32), // Count + &Pci // target buffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Copy protocol template + // + CopyMem (&Device->VirtioDevice, &mDeviceProtocolTemplate, + sizeof (VIRTIO_DEVICE_PROTOCOL)); + + // + // Initialize the protocol interface attributes + // + Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5); + Device->VirtioDevice.SubSystemDeviceId = Pci.Device.SubsystemID; + + // + // Note: We don't support the MSI-X capability. If we did, + // the offset would become 24 after enabling MSI-X. + // + Device->DeviceSpecificConfigurationOffset = + VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI; + + return EFI_SUCCESS; +} + +/** + + Uninitialize the internals of a virtio-pci device that has been successfully + set up with VirtioPciInit(). + + @param[in, out] Dev The device to clean up. + +**/ + +STATIC +VOID +EFIAPI +VirtioPciUninit ( + IN OUT VIRTIO_PCI_DEVICE *Device + ) +{ + // Note: This function mirrors VirtioPciInit() that does not allocate any + // resources - there's nothing to free here. +} + +/** + + After we've pronounced support for a specific device in + DriverBindingSupported(), we start managing said device (passed in by the + Driver Execution Environment) with the following service. + + See DriverBindingSupported() for specification references. + + @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object + incorporating this driver (independently of + any device). + + @param[in] DeviceHandle The supported device to drive. + + @param[in] RemainingDevicePath Relevant only for bus drivers, ignored. + + + @retval EFI_SUCCESS Driver instance has been created and + initialized for the virtio-pci device, it + is now accessible via VIRTIO_DEVICE_PROTOCOL. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + + @return Error codes from the OpenProtocol() boot + service, the PciIo protocol, VirtioPciInit(), + or the InstallProtocolInterface() boot service. + +**/ +STATIC +EFI_STATUS +EFIAPI +VirtioPciDeviceBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE DeviceHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + VIRTIO_PCI_DEVICE *Device; + EFI_STATUS Status; + + Device = (VIRTIO_PCI_DEVICE *) AllocateZeroPool (sizeof *Device); + if (Device == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, + (VOID **)&Device->PciIo, This->DriverBindingHandle, + DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR (Status)) { + goto FreeVirtioPci; + } + + // + // We must retain and ultimately restore the original PCI attributes of the + // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers / + // 18.3.2 Start() and Stop(). + // + // The third parameter ("Attributes", input) is ignored by the Get operation. + // The fourth parameter ("Result", output) is ignored by the Enable and Set + // operations. + // + // For virtio-pci we only need IO space access. + // + Status = Device->PciIo->Attributes (Device->PciIo, + EfiPciIoAttributeOperationGet, 0, &Device->OriginalPciAttributes); + if (EFI_ERROR (Status)) { + goto ClosePciIo; + } + + Status = Device->PciIo->Attributes ( + Device->PciIo, + EfiPciIoAttributeOperationEnable, + (EFI_PCI_IO_ATTRIBUTE_IO | + EFI_PCI_IO_ATTRIBUTE_BUS_MASTER), + NULL + ); + if (EFI_ERROR (Status)) { + goto ClosePciIo; + } + + // + // PCI IO access granted, configure protocol instance + // + + Status = VirtioPciInit (Device); + if (EFI_ERROR (Status)) { + goto RestorePciAttributes; + } + + // + // Setup complete, attempt to export the driver instance's VirtioDevice + // interface. + // + Device->Signature = VIRTIO_PCI_DEVICE_SIGNATURE; + Status = gBS->InstallProtocolInterface (&DeviceHandle, + &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE, + &Device->VirtioDevice); + if (EFI_ERROR (Status)) { + goto UninitDev; + } + + return EFI_SUCCESS; + +UninitDev: + VirtioPciUninit (Device); + +RestorePciAttributes: + Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet, + Device->OriginalPciAttributes, NULL); + +ClosePciIo: + gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, DeviceHandle); + +FreeVirtioPci: + FreePool (Device); + + return Status; +} + +/** + + Stop driving the Virtio PCI device + + @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object + incorporating this driver (independently of any + device). + + @param[in] DeviceHandle Stop driving this device. + + @param[in] NumberOfChildren Since this function belongs to a device driver + only (as opposed to a bus driver), the caller + environment sets NumberOfChildren to zero, and + we ignore it. + + @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren). + + @retval EFI_SUCCESS Driver instance has been stopped and the PCI + configuration attributes have been restored. + + @return Error codes from the OpenProtocol() or + CloseProtocol(), UninstallProtocolInterface() + boot services. + +**/ +STATIC +EFI_STATUS +EFIAPI +VirtioPciDeviceBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE DeviceHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + VIRTIO_DEVICE_PROTOCOL *VirtioDevice; + VIRTIO_PCI_DEVICE *Device; + + Status = gBS->OpenProtocol ( + DeviceHandle, // candidate device + &gVirtioDeviceProtocolGuid, // retrieve the VirtIo iface + (VOID **)&VirtioDevice, // target pointer + This->DriverBindingHandle, // requestor driver identity + DeviceHandle, // requesting lookup for dev. + EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Device = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice); + + // + // Handle Stop() requests for in-use driver instances gracefully. + // + Status = gBS->UninstallProtocolInterface (DeviceHandle, + &gVirtioDeviceProtocolGuid, &Device->VirtioDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + VirtioPciUninit (Device); + + Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet, + Device->OriginalPciAttributes, NULL); + + Status = gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, DeviceHandle); + + FreePool (Device); + + return Status; +} + + +// +// The static object that groups the Supported() (ie. probe), Start() and +// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata +// C, 10.1 EFI Driver Binding Protocol. +// +STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = { + &VirtioPciDeviceBindingSupported, + &VirtioPciDeviceBindingStart, + &VirtioPciDeviceBindingStop, + 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers + NULL, // ImageHandle, to be overwritten by + // EfiLibInstallDriverBindingComponentName2() in VirtioPciEntryPoint() + NULL // DriverBindingHandle, ditto +}; + + +// +// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and +// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name +// in English, for display on standard console devices. This is recommended for +// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's +// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names. +// +STATIC +EFI_UNICODE_STRING_TABLE mDriverNameTable[] = { + { "eng;en", L"Virtio PCI Driver" }, + { NULL, NULL } +}; + +STATIC +EFI_COMPONENT_NAME_PROTOCOL gComponentName; + +EFI_STATUS +EFIAPI +VirtioPciGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mDriverNameTable, + DriverName, + (BOOLEAN)(This == &gComponentName) // Iso639Language + ); +} + +EFI_STATUS +EFIAPI +VirtioPciGetDeviceName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE DeviceHandle, + IN EFI_HANDLE ChildHandle, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} + +STATIC +EFI_COMPONENT_NAME_PROTOCOL gComponentName = { + &VirtioPciGetDriverName, + &VirtioPciGetDeviceName, + "eng" // SupportedLanguages, ISO 639-2 language codes +}; + +STATIC +EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &VirtioPciGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioPciGetDeviceName, + "en" // SupportedLanguages, RFC 4646 language codes +}; + + +// +// Entry point of this driver. +// +EFI_STATUS +EFIAPI +VirtioPciDeviceEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gDriverBinding, + ImageHandle, + &gComponentName, + &gComponentName2 + ); +} diff --git a/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h b/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h new file mode 100644 index 000000000..fe8514d42 --- /dev/null +++ b/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h @@ -0,0 +1,188 @@ +/** @file + + Internal definitions for the VirtIo PCI Device driver + + Copyright (C) 2013, ARM Ltd + Copyright (c) 2017, AMD Inc, All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _VIRTIO_PCI_DEVICE_DXE_H_ +#define _VIRTIO_PCI_DEVICE_DXE_H_ + +#include +#include +#include +#include + +#include + +#define VIRTIO_PCI_DEVICE_SIGNATURE SIGNATURE_32 ('V', 'P', 'C', 'I') + +typedef struct { + UINT32 Signature; + VIRTIO_DEVICE_PROTOCOL VirtioDevice; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 OriginalPciAttributes; + UINT32 DeviceSpecificConfigurationOffset; +} VIRTIO_PCI_DEVICE; + +#define VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE(Device) \ + CR (Device, VIRTIO_PCI_DEVICE, VirtioDevice, VIRTIO_PCI_DEVICE_SIGNATURE) + + +EFI_STATUS +EFIAPI +VirtioPciIoRead ( + IN VIRTIO_PCI_DEVICE *Dev, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +VirtioPciIoWrite ( + IN VIRTIO_PCI_DEVICE *Dev, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINT64 Value + ); + +/******************************************** + * PCI Functions for VIRTIO_DEVICE_PROTOCOL + *******************************************/ +EFI_STATUS +EFIAPI +VirtioPciDeviceRead ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +VirtioPciDeviceWrite ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINT64 Value + ); + +EFI_STATUS +EFIAPI +VirtioPciGetDeviceFeatures ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT64 *DeviceFeatures + ); + +EFI_STATUS +EFIAPI +VirtioPciGetQueueSize ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT16 *QueueNumMax + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueAlignment ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT32 Alignment + ); + +EFI_STATUS +EFIAPI +VirtioPciSetPageSize ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT32 PageSize + ); + +EFI_STATUS +EFIAPI +VirtioPciGetDeviceStatus ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT8 *DeviceStatus + ); + +EFI_STATUS +EFIAPI +VirtioPciSetGuestFeatures ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT64 Features + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueAddress ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN VRING *Ring, + IN UINT64 RingBaseShift + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueSel ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT16 Sel + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueNotify ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT16 Index + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueSize ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT16 Size + ); + +EFI_STATUS +EFIAPI +VirtioPciSetDeviceStatus ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT8 DeviceStatus + ); + +EFI_STATUS +EFIAPI +VirtioPciAllocateSharedPages ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN NumPages, + OUT VOID **HostAddress + ); + +VOID +EFIAPI +VirtioPciFreeSharedPages ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN NumPages, + IN VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +VirtioPciMapSharedBuffer ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN VIRTIO_MAP_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +EFI_STATUS +EFIAPI +VirtioPciUnmapSharedBuffer ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN VOID *Mapping + ); +#endif // _VIRTIO_PCI_DEVICE_DXE_H_ diff --git a/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf b/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf new file mode 100644 index 000000000..be5f2aa22 --- /dev/null +++ b/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf @@ -0,0 +1,38 @@ +## @file +# This driver produces the VirtIo Device Protocol instances for VirtIo PCI +# Device +# +# Copyright (C) 2013, ARM Ltd +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = VirtioPciDeviceDxe + FILE_GUID = 83dd3b39-7caf-4fac-a542-e050b767e3a7 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = VirtioPciDeviceEntryPoint + +[Sources] + VirtioPciDevice.c + VirtioPciDevice.h + VirtioPciFunctions.c + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiPciIoProtocolGuid ## TO_START + gVirtioDeviceProtocolGuid ## BY_START diff --git a/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c b/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c new file mode 100644 index 000000000..46a9354be --- /dev/null +++ b/roms/edk2/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c @@ -0,0 +1,328 @@ +/** @file + + This driver produces Virtio Device Protocol instances for Virtio PCI devices. + + Copyright (C) 2012, Red Hat, Inc. + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ Copyright (C) 2013, ARM Ltd. + Copyright (C) 2017, AMD Inc, All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include +#include "VirtioPciDevice.h" + +/** + + Read a word from Region 0 of the device specified by VirtIo Device protocol. + + The function implements the ReadDevice protocol member of + VIRTIO_DEVICE_PROTOCOL. + + @param[in] This VirtIo Device protocol. + + @param[in] FieldOffset Source offset. + + @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }. + + @param[in] BufferSize Number of bytes available in the target buffer. Must + equal FieldSize. + + @param[out] Buffer Target buffer. + + + @return Status code returned by PciIo->Io.Read(). + +**/ +EFI_STATUS +EFIAPI +VirtioPciDeviceRead ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoRead (Dev, + Dev->DeviceSpecificConfigurationOffset + FieldOffset, + FieldSize, BufferSize, Buffer); +} + +/** + + Write a word into Region 0 of the device specified by VirtIo Device protocol. + + @param[in] This VirtIo Device protocol. + + @param[in] FieldOffset Destination offset. + + @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }. + + @param[in] Value Little endian value to write, converted to UINT64. + The least significant FieldSize bytes will be used. + + + @return Status code returned by PciIo->Io.Write(). + +**/ +EFI_STATUS +EFIAPI +VirtioPciDeviceWrite ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINT64 Value + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoWrite (Dev, + Dev->DeviceSpecificConfigurationOffset + FieldOffset, FieldSize, Value); +} + +EFI_STATUS +EFIAPI +VirtioPciGetDeviceFeatures ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT64 *DeviceFeatures + ) +{ + VIRTIO_PCI_DEVICE *Dev; + EFI_STATUS Status; + UINT32 Features32; + + if (DeviceFeatures == NULL) { + return EFI_INVALID_PARAMETER; + } + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + Status = VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_DEVICE_FEATURES, + sizeof (UINT32), sizeof (UINT32), &Features32); + if (!EFI_ERROR (Status)) { + *DeviceFeatures = Features32; + } + return Status; +} + +EFI_STATUS +EFIAPI +VirtioPciGetQueueSize ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT16 *QueueNumMax + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + if (QueueNumMax == NULL) { + return EFI_INVALID_PARAMETER; + } + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_SIZE, sizeof (UINT16), + sizeof (UINT16), QueueNumMax); +} + +EFI_STATUS +EFIAPI +VirtioPciGetDeviceStatus ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT8 *DeviceStatus + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + if (DeviceStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS, + sizeof (UINT8), sizeof (UINT8), DeviceStatus); +} + +EFI_STATUS +EFIAPI +VirtioPciSetGuestFeatures ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT64 Features + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + if (Features > MAX_UINT32) { + return EFI_UNSUPPORTED; + } + return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_GUEST_FEATURES, + sizeof (UINT32), Features); +} + +EFI_STATUS +EFIAPI +VirtioPciSetQueueAddress ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN VRING *Ring, + IN UINT64 RingBaseShift + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + ASSERT (RingBaseShift == 0); + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_ADDRESS, sizeof (UINT32), + (UINT32)((UINTN)Ring->Base >> EFI_PAGE_SHIFT)); +} + +EFI_STATUS +EFIAPI +VirtioPciSetQueueSel ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT16 Sel + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_SELECT, sizeof (UINT16), + Sel); +} + +EFI_STATUS +EFIAPI +VirtioPciSetQueueAlignment ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT32 Alignment + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioPciSetPageSize ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT32 PageSize + ) +{ + return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +VirtioPciSetQueueNotify ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT16 Index + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_NOTIFY, sizeof (UINT16), + Index); +} + +EFI_STATUS +EFIAPI +VirtioPciSetQueueSize ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT16 Size + ) +{ + // + // This function is only applicable in Virtio-MMIO. + // (The QueueSize field is read-only in Virtio proper (PCI)) + // + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioPciSetDeviceStatus ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT8 DeviceStatus + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS, + sizeof (UINT8), DeviceStatus); +} + +EFI_STATUS +EFIAPI +VirtioPciAllocateSharedPages ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN NumPages, + OUT VOID **HostAddress + ) +{ + VOID *Buffer; + + Buffer = AllocatePages (NumPages); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *HostAddress = Buffer; + return EFI_SUCCESS; +} + +VOID +EFIAPI +VirtioPciFreeSharedPages ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN NumPages, + IN VOID *HostAddress + ) +{ + FreePages (HostAddress, NumPages); +} + +EFI_STATUS +EFIAPI +VirtioPciMapSharedBuffer ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN VIRTIO_MAP_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + *DeviceAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress; + *Mapping = NULL; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioPciUnmapSharedBuffer ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN VOID *Mapping + ) +{ + return EFI_SUCCESS; +} -- cgit