diff options
Diffstat (limited to 'src/VBox/Devices/VirtIO/Virtio.h')
-rw-r--r-- | src/VBox/Devices/VirtIO/Virtio.h | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/src/VBox/Devices/VirtIO/Virtio.h b/src/VBox/Devices/VirtIO/Virtio.h new file mode 100644 index 00000000..492f5944 --- /dev/null +++ b/src/VBox/Devices/VirtIO/Virtio.h @@ -0,0 +1,364 @@ +/* $Id: Virtio.h $ */ +/** @file + * Virtio.h - Virtio Declarations + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#ifndef VBOX_INCLUDED_SRC_VirtIO_Virtio_h +#define VBOX_INCLUDED_SRC_VirtIO_Virtio_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + + +/** Pointer to the core shared state of a VirtIO PCI device */ +typedef struct VPCISTATE *PVPCISTATE; +/** Pointer to the core ring-3 state of a VirtIO PCI device */ +typedef struct VPCISTATER3 *PVPCISTATER3; +/** Pointer to the core ring-0 state of a VirtIO PCI device */ +typedef struct VPCISTATER0 *PVPCISTATER0; +/** Pointer to the core raw-mode state of a VirtIO PCI device */ +typedef struct VPCISTATERC *PVPCISTATERC; + +/** Pointer to the core current context state of a VirtIO PCI device */ +typedef CTX_SUFF(PVPCISTATE) PVPCISTATECC; +/** The core current context state of a VirtIO PCI device */ +typedef struct CTX_SUFF(VPCISTATE) VPCISTATECC; + + +/** @name Saved state versions. + * The saved state version is changed if either common or any of specific + * parts are changed. That is, it is perfectly possible that the version + * of saved vnet state will increase as a result of change in vblk structure + * for example. + */ +#define VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1 1 +#define VIRTIO_SAVEDSTATE_VERSION 2 +/** @} */ + +#define DEVICE_PCI_VENDOR_ID 0x1AF4 +#define DEVICE_PCI_BASE_ID 0x1000 +#define DEVICE_PCI_SUBSYSTEM_VENDOR_ID 0x1AF4 +#define DEVICE_PCI_SUBSYSTEM_BASE_ID 1 + +#define VIRTIO_MAX_NQUEUES 3 + +#define VPCI_HOST_FEATURES 0x0 +#define VPCI_GUEST_FEATURES 0x4 +#define VPCI_QUEUE_PFN 0x8 +#define VPCI_QUEUE_NUM 0xC +#define VPCI_QUEUE_SEL 0xE +#define VPCI_QUEUE_NOTIFY 0x10 +#define VPCI_STATUS 0x12 +#define VPCI_ISR 0x13 +#define VPCI_CONFIG 0x14 + +#define VPCI_ISR_QUEUE 0x1 +#define VPCI_ISR_CONFIG 0x3 + +#define VPCI_STATUS_ACK 0x01 +#define VPCI_STATUS_DRV 0x02 +#define VPCI_STATUS_DRV_OK 0x04 +#define VPCI_STATUS_FAILED 0x80 + +#define VPCI_F_NOTIFY_ON_EMPTY UINT32_C(0x01000000) +#define VPCI_F_ANY_LAYOUT UINT32_C(0x08000000) +#define VPCI_F_RING_INDIRECT_DESC UINT32_C(0x10000000) +#define VPCI_F_RING_EVENT_IDX UINT32_C(0x20000000) +#define VPCI_F_BAD_FEATURE UINT32_C(0x40000000) + +#define VRINGDESC_MAX_SIZE (2 * 1024 * 1024) +#define VRINGDESC_F_NEXT 0x01 +#define VRINGDESC_F_WRITE 0x02 +#define VRINGDESC_F_INDIRECT 0x04 + +typedef struct VRINGDESC +{ + uint64_t u64Addr; + uint32_t uLen; + uint16_t u16Flags; + uint16_t u16Next; +} VRINGDESC; +typedef VRINGDESC *PVRINGDESC; + +#define VRINGAVAIL_F_NO_INTERRUPT 0x01 + +typedef struct VRINGAVAIL +{ + uint16_t uFlags; + uint16_t uNextFreeIndex; + uint16_t auRing[1]; +} VRINGAVAIL; + +typedef struct VRINGUSEDELEM +{ + uint32_t uId; + uint32_t uLen; +} VRINGUSEDELEM; + +#define VRINGUSED_F_NO_NOTIFY 0x01 + +typedef struct VRingUsed +{ + uint16_t uFlags; + uint16_t uIndex; + VRINGUSEDELEM aRing[1]; +} VRINGUSED; +typedef VRINGUSED *PVRINGUSED; + +#define VRING_MAX_SIZE 1024 + +typedef struct VRING +{ + uint16_t uSize; + uint16_t padding[3]; + RTGCPHYS addrDescriptors; + RTGCPHYS addrAvail; + RTGCPHYS addrUsed; +} VRING; +typedef VRING *PVRING; + +typedef struct VQUEUE +{ + VRING VRing; + uint16_t uNextAvailIndex; + uint16_t uNextUsedIndex; + uint32_t uPageNumber; + char szName[16]; +} VQUEUE; +typedef VQUEUE *PVQUEUE; + +/** + * Queue callback (consumer?). + * + * @param pDevIns The device instance. + * @param pQueue Pointer to the queue structure. + */ +typedef DECLCALLBACKTYPE(void, FNVPCIQUEUECALLBACK,(PPDMDEVINS pDevIns, PVQUEUE pQueue)); +/** Pointer to a VQUEUE callback function. */ +typedef FNVPCIQUEUECALLBACK *PFNVPCIQUEUECALLBACK; + +typedef struct VQUEUER3 +{ + R3PTRTYPE(PFNVPCIQUEUECALLBACK) pfnCallback; +} VQUEUER3; +typedef VQUEUER3 *PVQUEUER3; + +typedef struct VQUEUESEG +{ + RTGCPHYS addr; + void *pv; + uint32_t cb; +} VQUEUESEG; + +typedef struct VQUEUEELEM +{ + uint32_t uIndex; + uint32_t cIn; + uint32_t cOut; + VQUEUESEG aSegsIn[VRING_MAX_SIZE]; + VQUEUESEG aSegsOut[VRING_MAX_SIZE]; +} VQUEUEELEM; +typedef VQUEUEELEM *PVQUEUEELEM; + + +enum VirtioDeviceType +{ + VIRTIO_NET_ID = 0, + VIRTIO_BLK_ID = 1, + VIRTIO_32BIT_HACK = 0x7fffffff +}; + + +/** + * The core shared state of a VirtIO PCI device + */ +typedef struct VPCISTATE +{ + PDMCRITSECT cs; /**< Critical section - what is it protecting? */ + /** Read-only part, never changes after initialization. */ + char szInstance[8]; /**< Instance name, e.g. VNet#1. */ + + /* Read/write part, protected with critical section. */ + /** Status LED. */ + PDMLED led; + + uint32_t uGuestFeatures; + uint16_t uQueueSelector; /**< An index in aQueues array. */ + uint8_t uStatus; /**< Device Status (bits are device-specific). */ + uint8_t uISR; /**< Interrupt Status Register. */ + + /** Number of queues actually used. */ + uint32_t cQueues; + uint32_t u32Padding; + /** Shared queue data. */ + VQUEUE Queues[VIRTIO_MAX_NQUEUES]; + + STAMCOUNTER StatIntsRaised; + STAMCOUNTER StatIntsSkipped; + +#ifdef VBOX_WITH_STATISTICS + STAMPROFILEADV StatIOReadR3; + STAMPROFILEADV StatIOReadR0; + STAMPROFILEADV StatIOReadRC; + STAMPROFILEADV StatIOWriteR3; + STAMPROFILEADV StatIOWriteR0; + STAMPROFILEADV StatIOWriteRC; +#endif +} VPCISTATE; + + +/** + * The core ring-3 state of a VirtIO PCI device + * + * @implements PDMILEDPORTS + */ +typedef struct VPCISTATER3 +{ + /** Status LUN: Base interface. */ + PDMIBASE IBase; + /** Status LUN: LED port interface. */ + PDMILEDPORTS ILeds; + /** Status LUN: LED connector (peer). */ + R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector; + /** Pointer to the shared state. */ + R3PTRTYPE(PVPCISTATE) pShared; + /** Ring-3 per-queue data. */ + VQUEUER3 Queues[VIRTIO_MAX_NQUEUES]; +} VPCISTATER3; + + +/** + * The core ring-0 state of a VirtIO PCI device + */ +typedef struct VPCISTATER0 +{ + uint64_t uUnused; +} VPCISTATER0; + + +/** + * The core raw-mode state of a VirtIO PCI device + */ +typedef struct VPCISTATERC +{ + uint64_t uUnused; +} VPCISTATERC; + + +/** @name VirtIO port I/O callbacks. + * @{ */ +typedef struct VPCIIOCALLBACKS +{ + DECLCALLBACKMEMBER(uint32_t, pfnGetHostFeatures,(PVPCISTATE pVPciState)); + DECLCALLBACKMEMBER(uint32_t, pfnGetHostMinimalFeatures,(PVPCISTATE pVPciState)); + DECLCALLBACKMEMBER(void, pfnSetHostFeatures,(PVPCISTATE pVPciState, uint32_t fFeatures)); + DECLCALLBACKMEMBER(int, pfnGetConfig,(PVPCISTATE pVPciState, uint32_t offCfg, uint32_t cb, void *pvData)); + DECLCALLBACKMEMBER(int, pfnSetConfig,(PVPCISTATE pVPciState, uint32_t offCfg, uint32_t cb, void *pvData)); + DECLCALLBACKMEMBER(int, pfnReset,(PPDMDEVINS pDevIns)); + DECLCALLBACKMEMBER(void, pfnReady,(PPDMDEVINS pDevIns)); +} VPCIIOCALLBACKS; +/** Pointer to a const VirtIO port I/O callback structure. */ +typedef const VPCIIOCALLBACKS *PCVPCIIOCALLBACKS; +/** @} */ + +int vpciR3Init(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVPCISTATECC pThisCC, uint16_t uDeviceId, uint16_t uClass, uint32_t cQueues); +int vpciRZInit(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVPCISTATECC pThisCC); +int vpciR3Term(PPDMDEVINS pDevIns, PVPCISTATE pThis); +PVQUEUE vpciR3AddQueue(PVPCISTATE pThis, PVPCISTATECC pThisCC, unsigned uSize, PFNVPCIQUEUECALLBACK pfnCallback, const char *pcszName); +void *vpciR3QueryInterface(PVPCISTATECC pThisCC, const char *pszIID); +void vpciR3SetWriteLed(PVPCISTATE pThis, bool fOn); +void vpciR3SetReadLed(PVPCISTATE pThis, bool fOn); +int vpciR3SaveExec(PPDMDEVINS pDevIns, PCPDMDEVHLPR3 pHlp, PVPCISTATE pThis, PSSMHANDLE pSSM); +int vpciR3LoadExec(PPDMDEVINS pDevIns, PCPDMDEVHLPR3 pHlp, PVPCISTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t cQueues); +void vpciR3DumpStateWorker(PVPCISTATE pThis, PCDBGFINFOHLP pHlp); + +void vpciReset(PPDMDEVINS pDevIns, PVPCISTATE pThis); +int vpciRaiseInterrupt(PPDMDEVINS pDevIns, PVPCISTATE pThis, int rcBusy, uint8_t u8IntCause); +int vpciIOPortIn(PPDMDEVINS pDevIns, PVPCISTATE pThis, RTIOPORT offPort, + uint32_t *pu32, unsigned cb,PCVPCIIOCALLBACKS pCallbacks); +int vpciIOPortOut(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVPCISTATECC pThisCC, RTIOPORT offPort, + uint32_t u32, unsigned cb, PCVPCIIOCALLBACKS pCallbacks); + +#define VPCI_CS + +#ifdef VPCI_CS +# define VPCI_R3_CS_ENTER_RETURN_VOID(a_pDevIns, a_pThis) do { \ + int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &(a_pThis)->cs, VERR_IGNORED); \ + PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &(a_pThis)->cs, rcLock); \ + } while (0) +#else +# define VPCI_R3_CS_ENTER_RETURN_VOID(a_pDevIns, a_pThis) do { } while (0) +#endif + +DECLINLINE(int) vpciCsEnter(PPDMDEVINS pDevIns, PVPCISTATE pThis, int rcBusy) +{ +#ifdef VPCI_CS + return PDMDevHlpCritSectEnter(pDevIns, &pThis->cs, rcBusy); +#else + RT_NOREF(pDevIns, pThis, rcBusy); + return VINF_SUCCESS; +#endif +} + +DECLINLINE(void) vpciCsLeave(PPDMDEVINS pDevIns, PVPCISTATE pThis) +{ +#ifdef VPCI_CS + PDMDevHlpCritSectLeave(pDevIns, &pThis->cs); +#endif +} + +void vringSetNotification(PPDMDEVINS pDevIns, PVRING pVRing, bool fEnabled); + +DECLINLINE(uint16_t) vringReadAvailIndex(PPDMDEVINS pDevIns, PVRING pVRing) +{ + uint16_t idx = 0; + PDMDevHlpPhysRead(pDevIns, pVRing->addrAvail + RT_UOFFSETOF(VRINGAVAIL, uNextFreeIndex), &idx, sizeof(idx)); + return idx; +} + +bool vqueueSkip(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue); +bool vqueueGet(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove = true); +void vqueuePut(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t uLen, uint32_t uReserved = 0); +void vqueueSync(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue); + +DECLINLINE(bool) vqueuePeek(PPDMDEVINS pDevIns, PVPCISTATE pThis, PVQUEUE pQueue, PVQUEUEELEM pElem) +{ + return vqueueGet(pDevIns, pThis, pQueue, pElem, /* fRemove */ false); +} + +DECLINLINE(bool) vqueueIsReady(PVQUEUE pQueue) +{ + return !!pQueue->VRing.addrAvail; +} + +DECLINLINE(bool) vqueueIsEmpty(PPDMDEVINS pDevIns, PVQUEUE pQueue) +{ + return vringReadAvailIndex(pDevIns, &pQueue->VRing) == pQueue->uNextAvailIndex; +} + +#endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_h */ + |