For the case when an IOMMU is used for translating system physical addresses to DMA bus master addresses, the transport-independent virtio device drivers will be required to map their VRING areas to bus addresses with VIRTIO_DEVICE_PROTOCOL.MapSharedBuffer() calls. - MMIO and legacy virtio transport do not support IOMMU to translate the addresses hence RingBaseShift will always be set to zero. - modern virtio transport supports IOMMU to translate the address, in next patch we will update the Virtio10Dxe to use RingBaseShift offset. Suggested-by: Laszlo Ersek <lersek@redhat.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Laszlo Ersek <lersek@redhat.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> [lersek@redhat.com: remove commit msg paragraph with VirtioLib reference] [lersek@redhat.com: fix typo in VIRTIO_SET_QUEUE_ADDRESS comment block] Reviewed-by: Laszlo Ersek <lersek@redhat.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
		
			
				
	
	
		
			356 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			356 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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 UINT64                *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
 | 
						|
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 (
 | 
						|
  IN VIRTIO_DEVICE_PROTOCOL *This,
 | 
						|
  IN 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 (
 | 
						|
  IN VIRTIO_DEVICE_PROTOCOL *This,
 | 
						|
  IN 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 (
 | 
						|
  IN VIRTIO_DEVICE_PROTOCOL *This,
 | 
						|
  IN 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 (
 | 
						|
  IN VIRTIO_DEVICE_PROTOCOL *This,
 | 
						|
  IN 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 (
 | 
						|
  IN VIRTIO_DEVICE_PROTOCOL *This,
 | 
						|
  IN 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 (
 | 
						|
  IN VIRTIO_DEVICE_PROTOCOL *This,
 | 
						|
  IN 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 (
 | 
						|
  IN VIRTIO_DEVICE_PROTOCOL  *This,
 | 
						|
  IN VRING                   *Ring,
 | 
						|
  IN UINT64                  RingBaseShift
 | 
						|
  )
 | 
						|
{
 | 
						|
  VIRTIO_MMIO_DEVICE *Device;
 | 
						|
 | 
						|
  ASSERT (RingBaseShift == 0);
 | 
						|
 | 
						|
  Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
 | 
						|
 | 
						|
  VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_PFN,
 | 
						|
    (UINT32)((UINTN)Ring->Base >> EFI_PAGE_SHIFT));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
VirtioMmioSetGuestFeatures (
 | 
						|
  IN VIRTIO_DEVICE_PROTOCOL *This,
 | 
						|
  IN UINT64                  Features
 | 
						|
  )
 | 
						|
{
 | 
						|
  VIRTIO_MMIO_DEVICE *Device;
 | 
						|
 | 
						|
  Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
 | 
						|
 | 
						|
  if (Features > MAX_UINT32) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
  VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_FEATURES,
 | 
						|
    (UINT32)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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
VirtioMmioAllocateSharedPages (
 | 
						|
  IN  VIRTIO_DEVICE_PROTOCOL  *This,
 | 
						|
  IN  UINTN                   NumPages,
 | 
						|
  OUT VOID                    **HostAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID        *Buffer;
 | 
						|
 | 
						|
  Buffer = AllocatePages (NumPages);
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  *HostAddress = Buffer;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
VirtioMmioFreeSharedPages (
 | 
						|
  IN  VIRTIO_DEVICE_PROTOCOL  *This,
 | 
						|
  IN  UINTN                   NumPages,
 | 
						|
  IN  VOID                    *HostAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  FreePages (HostAddress, NumPages);
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
VirtioMmioMapSharedBuffer (
 | 
						|
  IN      VIRTIO_DEVICE_PROTOCOL  *This,
 | 
						|
  IN      VIRTIO_MAP_OPERATION    Operation,
 | 
						|
  IN      VOID                    *HostAddress,
 | 
						|
  IN OUT  UINTN                   *NumberOfBytes,
 | 
						|
  OUT     EFI_PHYSICAL_ADDRESS    *DeviceAddress,
 | 
						|
  OUT     VOID                    **Mapping
 | 
						|
  )
 | 
						|
{
 | 
						|
  *DeviceAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
 | 
						|
  *Mapping = NULL;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
VirtioMmioUnmapSharedBuffer (
 | 
						|
  IN VIRTIO_DEVICE_PROTOCOL    *This,
 | 
						|
  IN VOID                      *Mapping
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |