From: Olivier Martin <olivier.mar...@arm.com>

Why is the virtio-mmio implementation of the protocol a library,
instead of a driver binary?
The UEFI driver model would encourage to create a virtio-mmio driver
instead of a library. But the reasons why I created a library are:

- A virtio-mmio driver would imply an additional protocol that would
probably have a single attribute field:

typedef struct {
  PHYSICAL_ADDRESS       BaseAddress;
} VIRTIO_MMIO_DEVICE_PROTOCOL;

- There is no (easy) way to scan the available VirtIo devices on a
platform. So, the UEFI firmware for this platform would need a driver
to produce instances for every virtio devices it wants to expose in
UEFI. A single call to a helper library (ie: VirtioMmioDeviceLib)
make the porting easier.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Olivier Martin <olivier.mar...@arm.com>

v5:
- typo fix in VirtioMmioInstallDevice() comment block
- 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
- VirtioMmioDeviceLib.inf: drop UefiDriverEntryPoint library dependency

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <ler...@redhat.com>
---
 .../VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf    |  42 +++
 OvmfPkg/Include/Library/VirtioMmioDeviceLib.h      |  66 +++++
 .../Library/VirtioMmioDeviceLib/VirtioMmioDevice.h | 147 ++++++++++
 .../Library/VirtioMmioDeviceLib/VirtioMmioDevice.c | 205 ++++++++++++++
 .../VirtioMmioDeviceFunctions.c                    | 300 +++++++++++++++++++++
 5 files changed, 760 insertions(+)
 create mode 100644 OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
 create mode 100644 OvmfPkg/Include/Library/VirtioMmioDeviceLib.h
 create mode 100644 OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.h
 create mode 100644 OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
 create mode 100644 
OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c

diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf 
b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
new file mode 100644
index 0000000..2e266a9
--- /dev/null
+++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
@@ -0,0 +1,42 @@
+## @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
+  UefiLib
+
+[Protocols]
+  gVirtioDeviceProtocolGuid            ## PRODUCES
diff --git a/OvmfPkg/Include/Library/VirtioMmioDeviceLib.h 
b/OvmfPkg/Include/Library/VirtioMmioDeviceLib.h
new file mode 100644
index 0000000..3f63a65
--- /dev/null
+++ b/OvmfPkg/Include/Library/VirtioMmioDeviceLib.h
@@ -0,0 +1,66 @@
+/** @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 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
+  );
+
+/**
+
+  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/Library/VirtioMmioDeviceLib/VirtioMmioDevice.h 
b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.h
new file mode 100644
index 0000000..3e4e560
--- /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/VirtioMmioDevice.c 
b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
new file mode 100644
index 0000000..7543e15
--- /dev/null
+++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
@@ -0,0 +1,205 @@
+/** @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);
+  FreePool (MmioDevice);
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c 
b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c
new file mode 100644
index 0000000..068e1ed
--- /dev/null
+++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c
@@ -0,0 +1,300 @@
+/** @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) {
+    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;
+
+  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);
+
+  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;
+}
+
+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;
+
+  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;
+
+  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 != 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 != 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;
+}
-- 
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