Nothing to do here for virtio 1.0 devices Signed-off-by: Jeff Brasen <jbrasen@nvidia.com> Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
		
			
				
	
	
		
			439 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			439 lines
		
	
	
		
			10 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.
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "VirtioMmioDevice.h"
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| VirtioMmioGetDeviceFeatures (
 | |
|   IN VIRTIO_DEVICE_PROTOCOL  *This,
 | |
|   OUT UINT64                 *DeviceFeatures
 | |
|   )
 | |
| {
 | |
|   VIRTIO_MMIO_DEVICE  *Device;
 | |
|   UINT32              LowBits, HighBits;
 | |
| 
 | |
|   if (DeviceFeatures == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
 | |
| 
 | |
|   if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
 | |
|     *DeviceFeatures = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_HOST_FEATURES);
 | |
|   } else {
 | |
|     VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_HOST_FEATURES_SEL, 0);
 | |
|     LowBits = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_HOST_FEATURES);
 | |
|     VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_HOST_FEATURES_SEL, 1);
 | |
|     HighBits        = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_HOST_FEATURES);
 | |
|     *DeviceFeatures = LShiftU64 (HighBits, 32) | LowBits;
 | |
|   }
 | |
| 
 | |
|   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);
 | |
| 
 | |
|   if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
 | |
|     VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM, QueueSize);
 | |
|   } else {
 | |
|     Device->QueueNum = 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);
 | |
| 
 | |
|   if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
 | |
|     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);
 | |
| 
 | |
|   if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
 | |
|     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);
 | |
| 
 | |
|   if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
 | |
|     Device->QueueNum = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX) & 0xFFFF;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| VirtioMmioSetQueueAddress (
 | |
|   IN VIRTIO_DEVICE_PROTOCOL  *This,
 | |
|   IN VRING                   *Ring,
 | |
|   IN UINT64                  RingBaseShift
 | |
|   )
 | |
| {
 | |
|   VIRTIO_MMIO_DEVICE  *Device;
 | |
|   UINT64              Address;
 | |
| 
 | |
|   ASSERT (RingBaseShift == 0);
 | |
| 
 | |
|   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
 | |
| 
 | |
|   if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_QUEUE_PFN,
 | |
|       (UINT32)((UINTN)Ring->Base >> EFI_PAGE_SHIFT)
 | |
|       );
 | |
|   } else {
 | |
|     VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM, Device->QueueNum);
 | |
| 
 | |
|     Address = (UINTN)Ring->Base;
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_QUEUE_DESC_LO,
 | |
|       (UINT32)Address
 | |
|       );
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_QUEUE_DESC_HI,
 | |
|       (UINT32)RShiftU64 (Address, 32)
 | |
|       );
 | |
| 
 | |
|     Address = (UINTN)Ring->Avail.Flags;
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_QUEUE_AVAIL_LO,
 | |
|       (UINT32)Address
 | |
|       );
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_QUEUE_AVAIL_HI,
 | |
|       (UINT32)RShiftU64 (Address, 32)
 | |
|       );
 | |
| 
 | |
|     Address = (UINTN)Ring->Used.Flags;
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_QUEUE_USED_LO,
 | |
|       (UINT32)Address
 | |
|       );
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_QUEUE_USED_HI,
 | |
|       (UINT32)RShiftU64 (Address, 32)
 | |
|       );
 | |
| 
 | |
|     VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_READY, 1);
 | |
|   }
 | |
| 
 | |
|   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 (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
 | |
|     if (Features > MAX_UINT32) {
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_GUEST_FEATURES,
 | |
|       (UINT32)Features
 | |
|       );
 | |
|   } else {
 | |
|     VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_FEATURES_SEL, 0);
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_GUEST_FEATURES,
 | |
|       (UINT32)Features
 | |
|       );
 | |
|     VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_FEATURES_SEL, 1);
 | |
|     VIRTIO_CFG_WRITE (
 | |
|       Device,
 | |
|       VIRTIO_MMIO_OFFSET_GUEST_FEATURES,
 | |
|       (UINT32)RShiftU64 (Features, 32)
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   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;
 | |
| }
 |