diff options
author | Steven Kinney <steven.kinney@linaro.org> | 2013-11-20 16:42:40 -0600 |
---|---|---|
committer | Steven Kinney <steven.kinney@linaro.org> | 2013-11-20 16:42:40 -0600 |
commit | 5b7afff892fdaf87dcde2d5d926774718662822d (patch) | |
tree | fe337805dcc03f471bf5658b6cb5d409dc3321e0 | |
parent | 5eea14ca2868314e4af2e50a2c64d7987b3b3e71 (diff) | |
parent | 6a90696e53f829e790a8ab67a8040dfd6707f313 (diff) |
Merge branch 'linaro-topic-virtio' into linaro-tracking-2013.11linaro-uefi-2013.11-rc3
45 files changed, 2813 insertions, 650 deletions
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.c b/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.c new file mode 100644 index 0000000000..8982568c52 --- /dev/null +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.c @@ -0,0 +1,73 @@ +/** @file + + Copyright (c) 2013, ARM Ltd. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Library/UefiLib.h> +#include <Library/VirtioMmioDeviceLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#define ARM_FVP_BASE_VIRTIO_BLOCK_BASE 0x1c130000 + +typedef struct { + VENDOR_DEVICE_PATH Vendor; + EFI_DEVICE_PATH_PROTOCOL End; +} VIRTIO_BLK_DEVICE_PATH; + +VIRTIO_BLK_DEVICE_PATH mVirtioBlockDevicePath = +{ + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)( sizeof(VENDOR_DEVICE_PATH) ), + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8) + } + }, + EFI_CALLER_ID_GUID, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } +}; + +EFI_STATUS +EFIAPI +ArmFvpInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->InstallProtocolInterface (&ImageHandle, + &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE, + &mVirtioBlockDevicePath); + if (EFI_ERROR (Status)) { + return Status; + } + + // Declare the Virtio BlockIo device + Status = VirtioMmioInstallDevice (ARM_FVP_BASE_VIRTIO_BLOCK_BASE, ImageHandle); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ArmFvpDxe: Failed to install Virtio block device\n")); + } + + return Status; +} diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.inf b/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.inf new file mode 100644 index 0000000000..893fd8d41d --- /dev/null +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.inf @@ -0,0 +1,35 @@ +#/** @file +# +# Copyright (c) 2013, ARM Ltd. All rights reserved.<BR> +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = ArmFvpDxe + FILE_GUID = fe61bb5f-1b67-4c24-b346-73db42e873e5 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = ArmFvpInitialise + +[Sources.common] + ArmFvpDxe.c + +[Packages] + MdePkg/MdePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + VirtioMmioDeviceLib + BaseMemoryLib diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4-foundation.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4-foundation.dsc index 6ed5649ed0..29dbbafef7 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4-foundation.dsc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4-foundation.dsc @@ -34,6 +34,10 @@ ArmCpuLib|ArmPkg/Drivers/ArmCpuLib/ArmCortexAEMv8Lib/ArmCortexAEMv8Lib.inf
ArmPlatformLib|ArmPlatformPkg/ArmVExpressPkg/Library/ArmVExpressLibRTSM/ArmVExpressFoundationLib.inf
+ # Virtio Support + VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf + VirtioMmioDeviceLib|OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf + ArmPlatformSysConfigLib|ArmPlatformPkg/ArmVExpressPkg/Library/ArmVExpressSysConfigLib/ArmVExpressSysConfigLib.inf
TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
@@ -238,6 +242,12 @@ ArmPkg/Filesystem/SemihostFs/SemihostFs.inf
#
+ # Platform Driver + # + ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.inf + OvmfPkg/VirtioBlkDxe/VirtioBlk.inf + + # # FAT filesystem + GPT/MBR partitioning
#
MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4-foundation.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4-foundation.fdf index 6c84f522f2..9981daf58f 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4-foundation.fdf +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4-foundation.fdf @@ -168,6 +168,12 @@ READ_LOCK_STATUS = TRUE INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
#
+ # Platform Driver + # + INF ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.inf + INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf + + # # UEFI application (Shell Embedded Boot Loader)
#
INF ShellBinPkg/UefiShell/UefiShell.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.dsc index 7cbdb643d1..cf5823d9ad 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.dsc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.dsc @@ -40,6 +40,10 @@ TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
+ # VirtIo Support + VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf + VirtioMmioDeviceLib|OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf + [LibraryClasses.common.SEC]
ArmLib|ArmPkg/Library/ArmLib/AArch64/AArch64LibSec.inf
ArmPlatformSecLib|ArmPlatformPkg/ArmVExpressPkg/Library/ArmVExpressSecLibRTSM/ArmVExpressSecLib.inf
@@ -267,6 +271,12 @@ ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
#
+ # Platform Driver + # + ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.inf + OvmfPkg/VirtioBlkDxe/VirtioBlk.inf + + # # FAT filesystem + GPT/MBR partitioning
#
MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.fdf b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.fdf index 531415d0da..af1b0fa97d 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.fdf +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.fdf @@ -176,7 +176,13 @@ READ_LOCK_STATUS = TRUE #
INF EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
INF ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
-
+ + # + # Platform Driver + # + INF ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.inf + INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf + #
# UEFI application (Shell Embedded Boot Loader)
#
diff --git a/OvmfPkg/Include/IndustryStandard/Virtio.h b/OvmfPkg/Include/IndustryStandard/Virtio.h index 622a8deef0..75c5a9c85a 100644 --- a/OvmfPkg/Include/IndustryStandard/Virtio.h +++ b/OvmfPkg/Include/IndustryStandard/Virtio.h @@ -4,6 +4,7 @@ specification.
Copyright (C) 2012, Red Hat, Inc.
+ Portion of Copyright (C) 2013, ARM Ltd. This program and the accompanying materials are licensed and made available
under the terms and conditions of the BSD License which accompanies this
@@ -35,6 +36,53 @@ #define VIRTIO_SUBSYSTEM_MAC80211_WLAN 10
//
+// Virtio IDs +// +#define VIRTIO_VENDOR_ID 0x1AF4 +#define VIRTIO_MMIO_MAGIC 0x74726976 // "virt" + + +// +// VirtIo Device Specific Configuration Offsets +// +#define VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI 20 +#define VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI_WITH_MSI_X 24 +#define VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO 0x100 + +// PCI VirtIo Header Offsets +// +#define VIRTIO_PCI_OFFSET_DEVICE_FEATURES 0x00 +#define VIRTIO_PCI_OFFSET_GUEST_FEATURES 0x04 +#define VIRTIO_PCI_OFFSET_QUEUE_ADDRESS 0x08 +#define VIRTIO_PCI_OFFSET_QUEUE_SIZE 0x0C +#define VIRTIO_PCI_OFFSET_QUEUE_SELECT 0x0E +#define VIRTIO_PCI_OFFSET_QUEUE_NOTIFY 0x10 +#define VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS 0x12 +#define VIRTIO_PCI_OFFSET_QUEUE_DEVICE_ISR 0x13 + +// +// MMIO VirtIo Header Offsets +// +#define VIRTIO_MMIO_OFFSET_MAGIC 0x00 +#define VIRTIO_MMIO_OFFSET_VERSION 0x04 +#define VIRTIO_MMIO_OFFSET_DEVICE_ID 0x08 +#define VIRTIO_MMIO_OFFSET_VENDOR_ID 0x0C +#define VIRTIO_MMIO_OFFSET_HOST_FEATURES 0x10 +#define VIRTIO_MMIO_OFFSET_HOST_FEATURES_SEL 0x14 +#define VIRTIO_MMIO_OFFSET_GUEST_FEATURES 0x20 +#define VIRTIO_MMIO_OFFSET_GUEST_FEATURES_SEL 0x24 +#define VIRTIO_MMIO_OFFSET_GUEST_PAGE_SIZE 0x28 +#define VIRTIO_MMIO_OFFSET_QUEUE_SEL 0x30 +#define VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX 0x34 +#define VIRTIO_MMIO_OFFSET_QUEUE_NUM 0x38 +#define VIRTIO_MMIO_OFFSET_QUEUE_ALIGN 0x3C +#define VIRTIO_MMIO_OFFSET_QUEUE_PFN 0x40 +#define VIRTIO_MMIO_OFFSET_QUEUE_NOTIFY 0x50 +#define VIRTIO_MMIO_OFFSET_INTERRUPT_STATUS 0x60 +#define VIRTIO_MMIO_OFFSET_INTERRUPT_ACK 0x64 +#define VIRTIO_MMIO_OFFSET_STATUS 0x70 + +// // Data in the communication area is defined as packed and accessed as
// volatile.
//
@@ -107,24 +155,6 @@ typedef struct { UINT16 QueueSize;
} VRING;
-
-//
-// virtio-0.9.5, 2.2.2 Virtio Header -- no MSI-X
-//
-#pragma pack(1)
-typedef struct {
- UINT32 VhdrDeviceFeatureBits;
- UINT32 VhdrGuestFeatureBits;
- UINT32 VhdrQueueAddress;
- UINT16 VhdrQueueSize;
- UINT16 VhdrQueueSelect;
- UINT16 VhdrQueueNotify;
- UINT8 VhdrDeviceStatus;
- UINT8 VhdrISR;
-} VIRTIO_HDR;
-#pragma pack()
-
-
//
// virtio-0.9.5, 2.2.2.1 Device Status
//
diff --git a/OvmfPkg/Include/IndustryStandard/VirtioBlk.h b/OvmfPkg/Include/IndustryStandard/VirtioBlk.h index b71f224b65..55f6548edc 100644 --- a/OvmfPkg/Include/IndustryStandard/VirtioBlk.h +++ b/OvmfPkg/Include/IndustryStandard/VirtioBlk.h @@ -26,19 +26,18 @@ //
#pragma pack(1)
typedef struct {
- VIRTIO_HDR Generic;
- UINT64 VhdrCapacity;
- UINT32 VhdrSizeMax;
- UINT32 VhdrSegMax;
- UINT16 VhdrCylinders;
- UINT8 VhdrHeads;
- UINT8 VhdrSectors;
- UINT32 VhdrBlkSize;
-} VBLK_HDR;
+ UINT64 Capacity; + UINT32 SizeMax; + UINT32 SegMax; + UINT16 Cylinders; + UINT8 Heads; + UINT8 Sectors; + UINT32 BlkSize; +} VIRTIO_BLK_CONFIG; #pragma pack()
-#define OFFSET_OF_VBLK(Field) OFFSET_OF (VBLK_HDR, Field)
-#define SIZE_OF_VBLK(Field) (sizeof ((VBLK_HDR *) 0)->Field)
+#define OFFSET_OF_VBLK(Field) OFFSET_OF (VIRTIO_BLK_CONFIG, Field) +#define SIZE_OF_VBLK(Field) (sizeof ((VIRTIO_BLK_CONFIG *) 0)->Field) #define VIRTIO_BLK_F_BARRIER BIT0
#define VIRTIO_BLK_F_SIZE_MAX BIT1
diff --git a/OvmfPkg/Include/IndustryStandard/VirtioNet.h b/OvmfPkg/Include/IndustryStandard/VirtioNet.h index 03dfeb2c59..90d9702cba 100644 --- a/OvmfPkg/Include/IndustryStandard/VirtioNet.h +++ b/OvmfPkg/Include/IndustryStandard/VirtioNet.h @@ -1,5 +1,4 @@ /** @file
-
Virtio Network Device specific type and macro definitions corresponding to
the virtio-0.9.5 specification.
@@ -25,14 +24,13 @@ //
#pragma pack(1)
typedef struct {
- VIRTIO_HDR Generic;
- UINT8 VhdrMac[6];
- UINT16 VhdrLinkStatus;
-} VNET_HDR;
+ UINT8 Mac[6]; + UINT16 LinkStatus; +} VIRTIO_NET_CONFIG; #pragma pack()
-#define OFFSET_OF_VNET(Field) OFFSET_OF (VNET_HDR, Field)
-#define SIZE_OF_VNET(Field) (sizeof ((VNET_HDR *) 0)->Field)
+#define OFFSET_OF_VNET(Field) OFFSET_OF (VIRTIO_NET_CONFIG, Field) +#define SIZE_OF_VNET(Field) (sizeof ((VIRTIO_NET_CONFIG *) 0)->Field) //
// Queue Identifiers
@@ -91,7 +89,7 @@ typedef struct { #define VIRTIO_NET_HDR_GSO_ECN BIT7
//
-// Link Status Bits in VNET_HDR.VhdrLinkStatus
+// Link Status Bits in VIRTIO_NET_CONFIG.LinkStatus //
#define VIRTIO_NET_S_LINK_UP BIT0
#define VIRTIO_NET_S_ANNOUNCE BIT1
diff --git a/OvmfPkg/Include/IndustryStandard/VirtioScsi.h b/OvmfPkg/Include/IndustryStandard/VirtioScsi.h index 59ce97e070..884e4d642a 100644 --- a/OvmfPkg/Include/IndustryStandard/VirtioScsi.h +++ b/OvmfPkg/Include/IndustryStandard/VirtioScsi.h @@ -26,22 +26,21 @@ //
#pragma pack(1)
typedef struct {
- VIRTIO_HDR Generic;
- UINT32 VhdrNumQueues;
- UINT32 VhdrSegMax;
- UINT32 VhdrMaxSectors;
- UINT32 VhdrCmdPerLun;
- UINT32 VhdrEventInfoSize;
- UINT32 VhdrSenseSize;
- UINT32 VhdrCdbSize;
- UINT16 VhdrMaxChannel;
- UINT16 VhdrMaxTarget;
- UINT32 VhdrMaxLun;
-} VSCSI_HDR;
+ UINT32 NumQueues; + UINT32 SegMax; + UINT32 MaxSectors; + UINT32 CmdPerLun; + UINT32 EventInfoSize; + UINT32 SenseSize; + UINT32 CdbSize; + UINT16 MaxChannel; + UINT16 MaxTarget; + UINT32 MaxLun; +} VIRTIO_SCSI_CONFIG; #pragma pack()
-#define OFFSET_OF_VSCSI(Field) OFFSET_OF (VSCSI_HDR, Field)
-#define SIZE_OF_VSCSI(Field) (sizeof ((VSCSI_HDR *) 0)->Field)
+#define OFFSET_OF_VSCSI(Field) OFFSET_OF (VIRTIO_SCSI_CONFIG, Field) +#define SIZE_OF_VSCSI(Field) (sizeof ((VIRTIO_SCSI_CONFIG *) 0)->Field) #define VIRTIO_SCSI_F_INOUT BIT0
#define VIRTIO_SCSI_F_HOTPLUG BIT1
diff --git a/OvmfPkg/Include/Library/VirtioLib.h b/OvmfPkg/Include/Library/VirtioLib.h index 51303491d0..e61a5090eb 100644 --- a/OvmfPkg/Include/Library/VirtioLib.h +++ b/OvmfPkg/Include/Library/VirtioLib.h @@ -17,71 +17,10 @@ #ifndef _VIRTIO_LIB_H_
#define _VIRTIO_LIB_H_
-#include <Protocol/PciIo.h>
+#include <Protocol/VirtioDevice.h> + #include <IndustryStandard/Virtio.h>
-/**
-
- 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
- driver-specific VIRTIO_CFG_WRITE() macros.
-
- @param[in] PciIo Target 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
-VirtioWrite (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINTN FieldOffset,
- IN UINTN FieldSize,
- IN UINT64 Value
- );
-
-
-/**
-
- 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
- driver-specific VIRTIO_CFG_READ() macros.
-
- @param[in] PciIo Source 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
-VirtioRead (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINTN FieldOffset,
- IN UINTN FieldSize,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- );
-
/**
@@ -218,7 +157,7 @@ VirtioAppendDesc ( Notify the host about the descriptor chain just built, and wait until the
host processes it.
- @param[in] PciIo The target virtio PCI device to notify.
+ @param[in] VirtIo The target virtio device to notify. @param[in] VirtQueueId Identifies the queue for the target device.
@@ -229,7 +168,7 @@ VirtioAppendDesc ( of the descriptor chain.
- @return Error code from VirtioWrite() if it fails.
+ @return Error code from VirtioWriteDevice() if it fails. @retval EFI_SUCCESS Otherwise, the host processed all descriptors.
@@ -237,10 +176,10 @@ VirtioAppendDesc ( EFI_STATUS
EFIAPI
VirtioFlush (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINT16 VirtQueueId,
- IN OUT VRING *Ring,
- IN DESC_INDICES *Indices
+ IN VIRTIO_DEVICE_PROTOCOL *VirtIo, + IN UINT16 VirtQueueId, + IN OUT VRING *Ring, + IN DESC_INDICES *Indices );
#endif // _VIRTIO_LIB_H_
diff --git a/OvmfPkg/Include/Library/VirtioMmioDeviceLib.h b/OvmfPkg/Include/Library/VirtioMmioDeviceLib.h new file mode 100644 index 0000000000..73e5a9e8d3 --- /dev/null +++ b/OvmfPkg/Include/Library/VirtioMmioDeviceLib.h @@ -0,0 +1,65 @@ +/** @file + + Definitions for the VirtIo MMIO Device Library + + Copyright (C) 2013, ARM Ltd + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _VIRTIO_MMIO_DEVICE_LIB_H_ +#define _VIRTIO_MMIO_DEVICE_LIB_H_ + +/** + + Initialize VirtIo Device and Install VIRTIO_DEVICE_PROTOCOL protocol + + @param[in] BaseAddress Base Address of the VirtIo MMIO Device + + @param[in] Handle Handle of the device the driver should be attached to. + + @retval EFI_SUCCESS The VirtIo Device has been installed + successfully. + + @retval EFI_OUT_OF_RESOURCES The function failed too allocate memory require + by the Virtio MMIO device initialization. + + @retval EFI_UNSUPPORTED BaseAddress does not point to a VirtIo MMIO + device. + + @return Status code returned by InstallProtocolInterface + Boot Service function. + +**/ +EFI_STATUS +VirtioMmioInstallDevice ( + IN PHYSICAL_ADDRESS BaseAddress, + IN EFI_HANDLE Handle + ); + +/** + + Uninstall the VirtIo Device + + @param[in] Handle Handle of the device where the VirtIo Device protocol + should have been installed. + + @retval EFI_SUCCESS The device has been un-initialized successfully. + + @return Status code returned by UninstallProtocolInterface + Boot Service function. + +**/ +EFI_STATUS +VirtioMmioUninstallDevice ( + IN EFI_HANDLE Handle + ); + +#endif // _VIRTIO_MMIO_DEVICE_LIB_H_ diff --git a/OvmfPkg/Include/Protocol/VirtioDevice.h b/OvmfPkg/Include/Protocol/VirtioDevice.h new file mode 100644 index 0000000000..cecac0541a --- /dev/null +++ b/OvmfPkg/Include/Protocol/VirtioDevice.h @@ -0,0 +1,376 @@ +/** @file + Virtio Device + + Copyright (c) 2013, ARM Ltd. All rights reserved.<BR> + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __VIRTIO_DEVICE_H__ +#define __VIRTIO_DEVICE_H__ + +// VirtIo Specification Revision: Major[31:24].Minor[23:16].Revision[15:0 +#define VIRTIO_SPEC_REVISION(major,minor,revision) \ + ((((major) & 0xFF) << 24) | (((minor) & 0xFF) << 16) | ((revision) & 0xFFFF)) + +#define VIRTIO_DEVICE_PROTOCOL_GUID { \ + 0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a }\ + } + +typedef struct _VIRTIO_DEVICE_PROTOCOL VIRTIO_DEVICE_PROTOCOL; + +/** + + Read a word from the device-specific I/O region of the Virtio Header. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] FieldOffset Source offset. + + @param[in] FieldSize Source field size in bytes, 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. + + @retval EFI_SUCCESS The data was read successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and read size. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_DEVICE_READ) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + + Write a word to the device-specific I/O region of the Virtio Header. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] FieldOffset Destination offset. + + @param[in] FieldSize Destination field size in bytes, + must be in {1, 2, 4, 8}. + + @param[out] Value Value to write. + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and write size. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_DEVICE_WRITE) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINT64 Value + ); + +/** + Read the device features field from the Virtio Header. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[out] DeviceFeatures The 32-bit device features field. + + @retval EFI_SUCCESS The data was read successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and read size. + @retval EFI_INVALID_PARAMETER DeviceFeatures is NULL +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_GET_DEVICE_FEATURES) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT32 *DeviceFeatures + ); + +/** + Write the guest features field in the Virtio Header. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] Features The 32-bit guest guest features field + +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_SET_GUEST_FEATURES) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT32 Features + ); + +/** + Read the queue address field from the Virtio Header. + + QueueAddress is the address of the virtqueue divided by 4096. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[out] QueueAddress The 32-bit queue address field. + + @retval EFI_SUCCESS The data was read successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and read size. + @retval EFI_INVALID_PARAMETER QueueAddress is NULL +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_GET_QUEUE_ADDRESS) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT32 *QueueAddress + ); + +/** + Write the queue address field in the Virtio Header. + + The parameter Address must be the base address of the virtqueue divided + by 4096. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] Address The 32-bit Queue Address field + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and write size. +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_SET_QUEUE_ADDRESS) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT32 Address + ); + +/** + + Write the queue select field in the Virtio Header. + + Writing to the queue select field sets the index of the queue to which + operations such as SetQueueAlign and GetQueueNumMax apply. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] Index The index of the queue to select + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and write size. +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_SET_QUEUE_SEL) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT16 Index + ); + +/** + + Write the queue notify field in the Virtio Header. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] Address The 32-bit Queue Notify field + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and write size. +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_SET_QUEUE_NOTIFY) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT16 Index + ); + +/** + Write the queue alignment field in the Virtio Header. + + The queue to which the alignment applies is selected by the Queue Select + field. + + Note: This operation is not implemented by the VirtIo over PCI. The PCI + implementation of this protocol returns EFI_SUCCESS. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] Alignment The alignment boundary of the Used Ring in bytes. + Must be a power of 2. + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and write size. +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_SET_QUEUE_ALIGN) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT32 Alignment + ); + +/** + Write the guest page size. + + Note: This operation is not implemented by the VirtIo over PCI. The PCI + implementation of this protocol returns EFI_SUCCESS. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] PageSize Size of the Guest page in bytes. + Must be a power of 2. + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and write size. +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_SET_PAGE_SIZE) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT32 PageSize + ); + +/** + + Get the size of the virtqueue selected by the queue select field. + + See Virtio spec Section 2.3 + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[out] QueueNumMax The size of the virtqueue in bytes. + Always a power of 2. + + @retval EFI_SUCCESS The data was read successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and read size. + @retval EFI_INVALID_PARAMETER QueueNumMax is NULL +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_GET_QUEUE_NUM_MAX) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT16 *QueueNumMax + ); + +/** + + Write to the QueueNum field in the Virtio Header. + + This function only applies to Virtio-MMIO and may be a stub for other + implementations. See Virtio Spec appendix X. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] QueueSize The number of elements in the queue. + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and write size. +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_SET_QUEUE_NUM) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT16 QueueSize + ); + +/** + + Get the DeviceStatus field from the Virtio Header. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[out] DeviceStatus The 8-bit value for the Device status field + + @retval EFI_SUCCESS The data was read successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and read size. + @retval EFI_INVALID_PARAMETER DeviceStatus is NULL +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_GET_DEVICE_STATUS) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT8 *DeviceStatus + ); + +/** + + Write the DeviceStatus field in the Virtio Header. + + @param[in] This This instance of VIRTIO_DEVICE_PROTOCOL + + @param[in] DeviceStatus The 8-bit value for the Device status field + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_UNSUPPORTED The underlying IO device doesn't support the + provided address offset and write size. +**/ +typedef +EFI_STATUS +(EFIAPI *VIRTIO_SET_DEVICE_STATUS) ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT8 DeviceStatus + ); + + +/// +/// This protocol provides an abstraction over the VirtIo transport layer +/// +struct _VIRTIO_DEVICE_PROTOCOL { + /// VirtIo Specification Revision encoded with VIRTIO_SPEC_REVISION() + UINT32 Revision; + /// From the Virtio Spec + INT32 SubSystemDeviceId; + + VIRTIO_GET_DEVICE_FEATURES GetDeviceFeatures; + VIRTIO_SET_GUEST_FEATURES SetGuestFeatures; + + VIRTIO_GET_QUEUE_ADDRESS GetQueueAddress; + VIRTIO_SET_QUEUE_ADDRESS SetQueueAddress; + + VIRTIO_SET_QUEUE_SEL SetQueueSel; + + VIRTIO_SET_QUEUE_NOTIFY SetQueueNotify; + + VIRTIO_SET_QUEUE_ALIGN SetQueueAlign; + VIRTIO_SET_PAGE_SIZE SetPageSize; + + VIRTIO_GET_QUEUE_NUM_MAX GetQueueNumMax; + VIRTIO_SET_QUEUE_NUM SetQueueNum; + + VIRTIO_GET_DEVICE_STATUS GetDeviceStatus; + VIRTIO_SET_DEVICE_STATUS SetDeviceStatus; + + // Functions to read/write Device Specific headers + VIRTIO_DEVICE_WRITE WriteDevice; + VIRTIO_DEVICE_READ ReadDevice; +}; + +extern EFI_GUID gVirtioDeviceProtocolGuid; + +#endif diff --git a/OvmfPkg/Library/VirtioLib/VirtioLib.c b/OvmfPkg/Library/VirtioLib/VirtioLib.c index 959bc5da87..1550318d81 100644 --- a/OvmfPkg/Library/VirtioLib/VirtioLib.c +++ b/OvmfPkg/Library/VirtioLib/VirtioLib.c @@ -3,6 +3,7 @@ Utility functions used by virtio device drivers.
Copyright (C) 2012, Red Hat, Inc.
+ Portion of Copyright (C) 2013, ARM Ltd. This program and the accompanying materials are licensed and made available
under the terms and conditions of the BSD License which accompanies this
@@ -14,7 +15,6 @@ **/
-#include <IndustryStandard/Pci22.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
@@ -26,143 +26,6 @@ /**
- 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
- driver-specific VIRTIO_CFG_WRITE() macros.
-
- @param[in] PciIo Target 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
-VirtioWrite (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINTN FieldOffset,
- IN UINTN FieldSize,
- IN UINT64 Value
- )
-{
- UINTN Count;
- EFI_PCI_IO_PROTOCOL_WIDTH Width;
-
- Count = 1;
- switch (FieldSize) {
- case 1:
- Width = EfiPciIoWidthUint8;
- break;
-
- case 2:
- Width = EfiPciIoWidthUint16;
- break;
-
- case 8:
- 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
- );
-}
-
-
-/**
-
- 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
- driver-specific VIRTIO_CFG_READ() macros.
-
- @param[in] PciIo Source 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
-VirtioRead (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINTN FieldOffset,
- IN UINTN FieldSize,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
-{
- UINTN Count;
- EFI_PCI_IO_PROTOCOL_WIDTH Width;
-
- ASSERT (FieldSize == BufferSize);
-
- Count = 1;
- switch (FieldSize) {
- case 1:
- Width = EfiPciIoWidthUint8;
- break;
-
- case 2:
- Width = EfiPciIoWidthUint16;
- break;
-
- case 8:
- 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
- );
-}
-
-
-/**
-
Configure a virtio ring.
This function sets up internal storage (the guest-host communication area)
@@ -376,7 +239,7 @@ VirtioAppendDesc ( Notify the host about the descriptor chain just built, and wait until the
host processes it.
- @param[in] PciIo The target virtio PCI device to notify.
+ @param[in] VirtIo The target virtio device to notify. @param[in] VirtQueueId Identifies the queue for the target device.
@@ -387,7 +250,7 @@ VirtioAppendDesc ( of the descriptor chain.
- @return Error code from VirtioWrite() if it fails.
+ @return Error code from VirtioWriteDevice() if it fails. @retval EFI_SUCCESS Otherwise, the host processed all descriptors.
@@ -395,10 +258,10 @@ VirtioAppendDesc ( EFI_STATUS
EFIAPI
VirtioFlush (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINT16 VirtQueueId,
- IN OUT VRING *Ring,
- IN DESC_INDICES *Indices
+ IN VIRTIO_DEVICE_PROTOCOL *VirtIo, + IN UINT16 VirtQueueId, + IN OUT VRING *Ring, + IN DESC_INDICES *Indices )
{
UINT16 NextAvailIdx;
@@ -427,12 +290,7 @@ VirtioFlush ( // OK.
//
MemoryFence();
- Status = VirtioWrite (
- PciIo,
- OFFSET_OF (VIRTIO_HDR, VhdrQueueNotify),
- sizeof (UINT16),
- VirtQueueId
- );
+ Status = VirtIo->SetQueueNotify (VirtIo, VirtQueueId); if (EFI_ERROR (Status)) {
return Status;
}
diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c new file mode 100644 index 0000000000..f763db5fb8 --- /dev/null +++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c @@ -0,0 +1,204 @@ +/** @file + + This driver produces Virtio Device Protocol instances for Virtio Mmio devices. + + Copyright (C) 2013, ARM Ltd. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include "VirtioMmioDevice.h" + +static VIRTIO_DEVICE_PROTOCOL mMmioDeviceProtocolTemplate = { + 0, // Revision + 0, // SubSystemDeviceId + VirtioMmioGetDeviceFeatures, // GetDeviceFeatures + VirtioMmioSetGuestFeatures, // SetGuestFeatures + VirtioMmioGetQueueAddress, // GetQueueAddress + VirtioMmioSetQueueAddress, // SetQueueAddress + VirtioMmioSetQueueSel, // SetQueueSel + VirtioMmioSetQueueNotify, // SetQueueNotify + VirtioMmioSetQueueAlignment, // SetQueueAlign + VirtioMmioSetPageSize, // SetPageSize + VirtioMmioGetQueueSize, // GetQueueNumMax + VirtioMmioSetQueueSize, // SetQueueNum + VirtioMmioGetDeviceStatus, // GetDeviceStatus + VirtioMmioSetDeviceStatus, // SetDeviceStatus + VirtioMmioDeviceWrite, // WriteDevice + VirtioMmioDeviceRead // ReadDevice +}; + +/** + + Initialize the VirtIo MMIO Device + + @param[in] BaseAddress Base Address of the VirtIo MMIO Device + + @param[in, out] Device The driver instance to configure. + + @retval EFI_SUCCESS Setup complete. + + @retval EFI_UNSUPPORTED The driver is not a VirtIo MMIO device. + +**/ +STATIC +EFI_STATUS +EFIAPI +VirtioMmioInit ( + IN PHYSICAL_ADDRESS BaseAddress, + IN OUT VIRTIO_MMIO_DEVICE *Device + ) +{ + UINT32 MagicValue; + UINT32 VendorId; + UINT32 Version; + + // Initialize VirtIo Mmio Device + CopyMem (&Device->VirtioDevice, &mMmioDeviceProtocolTemplate, + sizeof (VIRTIO_DEVICE_PROTOCOL)); + Device->BaseAddress = BaseAddress; + Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5); + Device->VirtioDevice.SubSystemDeviceId = + MmioRead32 (BaseAddress + VIRTIO_MMIO_OFFSET_DEVICE_ID); + + // Double-check MMIO-specific values + MagicValue = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_MAGIC); + if (MagicValue != VIRTIO_MMIO_MAGIC) { + return EFI_UNSUPPORTED; + } + + Version = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VERSION); + if (Version != 1) { + return EFI_UNSUPPORTED; + } + + // Double-check MMIO-specific values + VendorId = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VENDOR_ID); + if (VendorId != VIRTIO_VENDOR_ID) { + // The ARM Base and Foundation Models do not report a valid VirtIo VendorId. + // They return a value of 0x0 for the VendorId. + DEBUG((EFI_D_WARN, "VirtioMmioInit: Warning: The VendorId (0x%X) does not " + "match the VirtIo VendorId (0x%X).\n", + VendorId, VIRTIO_VENDOR_ID)); + //return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + + +/** + + Uninitialize the internals of a virtio-mmio device that has been successfully + set up with VirtioMmioInit(). + + @param[in, out] Device The device to clean up. + +**/ + +STATIC +VOID +EFIAPI +VirtioMmioUninit ( + IN VIRTIO_MMIO_DEVICE *Device + ) +{ + // Note: This function mirrors VirtioMmioInit() that does not allocate any + // resources - there's nothing to free here. +} + +EFI_STATUS +VirtioMmioInstallDevice ( + IN PHYSICAL_ADDRESS BaseAddress, + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + VIRTIO_MMIO_DEVICE *VirtIo; + + if (!BaseAddress) { + return EFI_INVALID_PARAMETER; + } + if (Handle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Allocate VIRTIO_MMIO_DEVICE + VirtIo = AllocateZeroPool (sizeof (VIRTIO_MMIO_DEVICE)); + if (VirtIo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + VirtIo->Signature = VIRTIO_MMIO_DEVICE_SIGNATURE; + + Status = VirtioMmioInit (BaseAddress, VirtIo); + if (EFI_ERROR (Status)) { + goto FreeVirtioMem; + } + + // Install VIRTIO_DEVICE_PROTOCOL to Handle + Status = gBS->InstallProtocolInterface (&Handle, + &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE, + &VirtIo->VirtioDevice); + if (EFI_ERROR (Status)) { + goto UninitVirtio; + } + + return EFI_SUCCESS; + +UninitVirtio: + VirtioMmioUninit (VirtIo); + +FreeVirtioMem: + FreePool (VirtIo); + return Status; +} + +EFI_STATUS +VirtioMmioUninstallDevice ( + IN EFI_HANDLE DeviceHandle + ) +{ + VIRTIO_DEVICE_PROTOCOL *VirtioDevice; + VIRTIO_MMIO_DEVICE *MmioDevice; + EFI_STATUS Status; + + Status = gBS->OpenProtocol ( + DeviceHandle, // candidate device + &gVirtioDeviceProtocolGuid, // retrieve the VirtIo iface + (VOID **)&VirtioDevice, // target pointer + DeviceHandle, // requestor driver identity + DeviceHandle, // requesting lookup for dev. + EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get the MMIO device from the VirtIo Device instance + MmioDevice = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice); + + // Uninstall the protocol interface + Status = gBS->UninstallProtocolInterface (DeviceHandle, + &gVirtioDeviceProtocolGuid, &MmioDevice->VirtioDevice + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Uninitialize the VirtIo Device + VirtioMmioUninit (MmioDevice); + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.h b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.h new file mode 100644 index 0000000000..188d873ae1 --- /dev/null +++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.h @@ -0,0 +1,147 @@ +/** @file + + Internal definitions for the VirtIo MMIO Device driver + + Copyright (C) 2013, ARM Ltd + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _VIRTIO_MMIO_DEVICE_INTERNAL_H_ +#define _VIRTIO_MMIO_DEVICE_INTERNAL_H_ + +#include <Protocol/VirtioDevice.h> + +#include <IndustryStandard/Virtio.h> + +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/UefiLib.h> +#include <Library/VirtioMmioDeviceLib.h> + +#define VIRTIO_MMIO_DEVICE_SIGNATURE SIGNATURE_32 ('V', 'M', 'I', 'O') + +typedef struct { + UINT32 Signature; + VIRTIO_DEVICE_PROTOCOL VirtioDevice; + PHYSICAL_ADDRESS BaseAddress; +} VIRTIO_MMIO_DEVICE; + +#define VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE(Device) \ + CR (Device, VIRTIO_MMIO_DEVICE, VirtioDevice, VIRTIO_MMIO_DEVICE_SIGNATURE) + +#define VIRTIO_CFG_WRITE(Device, Offset, Val) \ + (MmioWrite32 (Device->BaseAddress + (Offset), Val)) +#define VIRTIO_CFG_READ(Device, Offset) \ + (MmioRead32 (Device->BaseAddress + (Offset))) + +EFI_STATUS +EFIAPI +VirtioMmioDeviceRead ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOFfset, + IN UINTN FieldSize, + IN UINTN BufferSize, + OUT VOID* Buffer + ); + +EFI_STATUS +EFIAPI +VirtioMmioDeviceWrite ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINT64 Value + ); + +EFI_STATUS +EFIAPI +VirtioMmioGetDeviceFeatures ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT32 *DeviceFeatures + ); + +EFI_STATUS +EFIAPI +VirtioMmioGetQueueAddress ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT32 *QueueAddress + ); + +EFI_STATUS +EFIAPI +VirtioMmioGetQueueSize ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT16 *QueueNumMax + ); + +EFI_STATUS +EFIAPI +VirtioMmioGetDeviceStatus ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT8 *DeviceStatus + ); + +EFI_STATUS +EFIAPI +VirtioMmioSetQueueSize ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT16 QueueSize + ); + +EFI_STATUS +EFIAPI +VirtioMmioSetDeviceStatus ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT8 DeviceStatus + ); + +EFI_STATUS +EFIAPI +VirtioMmioSetQueueNotify ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT16 QueueNotify + ); + +EFI_STATUS +EFIAPI +VirtioMmioSetQueueSel ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT16 Sel + ); + +EFI_STATUS +VirtioMmioSetQueueAddress ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Address + ); + +EFI_STATUS +EFIAPI +VirtioMmioSetQueueAlignment ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Alignment + ); + +EFI_STATUS +EFIAPI +VirtioMmioSetPageSize ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 PageSize + ); + +EFI_STATUS +EFIAPI +VirtioMmioSetGuestFeatures ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Features + ); + +#endif // _VIRTIO_MMIO_DEVICE_INTERNAL_H_ diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c new file mode 100644 index 0000000000..fa76f8ffce --- /dev/null +++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c @@ -0,0 +1,304 @@ +/** @file + + This driver produces Virtio Device Protocol instances for Virtio MMIO devices. + + Copyright (C) 2012, Red Hat, Inc. + Copyright (c) 2012, Intel Corporation. All rights reserved.<BR> + Copyright (C) 2013, ARM Ltd. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "VirtioMmioDevice.h" + +EFI_STATUS +EFIAPI +VirtioMmioGetDeviceFeatures ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT32 *DeviceFeatures + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + if (DeviceFeatures == NULL) { + return EFI_INVALID_PARAMETER; + } + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + *DeviceFeatures = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_HOST_FEATURES); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioGetQueueAddress ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT32 *QueueAddress + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + if (QueueAddress == NULL) { + + } + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + *QueueAddress = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_QUEUE_PFN); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioGetQueueSize ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT16 *QueueNumMax + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + if (QueueNumMax == NULL) { + return EFI_INVALID_PARAMETER; + } + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + *QueueNumMax = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX) & 0xFFFF; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioGetDeviceStatus ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT8 *DeviceStatus + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + if (DeviceStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + *DeviceStatus = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_STATUS) & 0xFF; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioSetQueueSize ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT16 QueueSize + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM, QueueSize); +} + +EFI_STATUS +EFIAPI +VirtioMmioSetDeviceStatus ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT8 DeviceStatus + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_STATUS, DeviceStatus); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioSetQueueNotify ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT16 QueueNotify + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NOTIFY, QueueNotify); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioSetQueueAlignment ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Alignment + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_ALIGN, Alignment); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioSetPageSize ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 PageSize + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + ASSERT (PageSize == EFI_PAGE_SIZE); + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_PAGE_SIZE, PageSize); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioSetQueueSel ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT16 Sel + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_SEL, Sel); + + return EFI_SUCCESS; +} + +EFI_STATUS +VirtioMmioSetQueueAddress ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Address + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_PFN, Address); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioSetGuestFeatures ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Features + ) +{ + VIRTIO_MMIO_DEVICE *Device; + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_FEATURES, Features); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioDeviceWrite ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINT64 Value + ) +{ + UINTN DstBaseAddress; + VIRTIO_MMIO_DEVICE *Device; + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + // Double-check fieldsize + if (FieldSize > 8) { + return EFI_INVALID_PARAMETER; + } + + if ((FieldSize != 1) && (FieldSize != 2) && + (FieldSize != 4) && (FieldSize != 8)) { + return EFI_INVALID_PARAMETER; + } + + // Compute base address + DstBaseAddress = Device->BaseAddress + + VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO + FieldOffset; + + // + // The device-specific memory area of Virtio-MMIO can only be written in + // byte accesses. This is not currently in the Virtio spec. + // + MmioWriteBuffer8 (DstBaseAddress, FieldSize, (UINT8*)&Value); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioMmioDeviceRead ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + UINTN SrcBaseAddress; + VIRTIO_MMIO_DEVICE *Device; + + Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This); + + // Parameter validation + ASSERT (FieldSize == BufferSize); + + // Double-check fieldsize + if (FieldSize > 8) { + return EFI_INVALID_PARAMETER; + } + + if ((FieldSize != 1) && (FieldSize != 2) && + (FieldSize != 4) && (FieldSize != 8)) { + return EFI_INVALID_PARAMETER; + } + + // Compute base address + SrcBaseAddress = Device->BaseAddress + + VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO + FieldOffset; + + // + // The device-specific memory area of Virtio-MMIO can only be read in + // byte reads. This is not currently in the Virtio spec. + // + MmioReadBuffer8 (SrcBaseAddress, BufferSize, Buffer); + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf new file mode 100644 index 0000000000..0758375aa5 --- /dev/null +++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf @@ -0,0 +1,43 @@ +## @file +# This driver produces the VirtIo Device Protocol instances for VirtIo Mmio +# Device +# +# Copyright (C) 2013, ARM Ltd +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = VirtioMmioDeviceLib + FILE_GUID = 3b6ed966-b5d1-46a8-965b-867ff22d9c89 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = VirtioMmioDeviceLib + +[Sources] + VirtioMmioDevice.c + VirtioMmioDeviceFunctions.c + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + IoLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gVirtioDeviceProtocolGuid ## PRODUCES diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index d874f0c44f..11c44534aa 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -44,6 +44,7 @@ gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
[Protocols]
+ gVirtioDeviceProtocolGuid = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}} gBlockMmioProtocolGuid = {0x6b558ce3, 0x69e5, 0x4c67, {0xa6, 0x34, 0xf7, 0xfe, 0x72, 0xad, 0xbe, 0x84}}
[PcdsFixedAtBuild]
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index dd8270b119..c57822bdd4 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -408,6 +408,7 @@ }
OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
+ OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf index df4f2276ee..b13cf05899 100644 --- a/OvmfPkg/OvmfPkgIa32.fdf +++ b/OvmfPkg/OvmfPkgIa32.fdf @@ -181,6 +181,7 @@ INF MdeModulePkg/Universal/Metronome/Metronome.inf INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
INF OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
+INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
INF OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 8c665504c3..171cbe2b7a 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -415,6 +415,7 @@ }
OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
+ OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf index d93a7ff2e5..9965c3cf5a 100644 --- a/OvmfPkg/OvmfPkgIa32X64.fdf +++ b/OvmfPkg/OvmfPkgIa32X64.fdf @@ -181,6 +181,7 @@ INF MdeModulePkg/Universal/Metronome/Metronome.inf INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
INF OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
+INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
INF OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index 5ab3d63747..08c81e4a5b 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -413,6 +413,7 @@ }
OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
+ OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf index deee977271..e2420c5cfa 100644 --- a/OvmfPkg/OvmfPkgX64.fdf +++ b/OvmfPkg/OvmfPkgX64.fdf @@ -181,6 +181,7 @@ INF MdeModulePkg/Universal/Metronome/Metronome.inf INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
INF OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
+INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
INF OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c index 17b9f71d63..08edf23fce 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c @@ -23,7 +23,6 @@ **/
-#include <IndustryStandard/Pci.h>
#include <IndustryStandard/VirtioBlk.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
@@ -37,14 +36,14 @@ /**
Convenience macros to read and write region 0 IO space elements of the
- virtio-blk PCI device, for configuration purposes.
+ virtio-blk device, for configuration purposes. The following macros make it possible to specify only the "core parameters"
for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()
returns, the transaction will have been completed.
- @param[in] Dev Pointer to the VBLK_DEV structure whose PCI IO space
- we're accessing. Dev->PciIo must be valid.
+ @param[in] Dev Pointer to the VBLK_DEV structure whose VirtIo space + we're accessing. Dev->VirtIo must be valid. @param[in] Field A field name from VBLK_HDR, identifying the virtio-blk
configuration item to access.
@@ -57,23 +56,23 @@ one of UINT8, UINT16, UINT32, UINT64.
- @return Status code returned by VirtioWrite() / VirtioRead().
+ @return Status code returned by Virtio->WriteDevice() / Virtio->ReadDevice(). **/
-#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWrite ( \
- (Dev)->PciIo, \
- OFFSET_OF_VBLK (Field), \
- SIZE_OF_VBLK (Field), \
- (Value) \
+#define VIRTIO_CFG_WRITE(Dev, Field, Value) ((Dev)->VirtIo->WriteDevice ( \ + (Dev)->VirtIo, \ + OFFSET_OF_VBLK (Field), \ + SIZE_OF_VBLK (Field), \ + (Value) \ ))
-#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \
- (Dev)->PciIo, \
- OFFSET_OF_VBLK (Field), \
- SIZE_OF_VBLK (Field), \
- sizeof *(Pointer), \
- (Pointer) \
+#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice ( \ + (Dev)->VirtIo, \ + OFFSET_OF_VBLK (Field), \ + SIZE_OF_VBLK (Field), \ + sizeof *(Pointer), \ + (Pointer) \ ))
@@ -229,7 +228,7 @@ VerifyReadWriteRequest ( @retval EFI_SUCCESS Transfer complete.
- @retval EFI_DEVICE_ERROR Failed to notify host side via PCI write, or
+ @retval EFI_DEVICE_ERROR Failed to notify host side via VirtIo write, or unable to parse host response, or host response
is not VIRTIO_BLK_S_OK.
@@ -324,7 +323,7 @@ SynchronousRequest ( //
// virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).
//
- if (VirtioFlush (Dev->PciIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&
+ if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS && HostStatus == VIRTIO_BLK_S_OK) {
return EFI_SUCCESS;
}
@@ -500,11 +499,6 @@ VirtioBlkFlushBlocks ( underlying device
- 9 Driver Binding Protocol -- for exporting ourselves
- Specs relevant in the specific sense:
- - UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol
- - Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design
- Guidelines, 18.3 PCI drivers.
-
@param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
incorporating this driver (independently of
any device).
@@ -516,11 +510,11 @@ VirtioBlkFlushBlocks ( @retval EFI_SUCCESS The driver supports the device being probed.
- @retval EFI_UNSUPPORTED Based on virtio-blk PCI discovery, we do not support
+ @retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support the device.
@return Error codes from the OpenProtocol() boot service or
- the PciIo protocol.
+ the VirtIo protocol. **/
@@ -533,56 +527,36 @@ VirtioBlkDriverBindingSupported ( )
{
EFI_STATUS Status;
- EFI_PCI_IO_PROTOCOL *PciIo;
- PCI_TYPE00 Pci;
+ VIRTIO_DEVICE_PROTOCOL *VirtIo; //
- // Attempt to open the device with the PciIo set of interfaces. On success,
- // the protocol is "instantiated" for the PCI device. Covers duplicate open
+ // Attempt to open the device with the VirtIo set of interfaces. On success, + // the protocol is "instantiated" for the VirtIo device. Covers duplicate open // attempts (EFI_ALREADY_STARTED).
//
Status = gBS->OpenProtocol (
DeviceHandle, // candidate device
- &gEfiPciIoProtocolGuid, // for generic PCI access
- (VOID **)&PciIo, // handle to instantiate
+ &gVirtioDeviceProtocolGuid, // for generic VirtIo access + (VOID **)&VirtIo, // 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
+ EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo 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
- //
- Status = (Pci.Hdr.VendorId == 0x1AF4 &&
- Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F &&
- Pci.Hdr.RevisionID == 0x00 &&
- Pci.Device.SubsystemID == VIRTIO_SUBSYSTEM_BLOCK_DEVICE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
+ if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) { + Status = EFI_UNSUPPORTED; }
//
- // We needed PCI IO access only transitorily, to see whether we support the
+ // We needed VirtIo access only transitorily, to see whether we support the // device or not.
//
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle);
return Status;
}
@@ -594,8 +568,8 @@ VirtioBlkDriverBindingSupported ( device.
@param[in out] Dev The driver instance to configure. The caller is
- responsible for Dev->PciIo's validity (ie. working IO
- access to the underlying virtio-blk PCI device).
+ responsible for Dev->VirtIo's validity (ie. working IO + access to the underlying virtio-blk device). @retval EFI_SUCCESS Setup complete.
@@ -626,31 +600,40 @@ VirtioBlkInit ( // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
//
NextDevStat = 0; // step 1 -- reset device
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto Failed;
}
NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto Failed;
}
NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto Failed;
}
//
+ // Set Page Size - MMIO VirtIo Specific + // + Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE); + if (EFI_ERROR (Status)) { + goto ReleaseQueue; + } + + // // step 4a -- retrieve and validate features
//
- Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);
+ Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features); if (EFI_ERROR (Status)) {
goto Failed;
}
- Status = VIRTIO_CFG_READ (Dev, VhdrCapacity, &NumSectors);
+ + Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors); if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -660,7 +643,7 @@ VirtioBlkInit ( }
if (Features & VIRTIO_BLK_F_BLK_SIZE) {
- Status = VIRTIO_CFG_READ (Dev, VhdrBlkSize, &BlockSize);
+ Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize); if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -681,11 +664,11 @@ VirtioBlkInit ( //
// step 4b -- allocate virtqueue
//
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, 0);
+ Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0); if (EFI_ERROR (Status)) {
goto Failed;
}
- Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);
+ Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize); if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -700,22 +683,31 @@ VirtioBlkInit ( }
//
+ // Additional steps for MMIO: align the queue appropriately, and set the size + Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize); + Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE); + if (EFI_ERROR (Status)) { + goto ReleaseQueue; + } + + // // step 4c -- Report GPFN (guest-physical frame number) of queue. If anything
// fails from here on, we must release the ring resources.
//
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress,
- (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);
+ Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, + (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT); if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
+ //
// step 5 -- Report understood features. There are no virtio-blk specific
// features to negotiate in virtio-0.9.5, plus we do not want any of the
// device-independent (known or unknown) VIRTIO_F_* capabilities (see
// Appendix B).
//
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, 0);
+ Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, 0); if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@@ -724,7 +716,7 @@ VirtioBlkInit ( // step 6 -- initialization complete
//
NextDevStat |= VSTAT_DRIVER_OK;
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@@ -758,10 +750,10 @@ ReleaseQueue: Failed:
//
// Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
- // Status. PCI IO access failure here should not mask the original error.
+ // Status. VirtIo access failure here should not mask the original error. //
NextDevStat |= VSTAT_FAILED;
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); return Status; // reached only via Failed above
}
@@ -788,7 +780,7 @@ VirtioBlkUninit ( // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
// the old comms area.
//
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); VirtioRingUninit (&Dev->Ring);
@@ -815,13 +807,13 @@ VirtioBlkUninit ( @retval EFI_SUCCESS Driver instance has been created and
- initialized for the virtio-blk PCI device, it
+ initialized for the virtio-blk device, it is now accessibla via EFI_BLOCK_IO_PROTOCOL.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@return Error codes from the OpenProtocol() boot
- service, the PciIo protocol, VirtioBlkInit(),
+ service, the VirtIo protocol, VirtioBlkInit(), or the InstallProtocolInterface() boot service.
**/
@@ -842,43 +834,23 @@ VirtioBlkDriverBindingStart ( return EFI_OUT_OF_RESOURCES;
}
- Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
- (VOID **)&Dev->PciIo, This->DriverBindingHandle,
+ Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, + (VOID **)&Dev->VirtIo, This->DriverBindingHandle, DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) {
goto FreeVirtioBlk;
}
- //
- // 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-blk we only need IO space access.
- //
- Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet,
- 0, &Dev->OriginalPciAttributes);
- if (EFI_ERROR (Status)) {
- goto ClosePciIo;
- }
-
- Status = Dev->PciIo->Attributes (Dev->PciIo,
- EfiPciIoAttributeOperationEnable,
- EFI_PCI_IO_ATTRIBUTE_IO, NULL);
- if (EFI_ERROR (Status)) {
- goto ClosePciIo;
+ if (Dev->VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) { + return EFI_UNSUPPORTED; }
//
- // PCI IO access granted, configure virtio-blk device.
+ // VirtIo access granted, configure virtio-blk device. //
Status = VirtioBlkInit (Dev);
if (EFI_ERROR (Status)) {
- goto RestorePciAttributes;
+ goto CloseVirtIo; }
//
@@ -897,12 +869,8 @@ VirtioBlkDriverBindingStart ( UninitDev:
VirtioBlkUninit (Dev);
-RestorePciAttributes:
- Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
- Dev->OriginalPciAttributes, NULL);
-
-ClosePciIo:
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+CloseVirtIo: + gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle);
FreeVirtioBlk:
@@ -973,10 +941,7 @@ VirtioBlkDriverBindingStop ( VirtioBlkUninit (Dev);
- Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
- Dev->OriginalPciAttributes, NULL);
-
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle);
FreePool (Dev);
diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.h b/OvmfPkg/VirtioBlkDxe/VirtioBlk.h index d22570def9..43dd5064d4 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.h +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.h @@ -21,7 +21,6 @@ #include <Protocol/BlockIo.h>
#include <Protocol/ComponentName.h>
#include <Protocol/DriverBinding.h>
-#include <Protocol/PciIo.h>
#include <IndustryStandard/Virtio.h>
@@ -34,14 +33,13 @@ typedef struct { // at various call depths. The table to the right should make it easier to
// track them.
//
- // field init function init dpth
- // ---------------------- ------------------ ---------
- UINT32 Signature; // DriverBindingStart 0
- EFI_PCI_IO_PROTOCOL *PciIo; // DriverBindingStart 0
- UINT64 OriginalPciAttributes; // DriverBindingStart 0
- VRING Ring; // VirtioRingInit 2
- EFI_BLOCK_IO_PROTOCOL BlockIo; // VirtioBlkInit 1
- EFI_BLOCK_IO_MEDIA BlockIoMedia; // VirtioBlkInit 1
+ // field init function init dpth + // --------------------- ------------------ --------- + UINT32 Signature; // DriverBindingStart 0 + VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0 + VRING Ring; // VirtioRingInit 2 + EFI_BLOCK_IO_PROTOCOL BlockIo; // VirtioBlkInit 1 + EFI_BLOCK_IO_MEDIA BlockIoMedia; // VirtioBlkInit 1 } VBLK_DEV;
#define VIRTIO_BLK_FROM_BLOCK_IO(BlockIoPointer) \
@@ -66,11 +64,6 @@ typedef struct { underlying device
- 9 Driver Binding Protocol -- for exporting ourselves
- Specs relevant in the specific sense:
- - UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol
- - Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design
- Guidelines, 18.3 PCI drivers.
-
@param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
incorporating this driver (independently of
any device).
@@ -82,11 +75,10 @@ typedef struct { @retval EFI_SUCCESS The driver supports the device being probed.
- @retval EFI_UNSUPPORTED Based on virtio-blk PCI discovery, we do not support
+ @retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support the device.
- @return Error codes from the OpenProtocol() boot service or
- the PciIo protocol.
+ @return Error codes from the OpenProtocol() boot service. **/
@@ -117,14 +109,14 @@ VirtioBlkDriverBindingSupported ( @retval EFI_SUCCESS Driver instance has been created and
- initialized for the virtio-blk PCI device, it
+ initialized for the virtio-blk device, it is now accessibla via EFI_BLOCK_IO_PROTOCOL.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@return Error codes from the OpenProtocol() boot
- service, the PciIo protocol, VirtioBlkInit(),
- or the InstallProtocolInterface() boot service.
+ service, VirtioBlkInit(), or the + InstallProtocolInterface() boot service. **/
diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf b/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf index 6dffc3a22a..86266b26c4 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf @@ -38,5 +38,5 @@ VirtioLib
[Protocols]
- gEfiBlockIoProtocolGuid ## BY_START
- gEfiPciIoProtocolGuid ## TO_START
+ gEfiBlockIoProtocolGuid ## BY_START + gVirtioDeviceProtocolGuid ## TO_START diff --git a/OvmfPkg/VirtioNetDxe/ComponentName.c b/OvmfPkg/VirtioNetDxe/ComponentName.c index a291405ee6..1a43448fd4 100644 --- a/OvmfPkg/VirtioNetDxe/ComponentName.c +++ b/OvmfPkg/VirtioNetDxe/ComponentName.c @@ -139,20 +139,20 @@ VirtioNetGetControllerName ( }
//
- // confirm that the device is managed by this driver, using the PCI IO
+ // confirm that the device is managed by this driver, using the VirtIo // Protocol
//
Status = EfiTestManagedDevice (
ControllerHandle,
gVirtioNetDriverBinding.DriverBindingHandle,
- &gEfiPciIoProtocolGuid
+ &gVirtioDeviceProtocolGuid );
if (EFI_ERROR (Status)) {
return Status;
}
//
- // we don't give different names to the bus (= parent, = PCI) handle and the
+ // we don't give different names to the bus (= parent) handle and the // child (= MAC) handle
//
return LookupUnicodeString2 (
diff --git a/OvmfPkg/VirtioNetDxe/DriverBinding.c b/OvmfPkg/VirtioNetDxe/DriverBinding.c index c9259ab339..f92a447f00 100644 --- a/OvmfPkg/VirtioNetDxe/DriverBinding.c +++ b/OvmfPkg/VirtioNetDxe/DriverBinding.c @@ -15,7 +15,6 @@ **/
-#include <IndustryStandard/Pci.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h>
@@ -50,7 +49,7 @@ unused.
@retval EFI_UNSUPPORTED The host doesn't supply a MAC address.
- @return Status codes from Dev->PciIo->Io.Read(),
+ @return Status codes from Dev->VirtIo->Io.Read(), VIRTIO_CFG_READ() and VIRTIO_CFG_WRITE().
@retval EFI_SUCCESS Configuration values retrieved.
*/
@@ -74,19 +73,19 @@ VirtioNetGetFeatures ( // Initialization Sequence), but don't complete setting it up.
//
NextDevStat = 0; // step 1 -- reset device
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
return Status;
}
NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto YieldDevice;
}
NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto YieldDevice;
}
@@ -94,7 +93,7 @@ VirtioNetGetFeatures ( //
// step 4a -- retrieve and validate features
//
- Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);
+ Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features); if (EFI_ERROR (Status)) {
goto YieldDevice;
}
@@ -106,13 +105,12 @@ VirtioNetGetFeatures ( Status = EFI_UNSUPPORTED;
goto YieldDevice;
}
- Status = Dev->PciIo->Io.Read (Dev->PciIo, // PciIo
- EfiPciIoWidthUint8, // Width
- PCI_BAR_IDX0, // BarIndex
- OFFSET_OF_VNET (VhdrMac), // Offset
- SIZE_OF_VNET (VhdrMac), // Count
- MacAddress // Buffer
- );
+ Status = Dev->VirtIo->ReadDevice (Dev->VirtIo, + OFFSET_OF_VNET (Mac), // Offset + sizeof(UINT8), // FieldSize + SIZE_OF_VNET (Mac), // BufferSize + MacAddress // Buffer + ); if (EFI_ERROR (Status)) {
goto YieldDevice;
@@ -126,7 +124,7 @@ VirtioNetGetFeatures ( }
else {
*MediaPresentSupported = TRUE;
- Status = VIRTIO_CFG_READ (Dev, VhdrLinkStatus, &LinkStatus);
+ Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus); if (EFI_ERROR (Status)) {
goto YieldDevice;
}
@@ -134,7 +132,7 @@ VirtioNetGetFeatures ( }
YieldDevice:
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus,
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, EFI_ERROR (Status) ? VSTAT_FAILED : 0);
return Status;
@@ -207,9 +205,9 @@ VirtioNetSnpPopulate ( Dev->Snp.Mode = &Dev->Snm;
Dev->Snm.State = EfiSimpleNetworkStopped;
- Dev->Snm.HwAddressSize = SIZE_OF_VNET (VhdrMac);
- Dev->Snm.MediaHeaderSize = SIZE_OF_VNET (VhdrMac) + // dst MAC
- SIZE_OF_VNET (VhdrMac) + // src MAC
+ Dev->Snm.HwAddressSize = SIZE_OF_VNET (Mac); + Dev->Snm.MediaHeaderSize = SIZE_OF_VNET (Mac) + // dst MAC + SIZE_OF_VNET (Mac) + // src MAC 2; // Ethertype
Dev->Snm.MaxPacketSize = 1500;
Dev->Snm.NvRamSize = 0;
@@ -222,7 +220,7 @@ VirtioNetSnpPopulate ( Dev->Snm.MacAddressChangeable = FALSE;
Dev->Snm.MultipleTxSupported = TRUE;
- ASSERT (SIZE_OF_VNET (VhdrMac) <= sizeof (EFI_MAC_ADDRESS));
+ ASSERT (SIZE_OF_VNET (Mac) <= sizeof (EFI_MAC_ADDRESS)); Status = VirtioNetGetFeatures (Dev, &Dev->Snm.CurrentAddress,
&Dev->Snm.MediaPresentSupported, &Dev->Snm.MediaPresent);
@@ -230,8 +228,8 @@ VirtioNetSnpPopulate ( goto CloseWaitForPacket;
}
CopyMem (&Dev->Snm.PermanentAddress, &Dev->Snm.CurrentAddress,
- SIZE_OF_VNET (VhdrMac));
- SetMem (&Dev->Snm.BroadcastAddress, SIZE_OF_VNET (VhdrMac), 0xFF);
+ SIZE_OF_VNET (Mac)); + SetMem (&Dev->Snm.BroadcastAddress, SIZE_OF_VNET (Mac), 0xFF); //
// VirtioNetExitBoot() is queued by ExitBootServices(); its purpose is to
@@ -348,31 +346,36 @@ VirtioNetDriverBindingSupported ( )
{
EFI_STATUS Status;
- EFI_PCI_IO_PROTOCOL *PciIo;
- PCI_TYPE00 Pci;
-
- Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
- (VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER);
+ VIRTIO_DEVICE_PROTOCOL *VirtIo; + + // + // Attempt to open the device with the VirtIo set of interfaces. On success, + // the protocol is "instantiated" for the VirtIo device. Covers duplicate open + // attempts (EFI_ALREADY_STARTED). + // + Status = gBS->OpenProtocol ( + DeviceHandle, // candidate device + &gVirtioDeviceProtocolGuid, // for generic VirtIo access + (VOID **)&VirtIo, // handle to instantiate + This->DriverBindingHandle, // requestor driver identity + DeviceHandle, // ControllerHandle, according to + // the UEFI Driver Model + EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to + // the device; to be released + ); if (EFI_ERROR (Status)) {
return Status;
}
- Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0,
- sizeof Pci / sizeof (UINT32), &Pci);
+ if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_NETWORK_CARD) { + Status = EFI_UNSUPPORTED; + } //
- // virtio-0.9.5, 2.1 PCI Discovery:
- // the network device has Subsystem Device ID 1
+ // We needed VirtIo access only transitorily, to see whether we support the + // device or not. //
- if (Status == EFI_SUCCESS) {
- Status = (Pci.Hdr.VendorId == 0x1AF4 &&
- Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F &&
- Pci.Hdr.RevisionID == 0x00 &&
- Pci.Device.SubsystemID == VIRTIO_SUBSYSTEM_NETWORK_CARD) ? EFI_SUCCESS : EFI_UNSUPPORTED;
- }
-
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle);
return Status;
}
@@ -438,7 +441,7 @@ VirtioNetDriverBindingStart ( VNET_DEV *Dev;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
MAC_ADDR_DEVICE_PATH MacNode;
- VOID *ChildPciIo;
+ VOID *ChildVirtIo; //
// allocate space for the driver instance
@@ -449,30 +452,15 @@ VirtioNetDriverBindingStart ( }
Dev->Signature = VNET_SIG;
- //
- // get PCI access to the device and keep it open
- //
- Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
- (VOID **)&Dev->PciIo, This->DriverBindingHandle,
+ Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, + (VOID **)&Dev->VirtIo, This->DriverBindingHandle, DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) {
goto FreeVirtioNet;
}
- //
- // save original PCI attributes and enable IO space access
- //
- Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet,
- 0, &Dev->OrigPciAttributes);
- if (EFI_ERROR (Status)) {
- goto ClosePciIo;
- }
-
- Status = Dev->PciIo->Attributes (Dev->PciIo,
- EfiPciIoAttributeOperationEnable,
- EFI_PCI_IO_ATTRIBUTE_IO, NULL);
- if (EFI_ERROR (Status)) {
- goto ClosePciIo;
+ if (Dev->VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_NETWORK_CARD) { + return EFI_UNSUPPORTED; }
//
@@ -481,11 +469,11 @@ VirtioNetDriverBindingStart ( //
Status = VirtioNetSnpPopulate (Dev);
if (EFI_ERROR (Status)) {
- goto RestorePciAttributes;
+ goto CloseVirtIo; }
//
- // get the device path of the virtio-net PCI device -- one-shot open
+ // get the device path of the virtio-net device -- one-shot open //
Status = gBS->OpenProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid,
(VOID **)&DevicePath, This->DriverBindingHandle,
@@ -523,11 +511,11 @@ VirtioNetDriverBindingStart ( }
//
- // make a note that we keep this device open with PciIo for the sake of this
+ // make a note that we keep this device open with VirtIo for the sake of this // child
//
- Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
- &ChildPciIo, This->DriverBindingHandle,
+ Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, + &ChildVirtIo, This->DriverBindingHandle, Dev->MacHandle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
if (EFI_ERROR (Status)) {
goto UninstallMultiple;
@@ -547,12 +535,8 @@ FreeMacDevicePath: Evacuate:
VirtioNetSnpEvacuate (Dev);
-RestorePciAttributes:
- Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
- Dev->OrigPciAttributes, NULL);
-
-ClosePciIo:
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+CloseVirtIo: + gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle);
FreeVirtioNet:
@@ -637,7 +621,7 @@ VirtioNetDriverBindingStop ( Status = EFI_DEVICE_ERROR;
}
else {
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, Dev->MacHandle);
gBS->UninstallMultipleProtocolInterfaces (Dev->MacHandle,
&gEfiDevicePathProtocolGuid, Dev->MacDevicePath,
@@ -645,8 +629,6 @@ VirtioNetDriverBindingStop ( NULL);
FreePool (Dev->MacDevicePath);
VirtioNetSnpEvacuate (Dev);
- Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
- Dev->OrigPciAttributes, NULL);
FreePool (Dev);
}
@@ -657,7 +639,7 @@ VirtioNetDriverBindingStop ( //
// release remaining resources, tied directly to the parent handle
//
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle);
return EFI_SUCCESS;
diff --git a/OvmfPkg/VirtioNetDxe/Events.c b/OvmfPkg/VirtioNetDxe/Events.c index b9d7bbf6c6..4889580f3a 100644 --- a/OvmfPkg/VirtioNetDxe/Events.c +++ b/OvmfPkg/VirtioNetDxe/Events.c @@ -86,6 +86,6 @@ VirtioNetExitBoot ( Dev = Context;
if (Dev->Snm.State == EfiSimpleNetworkInitialized) {
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); }
}
diff --git a/OvmfPkg/VirtioNetDxe/SnpGetStatus.c b/OvmfPkg/VirtioNetDxe/SnpGetStatus.c index adb57cf8fe..b920115616 100644 --- a/OvmfPkg/VirtioNetDxe/SnpGetStatus.c +++ b/OvmfPkg/VirtioNetDxe/SnpGetStatus.c @@ -90,7 +90,7 @@ VirtioNetGetStatus ( if (Dev->Snm.MediaPresentSupported) {
UINT16 LinkStatus;
- Status = VIRTIO_CFG_READ (Dev, VhdrLinkStatus, &LinkStatus);
+ Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus); if (EFI_ERROR (Status)) {
goto Exit;
}
diff --git a/OvmfPkg/VirtioNetDxe/SnpInitialize.c b/OvmfPkg/VirtioNetDxe/SnpInitialize.c index 6cee014072..4352ab96b6 100644 --- a/OvmfPkg/VirtioNetDxe/SnpInitialize.c +++ b/OvmfPkg/VirtioNetDxe/SnpInitialize.c @@ -57,14 +57,15 @@ VirtioNetInitRing ( //
// step 4b -- allocate selected queue
//
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, Selector);
+ Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, Selector); if (EFI_ERROR (Status)) {
return Status;
}
- Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);
+ Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize); if (EFI_ERROR (Status)) {
return Status;
}
+ //
// For each packet (RX and TX alike), we need two descriptors:
// one for the virtio-net request header, and another one for the data
@@ -80,8 +81,8 @@ VirtioNetInitRing ( //
// step 4c -- report GPFN (guest-physical frame number) of queue
//
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress,
- (UINTN) Ring->Base >> EFI_PAGE_SHIFT);
+ Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, + (UINTN) Ring->Base >> EFI_PAGE_SHIFT); if (EFI_ERROR (Status)) {
VirtioRingUninit (Ring);
}
@@ -287,10 +288,9 @@ VirtioNetInitRx ( // virtio-0.9.5, 2.4.1.4 Notifying the Device
//
MemoryFence ();
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, VIRTIO_NET_Q_RX);
-
+ Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX); if (EFI_ERROR (Status)) {
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); FreePool (Dev->RxBuf);
}
@@ -366,25 +366,34 @@ VirtioNetInitialize ( // virtio-0.9.5 spec, 2.2.1 Device Initialization Sequence.
//
NextDevStat = VSTAT_ACK; // step 2 -- acknowledge device presence
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto InitFailed;
}
NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto DeviceFailed;
}
//
+ // Set Page Size - MMIO VirtIo Specific + // + Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE); + if (EFI_ERROR (Status)) { + goto ReleaseTxRing; + } + + // // step 4a -- retrieve features. Note that we're past validating required
// features in VirtioNetGetFeatures().
//
- Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);
+ Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features); if (EFI_ERROR (Status)) {
goto DeviceFailed;
}
+ ASSERT (Features & VIRTIO_NET_F_MAC);
ASSERT (Dev->Snm.MediaPresentSupported ==
!!(Features & VIRTIO_NET_F_STATUS));
@@ -406,7 +415,7 @@ VirtioNetInitialize ( // step 5 -- keep only the features we want
//
Features &= VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS;
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, Features);
+ Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features); if (EFI_ERROR (Status)) {
goto ReleaseTxRing;
}
@@ -415,7 +424,7 @@ VirtioNetInitialize ( // step 6 -- virtio-net initialization complete
//
NextDevStat |= VSTAT_DRIVER_OK;
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto ReleaseTxRing;
}
@@ -441,7 +450,7 @@ ReleaseTxAux: VirtioNetShutdownTx (Dev);
AbortDevice:
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); ReleaseTxRing:
VirtioRingUninit (&Dev->TxRing);
@@ -453,7 +462,7 @@ DeviceFailed: //
// restore device status invariant for the EfiSimpleNetworkStarted state
//
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); InitFailed:
gBS->RestoreTPL (OldTpl);
diff --git a/OvmfPkg/VirtioNetDxe/SnpReceive.c b/OvmfPkg/VirtioNetDxe/SnpReceive.c index 87c6ca9b4b..ce87978f1f 100644 --- a/OvmfPkg/VirtioNetDxe/SnpReceive.c +++ b/OvmfPkg/VirtioNetDxe/SnpReceive.c @@ -147,14 +147,14 @@ VirtioNetReceive ( CopyMem (Buffer, RxPtr, RxLen);
if (DestAddr != NULL) {
- CopyMem (DestAddr, RxPtr, SIZE_OF_VNET (VhdrMac));
+ CopyMem (DestAddr, RxPtr, SIZE_OF_VNET (Mac)); }
- RxPtr += SIZE_OF_VNET (VhdrMac);
+ RxPtr += SIZE_OF_VNET (Mac); if (SrcAddr != NULL) {
- CopyMem (SrcAddr, RxPtr, SIZE_OF_VNET (VhdrMac));
+ CopyMem (SrcAddr, RxPtr, SIZE_OF_VNET (Mac)); }
- RxPtr += SIZE_OF_VNET (VhdrMac);
+ RxPtr += SIZE_OF_VNET (Mac); if (Protocol != NULL) {
*Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
@@ -177,9 +177,7 @@ RecycleDesc: *Dev->RxRing.Avail.Idx = AvailIdx;
MemoryFence ();
- NotifyStatus = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify,
- VIRTIO_NET_Q_RX);
-
+ NotifyStatus = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX); if (!EFI_ERROR (Status)) { // earlier error takes precedence
Status = NotifyStatus;
}
diff --git a/OvmfPkg/VirtioNetDxe/SnpShutdown.c b/OvmfPkg/VirtioNetDxe/SnpShutdown.c index 42aeca1676..c05a22f659 100644 --- a/OvmfPkg/VirtioNetDxe/SnpShutdown.c +++ b/OvmfPkg/VirtioNetDxe/SnpShutdown.c @@ -63,7 +63,7 @@ VirtioNetShutdown ( break;
}
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); VirtioNetShutdownRx (Dev);
VirtioNetShutdownTx (Dev);
VirtioRingUninit (&Dev->TxRing);
diff --git a/OvmfPkg/VirtioNetDxe/SnpTransmit.c b/OvmfPkg/VirtioNetDxe/SnpTransmit.c index ff922ca021..b2a364b968 100644 --- a/OvmfPkg/VirtioNetDxe/SnpTransmit.c +++ b/OvmfPkg/VirtioNetDxe/SnpTransmit.c @@ -127,15 +127,15 @@ VirtioNetTransmit ( goto Exit;
}
Ptr = Buffer;
- ASSERT (SIZE_OF_VNET (VhdrMac) <= sizeof (EFI_MAC_ADDRESS));
+ ASSERT (SIZE_OF_VNET (Mac) <= sizeof (EFI_MAC_ADDRESS)); - CopyMem (Ptr, DestAddr, SIZE_OF_VNET (VhdrMac));
- Ptr += SIZE_OF_VNET (VhdrMac);
+ CopyMem (Ptr, DestAddr, SIZE_OF_VNET (Mac)); + Ptr += SIZE_OF_VNET (Mac); CopyMem (Ptr,
(SrcAddr == NULL) ? &Dev->Snm.CurrentAddress : SrcAddr,
- SIZE_OF_VNET (VhdrMac));
- Ptr += SIZE_OF_VNET (VhdrMac);
+ SIZE_OF_VNET (Mac)); + Ptr += SIZE_OF_VNET (Mac); *Ptr++ = (UINT8) (*Protocol >> 8);
*Ptr++ = (UINT8) *Protocol;
@@ -161,7 +161,7 @@ VirtioNetTransmit ( *Dev->TxRing.Avail.Idx = AvailIdx;
MemoryFence ();
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, VIRTIO_NET_Q_TX);
+ Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_TX); Exit:
gBS->RestoreTPL (OldTpl);
diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.h b/OvmfPkg/VirtioNetDxe/VirtioNet.h index 8c21bcdfa2..a0e0b4337c 100644 --- a/OvmfPkg/VirtioNetDxe/VirtioNet.h +++ b/OvmfPkg/VirtioNetDxe/VirtioNet.h @@ -24,7 +24,6 @@ #include <Protocol/ComponentName2.h>
#include <Protocol/DevicePath.h>
#include <Protocol/DriverBinding.h>
-#include <Protocol/PciIo.h>
#include <Protocol/SimpleNetwork.h>
#define VNET_SIG SIGNATURE_32 ('V', 'N', 'E', 'T')
@@ -75,8 +74,7 @@ typedef struct { // field init function
// ------------------ ------------------------------
UINT32 Signature; // VirtioNetDriverBindingStart
- EFI_PCI_IO_PROTOCOL *PciIo; // VirtioNetDriverBindingStart
- UINT64 OrigPciAttributes; // VirtioNetDriverBindingStart
+ VIRTIO_DEVICE_PROTOCOL *VirtIo; // VirtioNetDriverBindingStart EFI_SIMPLE_NETWORK_PROTOCOL Snp; // VirtioNetSnpPopulate
EFI_SIMPLE_NETWORK_MODE Snm; // VirtioNetSnpPopulate
EFI_EVENT ExitBoot; // VirtioNetSnpPopulate
@@ -109,19 +107,19 @@ typedef struct { #define VIRTIO_NET_FROM_SNP(SnpPointer) \
CR (SnpPointer, VNET_DEV, Snp, VNET_SIG)
-#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWrite ( \
- (Dev)->PciIo, \
- OFFSET_OF_VNET (Field), \
- SIZE_OF_VNET (Field), \
- (Value) \
+#define VIRTIO_CFG_WRITE(Dev, Field, Value) ((Dev)->VirtIo->WriteDevice ( \ + (Dev)->VirtIo, \ + OFFSET_OF_VNET (Field), \ + SIZE_OF_VNET (Field), \ + (Value) \ ))
-#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \
- (Dev)->PciIo, \
- OFFSET_OF_VNET (Field), \
- SIZE_OF_VNET (Field), \
- sizeof *(Pointer), \
- (Pointer) \
+#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice ( \ + (Dev)->VirtIo, \ + OFFSET_OF_VNET (Field), \ + SIZE_OF_VNET (Field), \ + sizeof *(Pointer), \ + (Pointer) \ ))
//
diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.inf b/OvmfPkg/VirtioNetDxe/VirtioNet.inf index 408a54112a..dea01f3b9a 100644 --- a/OvmfPkg/VirtioNetDxe/VirtioNet.inf +++ b/OvmfPkg/VirtioNetDxe/VirtioNet.inf @@ -57,4 +57,4 @@ [Protocols]
gEfiSimpleNetworkProtocolGuid ## BY_START
gEfiDevicePathProtocolGuid ## BY_START
- gEfiPciIoProtocolGuid ## TO_START
+ gVirtioDeviceProtocolGuid ## TO_START diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c new file mode 100644 index 0000000000..b120d5f2ca --- /dev/null +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c @@ -0,0 +1,667 @@ +/** @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.<BR> + Copyright (C) 2013, ARM Ltd. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 + VirtioPciGetQueueAddress, // GetQueueAddress + VirtioPciSetQueueAddress, // SetQueueAddress + VirtioPciSetQueueSel, // SetQueueSel + VirtioPciSetQueueNotify, // SetQueueNotify + VirtioPciSetQueueAlignment, // SetQueueAlignment + VirtioPciSetPageSize, // SetPageSize + VirtioPciGetQueueSize, // GetQueueNumMax + VirtioPciSetQueueSize, // SetQueueNum + VirtioPciGetDeviceStatus, // GetDeviceStatus + VirtioPciSetDeviceStatus, // SetDeviceStatus + VirtioPciDeviceWrite, // WriteDevice + VirtioPciDeviceRead // ReadDevice +}; + +/** + + 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; + + // The BufferSize must be a multiple of FieldSize + ASSERT ((BufferSize % FieldSize) == 0); + + PciIo = Dev->PciIo; + Count = BufferSize / FieldSize; + + 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 = 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 Exeuction 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, 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/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h new file mode 100644 index 0000000000..bbad164f6f --- /dev/null +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h @@ -0,0 +1,166 @@ +/** @file + + Internal definitions for the VirtIo PCI Device driver + + Copyright (C) 2013, ARM Ltd + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _VIRTIO_PCI_DEVICE_DXE_H_ +#define _VIRTIO_PCI_DEVICE_DXE_H_ + +#include <Protocol/ComponentName.h> +#include <Protocol/DriverBinding.h> +#include <Protocol/PciIo.h> +#include <Protocol/VirtioDevice.h> + +#include <IndustryStandard/Virtio.h> + +#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 UINT32 *DeviceFeatures + ); + +EFI_STATUS +EFIAPI +VirtioPciGetQueueAddress ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT32 *QueueAddress + ); + +EFI_STATUS +EFIAPI +VirtioPciGetQueueSize ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT16 *QueueNumMax + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueAlignment ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Alignment + ); + +EFI_STATUS +EFIAPI +VirtioPciSetPageSize ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 PageSize + ); + +EFI_STATUS +EFIAPI +VirtioPciGetDeviceStatus ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT8 *DeviceStatus + ); + +EFI_STATUS +EFIAPI +VirtioPciSetGuestFeatures ( + IN VIRTIO_DEVICE_PROTOCOL *This, + IN UINT32 Features + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueAddress ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Address + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueSel ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT16 Sel + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueNotify ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT16 Index + ); + +EFI_STATUS +EFIAPI +VirtioPciSetQueueSize ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT16 Size + ); + +EFI_STATUS +EFIAPI +VirtioPciSetDeviceStatus ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT8 DeviceStatus + ); + +#endif // _VIRTIO_PCI_DEVICE_DXE_H_ diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf new file mode 100644 index 0000000000..90a5dbc2b0 --- /dev/null +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf @@ -0,0 +1,43 @@ +## @file +# This driver produces the VirtIo Device Protocol instances for VirtIo PCI +# Device +# +# Copyright (C) 2013, ARM Ltd +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[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 + 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/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c new file mode 100644 index 0000000000..e9e48b945c --- /dev/null +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c @@ -0,0 +1,285 @@ +/** @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.<BR> + Copyright (C) 2013, ARM Ltd. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include "VirtioPciDevice.h" + +/** + + Read a word from Region 0 of the device specified by PciIo. + + The function implements the ReadDevice protocol member of + VIRTIO_DEVICE_PROTOCOL. + + @param[in] PciIo Source 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 +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 UINT32 *DeviceFeatures + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + if (DeviceFeatures == NULL) { + return EFI_INVALID_PARAMETER; + } + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_DEVICE_FEATURES, sizeof (UINT32), + sizeof (UINT32), DeviceFeatures); +} + +EFI_STATUS +EFIAPI +VirtioPciGetQueueAddress ( + IN VIRTIO_DEVICE_PROTOCOL *This, + OUT UINT32 *QueueAddress + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + if (QueueAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_ADDRESS, sizeof (UINT32), + sizeof (UINT32), QueueAddress); +} + +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 UINT32 Features + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_GUEST_FEATURES, + sizeof (UINT32), Features); +} + +EFI_STATUS +EFIAPI +VirtioPciSetQueueAddress ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Address + ) +{ + VIRTIO_PCI_DEVICE *Dev; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_ADDRESS, sizeof (UINT32), + Address); +} + +EFI_STATUS +EFIAPI +VirtioPciSetQueueSel ( + VIRTIO_DEVICE_PROTOCOL *This, + 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 ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 Alignment + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioPciSetPageSize ( + VIRTIO_DEVICE_PROTOCOL *This, + UINT32 PageSize + ) +{ + ASSERT (PageSize == EFI_PAGE_SIZE); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +VirtioPciSetQueueNotify ( + VIRTIO_DEVICE_PROTOCOL *This, + 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 ( + VIRTIO_DEVICE_PROTOCOL *This, + 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 ( + VIRTIO_DEVICE_PROTOCOL *This, + 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); +} diff --git a/OvmfPkg/VirtioScsiDxe/VirtioScsi.c b/OvmfPkg/VirtioScsiDxe/VirtioScsi.c index b836fb3e6a..3b6c3ade82 100644 --- a/OvmfPkg/VirtioScsiDxe/VirtioScsi.c +++ b/OvmfPkg/VirtioScsiDxe/VirtioScsi.c @@ -38,7 +38,6 @@ **/
-#include <IndustryStandard/Pci.h>
#include <IndustryStandard/VirtioScsi.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
@@ -52,14 +51,13 @@ /**
Convenience macros to read and write region 0 IO space elements of the
- virtio-scsi PCI device, for configuration purposes.
+ virtio-scsi VirtIo device, for configuration purposes. The following macros make it possible to specify only the "core parameters"
for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()
returns, the transaction will have been completed.
- @param[in] Dev Pointer to the VSCSI_DEV structure whose PCI IO space
- we're accessing. Dev->PciIo must be valid.
+ @param[in] Dev Pointer to the VirtIo Device Protocol @param[in] Field A field name from VSCSI_HDR, identifying the virtio-scsi
configuration item to access.
@@ -72,23 +70,23 @@ one of UINT8, UINT16, UINT32, UINT64.
- @return Status codes returned by VirtioWrite() / VirtioRead().
+ @return Status codes returned by Virtio->WriteDevice() / Virtio->ReadDevice(). **/
-#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWrite ( \
- (Dev)->PciIo, \
- OFFSET_OF_VSCSI (Field), \
- SIZE_OF_VSCSI (Field), \
- (Value) \
+#define VIRTIO_CFG_WRITE(Dev, Field, Value) ((Dev)->VirtIo->WriteDevice ( \ + (Dev)->VirtIo, \ + OFFSET_OF_VSCSI (Field), \ + SIZE_OF_VSCSI (Field), \ + (Value) \ ))
-#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \
- (Dev)->PciIo, \
- OFFSET_OF_VSCSI (Field), \
- SIZE_OF_VSCSI (Field), \
- sizeof *(Pointer), \
- (Pointer) \
+#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice ( \ + (Dev)->VirtIo, \ + OFFSET_OF_VSCSI (Field), \ + SIZE_OF_VSCSI (Field), \ + sizeof *(Pointer), \ + (Pointer) \ ))
@@ -471,7 +469,7 @@ VirtioScsiPassThru ( // EFI_NOT_READY would save us the effort, but it would also suggest that the
// caller retry.
//
- if (VirtioFlush (Dev->PciIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring,
+ if (VirtioFlush (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring, &Indices) != EFI_SUCCESS) {
Packet->InTransferLength = 0;
Packet->OutTransferLength = 0;
@@ -718,33 +716,41 @@ VirtioScsiInit ( // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
//
NextDevStat = 0; // step 1 -- reset device
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto Failed;
}
NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto Failed;
}
NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto Failed;
}
//
+ // Set Page Size - MMIO VirtIo Specific + // + Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE); + if (EFI_ERROR (Status)) { + goto ReleaseQueue; + } + + // // step 4a -- retrieve and validate features
//
- Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);
+ Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features); if (EFI_ERROR (Status)) {
goto Failed;
}
Dev->InOutSupported = !!(Features & VIRTIO_SCSI_F_INOUT);
- Status = VIRTIO_CFG_READ (Dev, VhdrMaxChannel, &MaxChannel);
+ Status = VIRTIO_CFG_READ (Dev, MaxChannel, &MaxChannel); if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -756,7 +762,7 @@ VirtioScsiInit ( goto Failed;
}
- Status = VIRTIO_CFG_READ (Dev, VhdrNumQueues, &NumQueues);
+ Status = VIRTIO_CFG_READ (Dev, NumQueues, &NumQueues); if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -765,7 +771,7 @@ VirtioScsiInit ( goto Failed;
}
- Status = VIRTIO_CFG_READ (Dev, VhdrMaxTarget, &Dev->MaxTarget);
+ Status = VIRTIO_CFG_READ (Dev, MaxTarget, &Dev->MaxTarget); if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -773,7 +779,7 @@ VirtioScsiInit ( Dev->MaxTarget = PcdGet16 (PcdVirtioScsiMaxTargetLimit);
}
- Status = VIRTIO_CFG_READ (Dev, VhdrMaxLun, &Dev->MaxLun);
+ Status = VIRTIO_CFG_READ (Dev, MaxLun, &Dev->MaxLun); if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -781,7 +787,7 @@ VirtioScsiInit ( Dev->MaxLun = PcdGet32 (PcdVirtioScsiMaxLunLimit);
}
- Status = VIRTIO_CFG_READ (Dev, VhdrMaxSectors, &Dev->MaxSectors);
+ Status = VIRTIO_CFG_READ (Dev, MaxSectors, &Dev->MaxSectors); if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -797,12 +803,11 @@ VirtioScsiInit ( //
// step 4b -- allocate request virtqueue
//
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect,
- VIRTIO_SCSI_REQUEST_QUEUE);
+ Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE); if (EFI_ERROR (Status)) {
goto Failed;
}
- Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);
+ Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize); if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -823,8 +828,8 @@ VirtioScsiInit ( // step 4c -- Report GPFN (guest-physical frame number) of queue. If anything
// fails from here on, we must release the ring resources.
//
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress,
- (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);
+ Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, + (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT); if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@@ -834,8 +839,8 @@ VirtioScsiInit ( // the known (or unknown) VIRTIO_SCSI_F_* or VIRTIO_F_* capabilities (see
// virtio-0.9.5, Appendices B and I), except bidirectional transfers.
//
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits,
- Features & VIRTIO_SCSI_F_INOUT);
+ Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, + Features & VIRTIO_SCSI_F_INOUT); if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@@ -844,11 +849,11 @@ VirtioScsiInit ( // We expect these maximum sizes from the host. Since they are
// guest-negotiable, ask for them rather than just checking them.
//
- Status = VIRTIO_CFG_WRITE (Dev, VhdrCdbSize, VIRTIO_SCSI_CDB_SIZE);
+ Status = VIRTIO_CFG_WRITE (Dev, CdbSize, VIRTIO_SCSI_CDB_SIZE); if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
- Status = VIRTIO_CFG_WRITE (Dev, VhdrSenseSize, VIRTIO_SCSI_SENSE_SIZE);
+ Status = VIRTIO_CFG_WRITE (Dev, SenseSize, VIRTIO_SCSI_SENSE_SIZE); if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@@ -857,7 +862,7 @@ VirtioScsiInit ( // step 6 -- initialization complete
//
NextDevStat |= VSTAT_DRIVER_OK;
- Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@@ -901,10 +906,10 @@ ReleaseQueue: Failed:
//
// Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
- // Status. PCI IO access failure here should not mask the original error.
+ // Status. VirtIo access failure here should not mask the original error. //
NextDevStat |= VSTAT_FAILED;
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); Dev->InOutSupported = FALSE;
Dev->MaxTarget = 0;
@@ -928,7 +933,7 @@ VirtioScsiUninit ( // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
// the old comms area.
//
- VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); Dev->InOutSupported = FALSE;
Dev->MaxTarget = 0;
@@ -953,11 +958,8 @@ VirtioScsiUninit ( // The implementation follows:
// - Driver Writer's Guide for UEFI 2.3.1 v1.01
// - 5.1.3.4 OpenProtocol() and CloseProtocol()
-// - 18 PCI Driver Design Guidelines
-// - 18.3 PCI drivers
// - UEFI Spec 2.3.1 + Errata C
// - 6.3 Protocol Handler Services
-// - 13.4 EFI PCI I/O Protocol
//
EFI_STATUS
@@ -968,57 +970,37 @@ VirtioScsiDriverBindingSupported ( IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
- EFI_STATUS Status;
- EFI_PCI_IO_PROTOCOL *PciIo;
- PCI_TYPE00 Pci;
+ EFI_STATUS Status; + VIRTIO_DEVICE_PROTOCOL *VirtIo; //
- // Attempt to open the device with the PciIo set of interfaces. On success,
- // the protocol is "instantiated" for the PCI device. Covers duplicate open
+ // Attempt to open the device with the VirtIo set of interfaces. On success, + // the protocol is "instantiated" for the VirtIo device. Covers duplicate open // attempts (EFI_ALREADY_STARTED).
//
Status = gBS->OpenProtocol (
DeviceHandle, // candidate device
- &gEfiPciIoProtocolGuid, // for generic PCI access
- (VOID **)&PciIo, // handle to instantiate
+ &gVirtioDeviceProtocolGuid, // for generic VirtIo access + (VOID **)&VirtIo, // 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
+ EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo 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
- //
- Status = (Pci.Hdr.VendorId == 0x1AF4 &&
- Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F &&
- Pci.Hdr.RevisionID == 0x00 &&
- Pci.Device.SubsystemID == VIRTIO_SUBSYSTEM_SCSI_HOST) ? EFI_SUCCESS : EFI_UNSUPPORTED;
+ if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_SCSI_HOST) { + Status = EFI_UNSUPPORTED; }
//
- // We needed PCI IO access only transitorily, to see whether we support the
+ // We needed VirtIo access only transitorily, to see whether we support the // device or not.
//
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle);
return Status;
}
@@ -1040,43 +1022,19 @@ VirtioScsiDriverBindingStart ( return EFI_OUT_OF_RESOURCES;
}
- Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
- (VOID **)&Dev->PciIo, This->DriverBindingHandle,
+ Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, + (VOID **)&Dev->VirtIo, This->DriverBindingHandle, DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) {
goto FreeVirtioScsi;
}
//
- // 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-scsi we only need IO space access.
- //
- Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet,
- 0, &Dev->OriginalPciAttributes);
- if (EFI_ERROR (Status)) {
- goto ClosePciIo;
- }
-
- Status = Dev->PciIo->Attributes (Dev->PciIo,
- EfiPciIoAttributeOperationEnable,
- EFI_PCI_IO_ATTRIBUTE_IO, NULL);
- if (EFI_ERROR (Status)) {
- goto ClosePciIo;
- }
-
- //
- // PCI IO access granted, configure virtio-scsi device.
+ // VirtIo access granted, configure virtio-scsi device. //
Status = VirtioScsiInit (Dev);
if (EFI_ERROR (Status)) {
- goto RestorePciAttributes;
+ goto CloseVirtIo; }
//
@@ -1096,12 +1054,8 @@ VirtioScsiDriverBindingStart ( UninitDev:
VirtioScsiUninit (Dev);
-RestorePciAttributes:
- Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
- Dev->OriginalPciAttributes, NULL);
-
-ClosePciIo:
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+CloseVirtIo: + gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle);
FreeVirtioScsi:
@@ -1149,10 +1103,7 @@ VirtioScsiDriverBindingStop ( VirtioScsiUninit (Dev);
- Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
- Dev->OriginalPciAttributes, NULL);
-
- gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle);
FreePool (Dev);
diff --git a/OvmfPkg/VirtioScsiDxe/VirtioScsi.h b/OvmfPkg/VirtioScsiDxe/VirtioScsi.h index f5220b2215..42d8ed765f 100644 --- a/OvmfPkg/VirtioScsiDxe/VirtioScsi.h +++ b/OvmfPkg/VirtioScsiDxe/VirtioScsi.h @@ -20,7 +20,6 @@ #include <Protocol/ComponentName.h>
#include <Protocol/DriverBinding.h>
-#include <Protocol/PciIo.h>
#include <Protocol/ScsiPassThruExt.h>
#include <IndustryStandard/Virtio.h>
@@ -49,18 +48,17 @@ typedef struct { // at various call depths. The table to the right should make it easier to
// track them.
//
- // field init function init depth
- // ---------------------- ------------------ ----------
- UINT32 Signature; // DriverBindingStart 0
- EFI_PCI_IO_PROTOCOL *PciIo; // DriverBindingStart 0
- UINT64 OriginalPciAttributes; // DriverBindingStart 0
- BOOLEAN InOutSupported; // VirtioScsiInit 1
- UINT16 MaxTarget; // VirtioScsiInit 1
- UINT32 MaxLun; // VirtioScsiInit 1
- UINT32 MaxSectors; // VirtioScsiInit 1
- VRING Ring; // VirtioRingInit 2
- EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru; // VirtioScsiInit 1
- EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode; // VirtioScsiInit 1
+ // field init function init depth + // ---------------- ------------------ ---------- + UINT32 Signature; // DriverBindingStart 0 + VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0 + BOOLEAN InOutSupported; // VirtioScsiInit 1 + UINT16 MaxTarget; // VirtioScsiInit 1 + UINT32 MaxLun; // VirtioScsiInit 1 + UINT32 MaxSectors; // VirtioScsiInit 1 + VRING Ring; // VirtioRingInit 2 + EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru; // VirtioScsiInit 1 + EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode; // VirtioScsiInit 1 } VSCSI_DEV;
#define VIRTIO_SCSI_FROM_PASS_THRU(PassThruPointer) \
diff --git a/OvmfPkg/VirtioScsiDxe/VirtioScsi.inf b/OvmfPkg/VirtioScsiDxe/VirtioScsi.inf index 8209c50275..e98780db8a 100644 --- a/OvmfPkg/VirtioScsiDxe/VirtioScsi.inf +++ b/OvmfPkg/VirtioScsiDxe/VirtioScsi.inf @@ -40,7 +40,7 @@ [Protocols]
gEfiExtScsiPassThruProtocolGuid ## BY_START
- gEfiPciIoProtocolGuid ## TO_START
+ gVirtioDeviceProtocolGuid ## TO_START [Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdVirtioScsiMaxTargetLimit ## CONSUMES
|