mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-29 12:35:53 +01:00
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;
|
|
}
|