REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the OvmfPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Andrew Fish <afish@apple.com>
		
			
				
	
	
		
			718 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			718 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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.<BR>
 | |
|   Copyright (C) 2013, ARM Ltd.
 | |
|   Copyright (C) 2017, AMD Inc, All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <IndustryStandard/Pci.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/UefiLib.h>
 | |
| 
 | |
| #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
 | |
|            );
 | |
| }
 |