/** @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.
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; 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; }