blob: caf2c42b1e08f1a7c55bcfeeb334a78de24e8837 [file] [log] [blame]
/** @file
Driver for the virtual Xen PCI device
Copyright (C) 2012, Red Hat, Inc.
Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
Copyright (C) 2013, ARM Ltd.
Copyright (C) 2015, Linaro Ltd.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <IndustryStandard/Acpi.h>
#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 <Protocol/PciIo.h>
#include <Protocol/XenIo.h>
#define PCI_VENDOR_ID_XEN 0x5853
#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
/**
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 The driver does not support the device being probed.
@return Error codes from the OpenProtocol() boot service or
the PciIo protocol.
**/
STATIC
EFI_STATUS
EFIAPI
XenIoPciDeviceBindingSupported (
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) {
if ((Pci.Hdr.VendorId == PCI_VENDOR_ID_XEN) &&
(Pci.Hdr.DeviceId == PCI_DEVICE_ID_XEN_PLATFORM))
{
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;
}
/**
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 The device was started.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@return Error codes from the OpenProtocol() boot
service, the PciIo protocol or the
InstallProtocolInterface() boot service.
**/
STATIC
EFI_STATUS
EFIAPI
XenIoPciDeviceBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE DeviceHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
XENIO_PROTOCOL *XenIo;
EFI_PCI_IO_PROTOCOL *PciIo;
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
XenIo = (XENIO_PROTOCOL *)AllocateZeroPool (sizeof *XenIo);
if (XenIo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gBS->OpenProtocol (
DeviceHandle,
&gEfiPciIoProtocolGuid,
(VOID **)&PciIo,
This->DriverBindingHandle,
DeviceHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto FreeXenIo;
}
//
// The BAR1 of this PCI device is used for shared memory and is supposed to
// look like MMIO. The address space of the BAR1 will be used to map the
// Grant Table.
//
Status = PciIo->GetBarAttributes (PciIo, PCI_BAR_IDX1, NULL, (VOID **)&BarDesc);
ASSERT_EFI_ERROR (Status);
ASSERT (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);
/* Get a Memory address for mapping the Grant Table. */
DEBUG ((DEBUG_INFO, "XenIoPci: BAR at %LX\n", BarDesc->AddrRangeMin));
XenIo->GrantTableAddress = BarDesc->AddrRangeMin;
FreePool (BarDesc);
Status = gBS->InstallProtocolInterface (
&DeviceHandle,
&gXenIoProtocolGuid,
EFI_NATIVE_INTERFACE,
XenIo
);
if (!EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
gBS->CloseProtocol (
DeviceHandle,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
DeviceHandle
);
FreeXenIo:
FreePool (XenIo);
return Status;
}
/**
Stop driving the XenIo 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
XenIoPciDeviceBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE DeviceHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
XENIO_PROTOCOL *XenIo;
Status = gBS->OpenProtocol (
DeviceHandle, // candidate device
&gXenIoProtocolGuid, // retrieve the XenIo iface
(VOID **)&XenIo, // 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;
}
//
// Handle Stop() requests for in-use driver instances gracefully.
//
Status = gBS->UninstallProtocolInterface (
DeviceHandle,
&gXenIoProtocolGuid,
XenIo
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->CloseProtocol (
DeviceHandle,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
DeviceHandle
);
FreePool (XenIo);
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 = {
&XenIoPciDeviceBindingSupported,
&XenIoPciDeviceBindingStart,
&XenIoPciDeviceBindingStop,
0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
NULL, // ImageHandle, to be overwritten by
// EfiLibInstallDriverBindingComponentName2() in XenIoPciDeviceEntryPoint()
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"XenIo PCI Driver" },
{ NULL, NULL }
};
STATIC
EFI_COMPONENT_NAME_PROTOCOL gComponentName;
EFI_STATUS
EFIAPI
XenIoPciGetDriverName (
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
XenIoPciGetDeviceName (
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 = {
&XenIoPciGetDriverName,
&XenIoPciGetDeviceName,
"eng" // SupportedLanguages, ISO 639-2 language codes
};
STATIC
EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&XenIoPciGetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&XenIoPciGetDeviceName,
"en" // SupportedLanguages, RFC 4646 language codes
};
//
// Entry point of this driver.
//
EFI_STATUS
EFIAPI
XenIoPciDeviceEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gDriverBinding,
ImageHandle,
&gComponentName,
&gComponentName2
);
}