2013-12-11 17:57:49 +01:00
|
|
|
/** @file
|
|
|
|
|
|
|
|
This driver produces Virtio Device Protocol instances for Virtio PCI devices.
|
|
|
|
|
|
|
|
Copyright (C) 2012, Red Hat, Inc.
|
2016-07-08 08:21:07 +02:00
|
|
|
Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
|
2013-12-11 17:57:49 +01:00
|
|
|
Copyright (C) 2013, ARM Ltd.
|
2017-08-23 12:57:15 +02:00
|
|
|
Copyright (C) 2017, AMD Inc, All rights reserved.<BR>
|
2013-12-11 17:57:49 +01:00
|
|
|
|
2019-04-04 01:06:33 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2013-12-11 17:57:49 +01:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#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
|
2017-08-23 12:57:15 +02:00
|
|
|
VirtioPciDeviceRead, // ReadDevice
|
|
|
|
VirtioPciAllocateSharedPages, // AllocateSharedPages
|
|
|
|
VirtioPciFreeSharedPages, // FreeSharedPages
|
|
|
|
VirtioPciMapSharedBuffer, // MapSharedBuffer
|
|
|
|
VirtioPciUnmapSharedBuffer, // UnmapSharedBuffer
|
2013-12-11 17:57:49 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
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
|
2016-07-08 08:21:07 +02:00
|
|
|
Driver Execution Environment) with the following service.
|
2013-12-11 17:57:49 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-08-14 13:36:23 +02:00
|
|
|
Status = Device->PciIo->Attributes (
|
|
|
|
Device->PciIo,
|
|
|
|
EfiPciIoAttributeOperationEnable,
|
|
|
|
(EFI_PCI_IO_ATTRIBUTE_IO |
|
|
|
|
EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
|
|
|
|
NULL
|
|
|
|
);
|
2013-12-11 17:57:49 +01:00
|
|
|
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
|
|
|
|
);
|
|
|
|
}
|