Testing:

- OvmfPkg, X64:
  - VirtioNetDxe:
    - PXE boot on libvirt's virtual network
    - DataSource socket utility from AppPkg (guest to host)
  - VirtioBlkDxe: booted
    - Fedora 19
    - Windows 2012 R2
    - Windows 2008 R2 (SeaBIOS CSM build of OVMF)
  - VirtioScsiDxe: booted
    - RHEL-6

- ArmVExpress-RTSM-AEMv8Ax4-foundation, Aarch64 Foundation model:
  - VirtioBlkDxe: booted
    - Linaro OpenEmbedded 13.10 image (semihosting + virtio-blk)
    - Linaro OpenEmbedded 13.10 image (virtio-blk only)
    - Fedora 19 image (with EFI stub, virtio-blk only)

Notes:
- Kept Olivier's C-u and S-o-b in the first place everywhere.
- When I touched a patch, I added my changes below Olivier's S-o-b, and
  added my own C-u and S-o-b too.
- When I didn't touch a patch, and Jordan was explicitly OK with it (as
  in, R-b), I added his R-b.

Summary list of changes in v5 (in the order visible in the squashed diff
below; patches contain broken out v4->v5 lists):

- VirtioMmioDeviceLib.inf: drop UefiDriverEntryPoint library dependency
- VirtioFlush(): update comment block in VirtioLib.[hc]; error code is
  propagated from VirtIo->SetQueueNotify().
- typo fix in VirtioMmioInstallDevice() comment block
- add disclaimer (two instances) about the protocol being work in
  progress
- ensure / document that the VIRTIO_BLK_DEVICE_PATH structure must be
  packed
- fix whitespace damage in definition of "mVirtioBlockDevicePath"
- plug MmioDevice leak in VirtioMmioUninstallDevice()
- return EFI_INVALID_PARAMETER in VirtioMmioGetQueueAddress() if
  QueueAddress is NULL
- VirtioMmioSetQueueSize(): fix return value (it's a status code)
- VirtioMmioSetPageSize(): check against EFI_PAGE_SIZE with "if" plus
  EFI_UNSUPPORTED, rather than ASSERT()
- VirtioMmioDeviceWrite(), VirtioMmioDeviceRead(): remove redundant
  (FieldSize > 8) checks
- VirtioBlkInit(): jump to Failed label if SetPageSize() fails
- VirtioBlkInit(): fixup comment, and add error handling, near
  SetQueueNum() call
- VirtioBlkDriverBindingStart(): remove redundant (always false) check
  for a subsystem device ID different from
  VIRTIO_SUBSYSTEM_BLOCK_DEVICE; VirtioBlkDriverBindingSupported()
  handles it already
- VirtioNetGetFeatures(): update stale comment block
- VirtioNetGetFeatures(): retrieve MAC address byte for byte (open-coded
  loop)
- VirtioNetDriverBindingStart(): remove redundant (always false) check
  for a subsystem device ID different from
  VIRTIO_SUBSYSTEM_NETWORK_CARD; VirtioNetDriverBindingSupported()
  handles it already
- VirtioNetInitRing(): call SetQueueNum() and SetQueueAlign() for proper
  MMIO operation
- VirtioNetInitialize(): fix destination error label for when
  SetPageSize() fails
- VirtioPciIoRead(): restore the original requirement that FieldSize
  equal BufferSize exactly (not only divide it). The looping added in v4
  did not match the comment block, and the only place that used it in v4
  (ie. VirtioNetGetFeatures()) needs an open-coded loop anyway (will be
  done in a later part of v5).
- updated comment block on VirtioPciDeviceRead()
- return EFI_UNSUPPORTED instead of failed ASSERT() in
  VirtioPciSetPageSize()
- VirtioScsi.c: fix comment block of
  VIRTIO_CFG_WRITE()/VIRTIO_CFG_READ()
- VirtioScsiInit(): fix destination error label for when SetPageSize()
  fails
- VirtioScsiInit(): call SetQueueNum() and SetQueueAlign() for proper
  MMIO operation

Changes not visible in the squashed diff (because the end result is the
same in both v4 and v5):

- ArmPlatformPkg/ArmVExpressPkg: Added the empty 'ArmFvpDxe' platform
  UEFI driver:
  - For uniformity, add the empty driver to
    ArmVExpress-RTSM-AEMv8Ax4-foundation.* too in this patch, not just
    ArmVExpress-RTSM-AEMv8Ax4.*. V4 added the empty driver to
    ArmVExpress-RTSM-AEMv8Ax4-foundation.* not sooner than the next
    patch, fusing it with other (= virtio) functionality. Let's split
    these changes cleanly.

- ArmPlatformPkg/ArmFvpDxe: Added Virtio Block support:
  - the platform driver is added to all platform DSC and FDF files in
    the previous patch; this patch focuses on virtio only

Squashed diff between v4 and v5 (17 lines of context for readability):

> diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf 
> b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
> index 126afec..2e266a9 100644
> --- a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
> +++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
> @@ -22,22 +22,21 @@
>    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/Include/Library/VirtioLib.h 
> b/OvmfPkg/Include/Library/VirtioLib.h
> index df4fc62..36527a5 100644
> --- a/OvmfPkg/Include/Library/VirtioLib.h
> +++ b/OvmfPkg/Include/Library/VirtioLib.h
> @@ -154,32 +154,32 @@ VirtioAppendDesc (
>
>  /**
>
>    Notify the host about the descriptor chain just built, and wait until the
>    host processes it.
>
>    @param[in] VirtIo       The target virtio device to notify.
>
>    @param[in] VirtQueueId  Identifies the queue for the target device.
>
>    @param[in,out] Ring     The virtio ring with descriptors to submit.
>
>    @param[in] Indices      Indices->NextDescIdx is not accessed.
>                            Indices->HeadDescIdx identifies the head descriptor
>                            of the descriptor chain.
>
>
> -  @return              Error code from VirtioWriteDevice() if it fails.
> +  @return              Error code from VirtIo->SetQueueNotify() if it fails.
>
>    @retval EFI_SUCCESS  Otherwise, the host processed all descriptors.
>
>  **/
>  EFI_STATUS
>  EFIAPI
>  VirtioFlush (
>    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
> index ac71014..3f63a65 100644
> --- a/OvmfPkg/Include/Library/VirtioMmioDeviceLib.h
> +++ b/OvmfPkg/Include/Library/VirtioMmioDeviceLib.h
> @@ -9,40 +9,41 @@
>    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.
> +  @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
> +  @retval EFI_OUT_OF_RESOURCES  The function failed to allocate memory 
> required
>                                  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
>    );
>
>  /**
>
> diff --git a/OvmfPkg/Include/Protocol/VirtioDevice.h 
> b/OvmfPkg/Include/Protocol/VirtioDevice.h
> index 71541f8..a6bb516 100644
> --- a/OvmfPkg/Include/Protocol/VirtioDevice.h
> +++ b/OvmfPkg/Include/Protocol/VirtioDevice.h
> @@ -1,22 +1,25 @@
>  /** @file
>    Virtio Device
>
>    Copyright (c) 2013, ARM Ltd. All rights reserved.<BR>
>
> +  DISCLAIMER: the VIRTIO_DEVICE_PROTOCOL introduced here is a work in 
> progress,
> +  and should not be used outside of the EDK II tree.
> +
>    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))
>
> @@ -327,34 +330,37 @@ EFI_STATUS
>    @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
>  ///
> +///  DISCLAIMER: this protocol is a work in progress, and should not be used
> +///  outside of the EDK II tree.
> +///
>  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;
> diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.c 
> b/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.c
> index 0cf5b7b..1885b69 100644
> --- a/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.c
> +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.c
> @@ -5,56 +5,58 @@
>    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
>
> +#pragma pack(1)
>  typedef struct {
>    VENDOR_DEVICE_PATH                  Vendor;
>    EFI_DEVICE_PATH_PROTOCOL            End;
>  } VIRTIO_BLK_DEVICE_PATH;
> +#pragma pack()
>
>  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,
> diff --git a/OvmfPkg/Library/VirtioLib/VirtioLib.c 
> b/OvmfPkg/Library/VirtioLib/VirtioLib.c
> index 9bbd141..54cf225 100644
> --- a/OvmfPkg/Library/VirtioLib/VirtioLib.c
> +++ b/OvmfPkg/Library/VirtioLib/VirtioLib.c
> @@ -236,35 +236,35 @@ VirtioAppendDesc (
>
>  /**
>
>    Notify the host about the descriptor chain just built, and wait until the
>    host processes it.
>
>    @param[in] VirtIo       The target virtio device to notify.
>
>    @param[in] VirtQueueId  Identifies the queue for the target device.
>
>    @param[in,out] Ring     The virtio ring with descriptors to submit.
>
>    @param[in] Indices      Indices->NextDescIdx is not accessed.
>                            Indices->HeadDescIdx identifies the head descriptor
>                            of the descriptor chain.
>
>
> -  @return              Error code from VirtioWriteDevice() if it fails.
> +  @return              Error code from VirtIo->SetQueueNotify() if it fails.
>
>    @retval EFI_SUCCESS  Otherwise, the host processed all descriptors.
>
>  **/
>  EFI_STATUS
>  EFIAPI
>  VirtioFlush (
>    IN     VIRTIO_DEVICE_PROTOCOL *VirtIo,
>    IN     UINT16                 VirtQueueId,
>    IN OUT VRING                  *Ring,
>    IN     DESC_INDICES           *Indices
>    )
>  {
>    UINT16     NextAvailIdx;
>    EFI_STATUS Status;
>    UINTN      PollPeriodUsecs;
>
> diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c 
> b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
> index 4d8578e..7543e15 100644
> --- a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
> +++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
> @@ -185,20 +185,21 @@ VirtioMmioUninstallDevice (
>    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);
> +  FreePool (MmioDevice);
>
>    return EFI_SUCCESS;
>  }
> diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c 
> b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c
> index bcba062..068e1ed 100644
> --- a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c
> +++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c
> @@ -34,35 +34,35 @@ VirtioMmioGetDeviceFeatures (
>    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) {
> -
> +    return EFI_INVALID_PARAMETER;
>    }
>
>    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;
> @@ -95,35 +95,37 @@ VirtioMmioGetDeviceStatus (
>
>    *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);
> +  VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM, QueueSize);
> +
> +  return EFI_SUCCESS;
>  }
>
>  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;
>  }
> @@ -155,35 +157,37 @@ VirtioMmioSetQueueAlignment (
>
>    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);
> +  if (PageSize != EFI_PAGE_SIZE) {
> +    return EFI_UNSUPPORTED;
> +  }
>
>    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;
>
> @@ -226,38 +230,34 @@ VirtioMmioSetGuestFeatures (
>  }
>
>  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;
>  }
> @@ -267,38 +267,34 @@ 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/VirtioBlkDxe/VirtioBlk.c 
> b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
> index 0dcb05c..e0be7b0 100644
> --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
> +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
> @@ -608,35 +608,35 @@ VirtioBlkInit (
>    NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence
>    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 = 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;
> +    goto Failed;
>    }
>
>    //
>    // step 4a -- retrieve and validate features
>    //
>    Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
>    if (EFI_ERROR (Status)) {
>      goto Failed;
>    }
>
>    Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
>    if (EFI_ERROR (Status)) {
>      goto Failed;
>    }
>    if (NumSectors == 0) {
>      Status = EFI_UNSUPPORTED;
>      goto Failed;
> @@ -669,44 +669,49 @@ VirtioBlkInit (
>      goto Failed;
>    }
>    Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
>    if (EFI_ERROR (Status)) {
>      goto Failed;
>    }
>    if (QueueSize < 3) { // SynchronousRequest() uses at most three descriptors
>      Status = EFI_UNSUPPORTED;
>      goto Failed;
>    }
>
>    Status = VirtioRingInit (QueueSize, &Dev->Ring);
>    if (EFI_ERROR (Status)) {
>      goto Failed;
>    }
>
>    //
> -  // Additional steps for MMIO: align the queue appropriately, and set the 
> size
> -  Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
> +  // Additional steps for MMIO: align the queue appropriately, and set the
> +  // size. If anything fails from here on, we must release the ring 
> resources.
> +  //
> +  Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
> +  if (EFI_ERROR (Status)) {
> +    goto ReleaseQueue;
> +  }
> +
>    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.
> +  // step 4c -- Report GPFN (guest-physical frame number) of queue.
>    //
>    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 = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, 0);
>    if (EFI_ERROR (Status)) {
>      goto ReleaseQueue;
> @@ -827,38 +832,34 @@ VirtioBlkDriverBindingStart (
>    )
>  {
>    VBLK_DEV   *Dev;
>    EFI_STATUS Status;
>
>    Dev = (VBLK_DEV *) AllocateZeroPool (sizeof *Dev);
>    if (Dev == NULL) {
>      return EFI_OUT_OF_RESOURCES;
>    }
>
>    Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
>                    (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
>                    DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
>    if (EFI_ERROR (Status)) {
>      goto FreeVirtioBlk;
>    }
>
> -  if (Dev->VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {
> -    return EFI_UNSUPPORTED;
> -  }
> -
>    //
>    // VirtIo access granted, configure virtio-blk device.
>    //
>    Status = VirtioBlkInit (Dev);
>    if (EFI_ERROR (Status)) {
>      goto CloseVirtIo;
>    }
>
>    //
>    // Setup complete, attempt to export the driver instance's BlockIo 
> interface.
>    //
>    Dev->Signature = VBLK_SIG;
>    Status = gBS->InstallProtocolInterface (&DeviceHandle,
>                    &gEfiBlockIoProtocolGuid, EFI_NATIVE_INTERFACE,
>                    &Dev->BlockIo);
>    if (EFI_ERROR (Status)) {
>      goto UninitDev;
> diff --git a/OvmfPkg/VirtioNetDxe/DriverBinding.c 
> b/OvmfPkg/VirtioNetDxe/DriverBinding.c
> index 330f1f3..93995c6 100644
> --- a/OvmfPkg/VirtioNetDxe/DriverBinding.c
> +++ b/OvmfPkg/VirtioNetDxe/DriverBinding.c
> @@ -35,51 +35,51 @@
>
>    Only VirtioNetSnpPopulate() may call this function.
>
>    If the function fails for any reason, the virtio-net device is moved to
>    VSTAT_FAILED instead of being reset. This serves only informative purposes
>    for the host side.
>
>    param[in,out] Dev                 The VNET_DEV structure being created for
>                                      the virtio-net device.
>    param[out] MacAddress             MAC address configured by the host.
>    param[out] MediaPresentSupported  Link status is made available by the 
> host.
>    param[out] MediaPresent           If link status is made available by the
>                                      host, the current link status is stored 
> in
>                                      *MediaPresent. Otherwise MediaPresent is
>                                      unused.
>
>    @retval EFI_UNSUPPORTED           The host doesn't supply a MAC address.
> -  @return                           Status codes from Dev->VirtIo->Io.Read(),
> -                                    VIRTIO_CFG_READ() and VIRTIO_CFG_WRITE().
> +  @return                           Status codes from VirtIo protocol 
> members.
>    @retval EFI_SUCCESS               Configuration values retrieved.
>  */
>  STATIC
>  EFI_STATUS
>  EFIAPI
>  VirtioNetGetFeatures (
>    IN OUT  VNET_DEV        *Dev,
>    OUT     EFI_MAC_ADDRESS *MacAddress,
>    OUT     BOOLEAN         *MediaPresentSupported,
>    OUT     BOOLEAN         *MediaPresent
>    )
>  {
>    EFI_STATUS Status;
>    UINT8      NextDevStat;
>    UINT32     Features;
> +  UINTN      MacIdx;
>    UINT16     LinkStatus;
>
>    //
>    // Interrogate the device for features (virtio-0.9.5, 2.2.1 Device
>    // Initialization Sequence), but don't complete setting it up.
>    //
>    NextDevStat = 0;             // step 1 -- reset device
>    Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
>
>    NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence
>    Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
>    if (EFI_ERROR (Status)) {
>      goto YieldDevice;
>    }
> @@ -91,43 +91,44 @@ VirtioNetGetFeatures (
>    }
>
>    //
>    // step 4a -- retrieve and validate features
>    //
>    Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
>    if (EFI_ERROR (Status)) {
>      goto YieldDevice;
>    }
>
>    //
>    // get MAC address byte-wise
>    //
>    if ((Features & VIRTIO_NET_F_MAC) == 0) {
>      Status = EFI_UNSUPPORTED;
>      goto YieldDevice;
>    }
> -  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;
> +  for (MacIdx = 0; MacIdx < SIZE_OF_VNET (Mac); ++MacIdx) {
> +    Status = Dev->VirtIo->ReadDevice (Dev->VirtIo,
> +                            OFFSET_OF_VNET (Mac) + MacIdx, // Offset
> +                            1,                             // FieldSize
> +                            1,                             // BufferSize
> +                            &MacAddress->Addr[MacIdx]      // Buffer
> +                            );
> +    if (EFI_ERROR (Status)) {
> +      goto YieldDevice;
> +    }
>    }
>
>    //
>    // check if link status is reported, and if so, what the link status is
>    //
>    if ((Features & VIRTIO_NET_F_STATUS) == 0) {
>      *MediaPresentSupported = FALSE;
>    }
>    else {
>      *MediaPresentSupported = TRUE;
>      Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus);
>      if (EFI_ERROR (Status)) {
>        goto YieldDevice;
>      }
>      *MediaPresent = !!(LinkStatus & VIRTIO_NET_S_LINK_UP);
>    }
>
> @@ -445,38 +446,34 @@ VirtioNetDriverBindingStart (
>
>    //
>    // allocate space for the driver instance
>    //
>    Dev = (VNET_DEV *) AllocateZeroPool (sizeof *Dev);
>    if (Dev == NULL) {
>      return EFI_OUT_OF_RESOURCES;
>    }
>    Dev->Signature = VNET_SIG;
>
>    Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
>                    (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
>                    DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
>    if (EFI_ERROR (Status)) {
>      goto FreeVirtioNet;
>    }
>
> -  if (Dev->VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_NETWORK_CARD) {
> -    return EFI_UNSUPPORTED;
> -  }
> -
>    //
>    // now we can run a basic one-shot virtio-net initialization required to
>    // retrieve the MAC address
>    //
>    Status = VirtioNetSnpPopulate (Dev);
>    if (EFI_ERROR (Status)) {
>      goto CloseVirtIo;
>    }
>
>    //
>    // get the device path of the virtio-net device -- one-shot open
>    //
>    Status = gBS->OpenProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid,
>                    (VOID **)&DevicePath, This->DriverBindingHandle,
>                    DeviceHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
>    if (EFI_ERROR (Status)) {
>      goto Evacuate;
> diff --git a/OvmfPkg/VirtioNetDxe/SnpInitialize.c 
> b/OvmfPkg/VirtioNetDxe/SnpInitialize.c
> index 56a55db..8dcf9da 100644
> --- a/OvmfPkg/VirtioNetDxe/SnpInitialize.c
> +++ b/OvmfPkg/VirtioNetDxe/SnpInitialize.c
> @@ -65,41 +65,61 @@ VirtioNetInitRing (
>    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
>    //
>    if (QueueSize < 2) {
>      return EFI_UNSUPPORTED;
>    }
>    Status = VirtioRingInit (QueueSize, Ring);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
>
>    //
> +  // Additional steps for MMIO: align the queue appropriately, and set the
> +  // size. If anything fails from here on, we must release the ring 
> resources.
> +  //
> +  Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
> +  if (EFI_ERROR (Status)) {
> +    goto ReleaseQueue;
> +  }
> +
> +  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
>    //
>    Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,
>        (UINTN) Ring->Base >> EFI_PAGE_SHIFT);
>    if (EFI_ERROR (Status)) {
> -    VirtioRingUninit (Ring);
> +    goto ReleaseQueue;
>    }
> +
> +  return EFI_SUCCESS;
> +
> +ReleaseQueue:
> +  VirtioRingUninit (Ring);
> +
>    return Status;
>  }
>
>
>  /**
>    Set up static scaffolding for the VirtioNetTransmit() and
>    VirtioNetGetStatus() SNP methods.
>
>    This function may only be called by VirtioNetInitialize().
>
>    The structures laid out and resources configured include:
>    - fully populate the TX queue with a static pattern of virtio descriptor
>      chains,
>    - tracking of heads of free descriptor chains from the above,
>    - one common virtio-net request header (never modified by the host) for all
>      pending TX packets,
>    - select polling over TX interrupt.
> @@ -368,35 +388,35 @@ VirtioNetInitialize (
>    NextDevStat = VSTAT_ACK;    // step 2 -- acknowledge device presence
>    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 = 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;
> +    goto DeviceFailed;
>    }
>
>    //
>    // step 4a -- retrieve features. Note that we're past validating required
>    // features in VirtioNetGetFeatures().
>    //
>    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));
>
>    //
>    // step 4b, 4c -- allocate and report virtqueues
> diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c 
> b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c
> index c513622..c03a273 100644
> --- a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c
> +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c
> @@ -66,59 +66,60 @@ STATIC VIRTIO_DEVICE_PROTOCOL mDeviceProtocolTemplate = {
>    @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);
> +  ASSERT (FieldSize == BufferSize);
>
>    PciIo = Dev->PciIo;
> -  Count = BufferSize / FieldSize;
> +  Count = 1;
>
>    switch (FieldSize) {
>      case 1:
>        Width = EfiPciIoWidthUint8;
>        break;
>
>      case 2:
>        Width = EfiPciIoWidthUint16;
>        break;
>
>      case 8:
> +      //
>        // The 64bit PCI I/O is broken down into two 32bit reads to prevent
>        // any alignment or width issues.
>        // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():
>        //
>        // The I/O operations are carried out exactly as requested. The caller
>        // is responsible for any alignment and I/O width issues which the
>        // bus, device, platform, or type of I/O might require. For example on
> -      // some platforms, width requests of EfiPciIoWidthUint64 do not work
> -      Count = Count * 2;
> +      // some platforms, width requests of EfiPciIoWidthUint64 do not work.
> +      //
> +      Count = 2;
>        // fall through
>
>      case 4:
>        Width = EfiPciIoWidthUint32;
>        break;
>
>      default:
>        ASSERT (FALSE);
>        return EFI_INVALID_PARAMETER;
>    }
>
>    return PciIo->Io.Read (
>                       PciIo,
>                       Width,
>                       PCI_BAR_IDX0,
>                       FieldOffset,
>                       Count,
> diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c 
> b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c
> index 586bec6..9c40fd9 100644
> --- a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c
> +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c
> @@ -10,40 +10,40 @@
>    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.
> +  Read a word from Region 0 of the device specified by VirtIo Device 
> protocol.
>
>    The function implements the ReadDevice protocol member of
>    VIRTIO_DEVICE_PROTOCOL.
>
> -  @param[in] PciIo        Source PCI device.
> +  @param[in] This         VirtIo Device protocol.
>
>    @param[in] FieldOffset  Source offset.
>
>    @param[in] FieldSize    Source field size, must be in { 1, 2, 4, 8 }.
>
>    @param[in] BufferSize   Number of bytes available in the target buffer. 
> Must
>                            equal FieldSize.
>
>    @param[out] Buffer      Target buffer.
>
>
>    @return  Status code returned by PciIo->Io.Read().
>
>  **/
>  EFI_STATUS
>  EFIAPI
>  VirtioPciDeviceRead (
> @@ -221,37 +221,35 @@ VirtioPciSetQueueSel (
>  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;
> +  return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
>  }
>
>  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);
>  }
>
> diff --git a/OvmfPkg/VirtioScsiDxe/VirtioScsi.c 
> b/OvmfPkg/VirtioScsiDxe/VirtioScsi.c
> index 9702985..267f5f9 100644
> --- a/OvmfPkg/VirtioScsiDxe/VirtioScsi.c
> +++ b/OvmfPkg/VirtioScsiDxe/VirtioScsi.c
> @@ -36,42 +36,42 @@
>    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/VirtioScsi.h>
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/DebugLib.h>
>  #include <Library/MemoryAllocationLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiLib.h>
>  #include <Library/VirtioLib.h>
>
>  #include "VirtioScsi.h"
>
>  /**
>
> -  Convenience macros to read and write region 0 IO space elements of the
> -  virtio-scsi VirtIo device, for configuration purposes.
> +  Convenience macros to read and write configuration elements of the
> +  virtio-scsi VirtIo device.
>
>    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 VirtIo Device Protocol
> +  @param[in] Dev       Pointer to the VSCSI_DEV structure.
>
>    @param[in] Field     A field name from VSCSI_HDR, identifying the 
> virtio-scsi
>                         configuration item to access.
>
>    @param[in] Value     (VIRTIO_CFG_WRITE() only.) The value to write to the
>                         selected configuration item.
>
>    @param[out] Pointer  (VIRTIO_CFG_READ() only.) The object to receive the
>                         value read from the configuration item. Its type must 
> be
>                         one of UINT8, UINT16, UINT32, UINT64.
>
>
>    @return  Status codes returned by Virtio->WriteDevice() / 
> Virtio->ReadDevice().
>
>  **/
>
>  #define VIRTIO_CFG_WRITE(Dev, Field, Value)  ((Dev)->VirtIo->WriteDevice (  \
> @@ -724,35 +724,35 @@ VirtioScsiInit (
>    NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence
>    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 = 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;
> +    goto Failed;
>    }
>
>    //
>    // step 4a -- retrieve and validate 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, MaxChannel, &MaxChannel);
>    if (EFI_ERROR (Status)) {
>      goto Failed;
>    }
>    if (MaxChannel != 0) {
>      //
> @@ -811,36 +811,49 @@ VirtioScsiInit (
>    if (EFI_ERROR (Status)) {
>      goto Failed;
>    }
>    //
>    // VirtioScsiPassThru() uses at most four descriptors
>    //
>    if (QueueSize < 4) {
>      Status = EFI_UNSUPPORTED;
>      goto Failed;
>    }
>
>    Status = VirtioRingInit (QueueSize, &Dev->Ring);
>    if (EFI_ERROR (Status)) {
>      goto Failed;
>    }
>
>    //
> -  // step 4c -- Report GPFN (guest-physical frame number) of queue. If 
> anything
> -  // fails from here on, we must release the ring resources.
> +  // Additional steps for MMIO: align the queue appropriately, and set the
> +  // size. If anything fails from here on, we must release the ring 
> resources.
> +  //
> +  Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
> +  if (EFI_ERROR (Status)) {
> +    goto ReleaseQueue;
> +  }
> +
> +  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.
>    //
>    Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,
>        (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);
>    if (EFI_ERROR (Status)) {
>      goto ReleaseQueue;
>    }
>
>    //
>    // step 5 -- Report understood features and guest-tuneables. We want none 
> of
>    // the known (or unknown) VIRTIO_SCSI_F_* or VIRTIO_F_* capabilities (see
>    // virtio-0.9.5, Appendices B and I), except bidirectional transfers.
>    //
>    Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo,
>        Features & VIRTIO_SCSI_F_INOUT);
>    if (EFI_ERROR (Status)) {
>      goto ReleaseQueue;
>    }

Olivier Martin (8):
  OvmfPkg/VirtioDevice.h: Introduced VIRTIO_DEVICE_PROTOCOL protocol
  OvmfPkg/VirtioPciDeviceDxe: Implement VIRTIO_DEVICE_PROTOCOL for
    VirtIo Devices over PCI
  OvmfPkg/VirtioMmioDeviceLib: Implement VIRTIO_DEVICE_PROTOCOL for
    VirtIo Devices over MMIO
  OvmfPkg: Make the VirtIo devices use the new VIRTIO_DEVICE_PROTOCOL
  OvmfPkg/Virtio.h: Removed definition of VIRTIO_HDR
  ArmPlatformPkg/ArmVExpressPkg: Added the empty 'ArmFvpDxe' platform
    UEFI driver
  ArmPlatformPkg/ArmFvpDxe: Added Virtio Block support
  OvmfPkg/Virtio: Removed VirtioReadDevice() / VirtIoWriteDevice()
    functions

 .../ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.inf         |  35 ++
 .../VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf    |  42 ++
 OvmfPkg/VirtioBlkDxe/VirtioBlk.inf                 |   4 +-
 OvmfPkg/VirtioNetDxe/VirtioNet.inf                 |   2 +-
 OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf  |  43 ++
 OvmfPkg/VirtioScsiDxe/VirtioScsi.inf               |   2 +-
 OvmfPkg/Include/IndustryStandard/Virtio.h          |  18 -
 OvmfPkg/Include/IndustryStandard/VirtioBlk.h       |  21 +-
 OvmfPkg/Include/IndustryStandard/VirtioNet.h       |  14 +-
 OvmfPkg/Include/IndustryStandard/VirtioScsi.h      |  27 +-
 OvmfPkg/Include/Library/VirtioLib.h                |  77 +--
 OvmfPkg/Include/Library/VirtioMmioDeviceLib.h      |  66 ++
 OvmfPkg/Include/Protocol/VirtioDevice.h            | 382 ++++++++++++
 .../Library/VirtioMmioDeviceLib/VirtioMmioDevice.h | 147 +++++
 OvmfPkg/VirtioBlkDxe/VirtioBlk.h                   |  32 +-
 OvmfPkg/VirtioNetDxe/VirtioNet.h                   |  26 +-
 OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h       | 166 +++++
 OvmfPkg/VirtioScsiDxe/VirtioScsi.h                 |  24 +-
 .../ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.c           |  75 +++
 OvmfPkg/Library/VirtioLib/VirtioLib.c              | 158 +----
 .../Library/VirtioMmioDeviceLib/VirtioMmioDevice.c | 205 +++++++
 .../VirtioMmioDeviceFunctions.c                    | 300 +++++++++
 OvmfPkg/VirtioBlkDxe/VirtioBlk.c                   | 194 +++---
 OvmfPkg/VirtioNetDxe/ComponentName.c               |   6 +-
 OvmfPkg/VirtioNetDxe/DriverBinding.c               | 137 ++---
 OvmfPkg/VirtioNetDxe/Events.c                      |   2 +-
 OvmfPkg/VirtioNetDxe/SnpGetStatus.c                |   2 +-
 OvmfPkg/VirtioNetDxe/SnpInitialize.c               |  59 +-
 OvmfPkg/VirtioNetDxe/SnpReceive.c                  |  12 +-
 OvmfPkg/VirtioNetDxe/SnpShutdown.c                 |   2 +-
 OvmfPkg/VirtioNetDxe/SnpTransmit.c                 |  12 +-
 OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c       | 668 +++++++++++++++++++++
 OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c    | 283 +++++++++
 OvmfPkg/VirtioScsiDxe/VirtioScsi.c                 | 192 +++---
 .../ArmVExpress-RTSM-AEMv8Ax4-foundation.dsc       |  10 +
 .../ArmVExpress-RTSM-AEMv8Ax4-foundation.fdf       |   6 +
 .../ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.dsc   |  10 +
 .../ArmVExpressPkg/ArmVExpress-RTSM-AEMv8Ax4.fdf   |   8 +-
 OvmfPkg/OvmfPkg.dec                                |   1 +
 OvmfPkg/OvmfPkgIa32.dsc                            |   1 +
 OvmfPkg/OvmfPkgIa32.fdf                            |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                         |   1 +
 OvmfPkg/OvmfPkgIa32X64.fdf                         |   1 +
 OvmfPkg/OvmfPkgX64.dsc                             |   1 +
 OvmfPkg/OvmfPkgX64.fdf                             |   1 +
 45 files changed, 2813 insertions(+), 663 deletions(-)
 create mode 100644 ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.inf
 create mode 100644 OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
 create mode 100644 OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
 create mode 100644 OvmfPkg/Include/Library/VirtioMmioDeviceLib.h
 create mode 100644 OvmfPkg/Include/Protocol/VirtioDevice.h
 create mode 100644 OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.h
 create mode 100644 OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h
 create mode 100644 ArmPlatformPkg/ArmVExpressPkg/ArmFvpDxe/ArmFvpDxe.c
 create mode 100644 OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
 create mode 100644 
OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c
 create mode 100644 OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c
 create mode 100644 OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c

-- 
1.8.3.1


------------------------------------------------------------------------------
Rapidly troubleshoot problems before they affect your business. Most IT 
organizations don't have a clear picture of how application performance 
affects their revenue. With AppDynamics, you get 100% visibility into your 
Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
http://pubads.g.doubleclick.net/gampad/clk?id=84349351&iu=/4140/ostg.clktrk
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to