blob: de2c5fa2a63d54fc6221ef7bb95e9c65e38584b1 [file] [log] [blame]
/** @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;
}