VirtualBox

Changeset 80194 in vbox for trunk/src


Ignore:
Timestamp:
Aug 8, 2019 7:26:33 AM (5 years ago)
Author:
vboxsync
Message:

Some more re-structuring and encapsulation of library implementation. Starting to flesh out more of the negotiation with the driver and spec-defined behaviors (See #9440, Comment #43)

Location:
trunk/src/VBox/Devices
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp

    r80169 r80194  
    6060#define VIRTIOSCSI_REGION_PCI_CAP                   2
    6161
    62 
    63 
    6462/**
    6563 * This macro resolves to boolean true if uOffset matches a field offset and size exactly,
    6664 * (or if it is a 64-bit field, if it accesses either 32-bit part as a 32-bit access)
    6765 * ASSUMED this critereon is mandated by section 4.1.3.1 of the VirtIO 1.0 specification)
     66 * This MACRO can be re-written to allow unaligned access to a field (within bounds).
    6867 *
    6968 * @param   member   - Member of VIRTIO_PCI_COMMON_CFG_T
     
    7271 * @result           - true or false
    7372 */
    74 #define VIRTIO_1_0__SECT_4_1_3_1__COMPLIANT
    75 #ifdef VIRTIO_1_0__SECT_4_1_3_1__COMPLIANT
    76 #   define MATCH_SCSI_CONFIG(member) \
     73#define MATCH_SCSI_CONFIG(member) \
    7774            (RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member) == 64 \
    7875             && (   uOffset == RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member) \
     
    8178         || (uOffset == RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member) \
    8279               && cb == RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member))
    83 #else
    84 #   define MATCH_SCSI_CONFIG(member) \
    85         ((int)uOffset >= RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member) \
    86             &&  uOffset < (uint32_t)(RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member) \
    87                                    + RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member)) \
    88             &&   cb <= RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member) \
    89                       - (uOffset - RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member)))
    90 #endif
    9180
    9281#define LOG_ACCESSOR(member) \
     
    9786        uint32_t uMemberOffset = uOffset - RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member); \
    9887        if (fWrite) \
    99             memcpy(((char *)&pThis->virtioScsiConfig.member) + uMemberOffset, (const char *)pv, cb); \
     88            memcpy(((char *)&pVirtioScsi->virtioScsiConfig.member) + uMemberOffset, (const char *)pv, cb); \
    10089        else \
    101             memcpy((char *)pv, (const char *)(((char *)&pThis->virtioScsiConfig.member) + uMemberOffset), cb); \
     90            memcpy((char *)pv, (const char *)(((char *)&pVirtioScsi->virtioScsiConfig.member) + uMemberOffset), cb); \
    10291        LOG_ACCESSOR(member); \
    10392    }
     
    11099        else \
    111100        { \
    112             memcpy((char *)pv, (const char *)(((char *)&pThis->virtioScsiConfig.member) + uMemberOffset), cb); \
     101            memcpy((char *)pv, (const char *)(((char *)&pVirtioScsi->virtioScsiConfig.member) + uMemberOffset), cb); \
    113102            LOG_ACCESSOR(member); \
    114103        } \
     
    346335typedef struct VIRTIOSCSI
    347336{
    348     /* virtioState must be first member */
    349     VIRTIOSTATE                     virtioState;
     337    /* Opaque handle to Virtio common framework */
     338    VIRTIOHANDLE                    hVirtio;
    350339
    351340    /* SCSI target instances data */
     
    783772}
    784773
    785 static int virtioScsiR3CfgAccessed(PVIRTIOSCSI pThis, uint32_t uOffset,
     774static int virtioScsiR3CfgAccessed(PVIRTIOSCSI pVirtioScsi, uint32_t uOffset,
    786775                                    const void *pv, size_t cb, uint8_t fWrite)
    787776{
     
    856845{
    857846    int rc = VINF_SUCCESS;
    858     PVIRTIOSCSI  pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
     847    PVIRTIOSCSI  pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
    859848
    860849//    LogFunc(("Read from Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n",
    861850//              uOffset, cb));
    862851
    863     rc = virtioScsiR3CfgAccessed(pThis, uOffset, pv, cb, false);
     852    rc = virtioScsiR3CfgAccessed(pVirtioScsi, uOffset, pv, cb, false);
    864853
    865854    return rc;
     
    878867{
    879868    int rc = VINF_SUCCESS;
    880     PVIRTIOSCSI  pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
     869    PVIRTIOSCSI  pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
    881870
    882871//    LogFunc(("Write to Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n",
    883872//              uOffset, cb));
    884873
    885     rc = virtioScsiR3CfgAccessed(pThis, uOffset, pv, cb, true);
     874    rc = virtioScsiR3CfgAccessed(pVirtioScsi, uOffset, pv, cb, true);
    886875
    887876    return rc;
     
    11021091    pVirtioPciParams->uInterruptPin  = 0x01;
    11031092
    1104     PVIRTIOSTATE pVirtio = &(pThis->virtioState);
    1105 
    1106     virtioSetHostFeatures(pVirtio, VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED);
    1107 
    11081093    pThis->IBase.pfnQueryInterface = virtioScsiR3DeviceQueryInterface;
    11091094
     
    11201105    pThis->virtioScsiConfig.uMaxLun         = 16383; /* from VirtIO 1.0 spec */
    11211106
    1122     rc = virtioConstruct(pDevIns, pVirtio, iInstance, pVirtioPciParams,
     1107    rc = virtioConstruct(pDevIns, &pThis->hVirtio, iInstance, pVirtioPciParams,
    11231108                         VIRTIOSCSI_NAME_FMT, VIRTIOSCSI_N_QUEUES, VIRTIOSCSI_REGION_PCI_CAP,
     1109                         VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED,
    11241110                         virtioScsiR3DevCapRead, virtioScsiR3DevCapWrite,
    11251111                         sizeof(VIRTIO_SCSI_CONFIG_T) /* cbDevSpecificCap */,
    1126                          true /* fHaveDevSpecificCap */,
     1112                         (void *)&pThis->virtioScsiConfig /* pDevSpecificCap */,
    11271113                         0 /* uNotifyOffMultiplier */);
    11281114
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp

    r80168 r80194  
    11/* $Id$ */
    22/** @file
    3  * Virtio_1_0 - Virtio Common Functions (VirtQueue, VQueue, Virtio PCI)
     3 * Virtio_1_0 - Virtio Common Functions (VirtQ, VQueue, Virtio PCI)
    44 */
    55
     
    2626#include <iprt/assert.h>
    2727#include <iprt/uuid.h>
     28#include <iprt/mem.h>
    2829#include <VBox/vmm/pdmdev.h>
     30#include "Virtio_1_0_impl.h"
    2931#include "Virtio_1_0.h"
    30 #include "Virtio_1_0_impl.h"
    3132
    3233#define INSTANCE(pState) pState->szInstance
    3334#define IFACE_TO_STATE(pIface, ifaceName) ((VIRTIOSTATE *)((char*)(pIface) - RT_UOFFSETOF(VIRTIOSTATE, ifaceName)))
     35
     36#define H2P(hVirtio) ((PVIRTIOSTATE)(hVirtio))
    3437
    3538#ifdef LOG_ENABLED
     
    3740#endif
    3841
    39 void virtQueueReadDesc(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue, uint32_t idx, PVIRTQUEUEDESC pDesc)
    40 {
    41     //Log(("%s virtQueueReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVirtQueue, idx));
     42/**
     43 * Formats the logging of a memory-mapped I/O input or output value
     44 *
     45 * @param   pszFunc     - To avoid displaying this function's name via __FUNCTION__ or LogFunc()
     46 * @param   pszMember   - Name of struct member
     47 * @param   pv          - pointer to value
     48 * @param   cb          - size of value
     49 * @param   uOffset     - offset into member where value starts
     50 * @param   fWrite      - True if write I/O
     51 * @param   fHasIndex   - True if the member is indexed
     52 * @param   idx         - The index if fHasIndex
     53 */
     54void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, const void *pv, uint32_t cb,
     55                        uint32_t uOffset, bool fWrite, bool fHasIndex, uint32_t idx)
     56{
     57
     58#define FMTHEX(fmtout, val, cNybs) \
     59    fmtout[cNybs] = '\0'; \
     60    for (uint8_t i = 0; i < cNybs; i++) \
     61        fmtout[(cNybs - i) -1] = "0123456789abcdef"[(val >> (i * 4)) & 0xf];
     62
     63#define MAX_STRING   64
     64    char pszIdx[MAX_STRING] = { 0 };
     65    char pszDepiction[MAX_STRING] = { 0 };
     66    char pszFormattedVal[MAX_STRING] = { 0 };
     67    if (fHasIndex)
     68        RTStrPrintf(pszIdx, sizeof(pszIdx), "[%d]", idx);
     69    if (cb == 1 || cb == 2 || cb == 4 || cb == 8)
     70    {
     71        /* manually padding with 0's instead of \b due to different impl of %x precision than printf() */
     72        uint64_t val = 0;
     73        memcpy((char *)&val, pv, cb);
     74        FMTHEX(pszFormattedVal, val, cb * 2);
     75        if (uOffset != 0) /* display bounds if partial member access */
     76            RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s[%d:%d]",
     77                        pszMember, pszIdx, uOffset, uOffset + cb - 1);
     78        else
     79            RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s", pszMember, pszIdx);
     80        RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%-30s", pszDepiction);
     81        uint32_t first = 0;
     82        for (uint8_t i = 0; i < sizeof(pszDepiction); i++)
     83            if (pszDepiction[i] == ' ' && first++ != 0)
     84                pszDepiction[i] = '.';
     85        Log(("%s: Guest %s %s 0x%s\n", \
     86                  pszFunc, fWrite ? "wrote" : "read ", pszDepiction, pszFormattedVal));
     87    }
     88    else /* odd number or oversized access, ... log inline hex-dump style */
     89    {
     90        Log(("%s: Guest %s %s%s[%d:%d]: %.*Rhxs\n", \
     91              pszFunc, fWrite ? "wrote" : "read ", pszMember,
     92              pszIdx, uOffset, uOffset + cb, cb, pv));
     93    }
     94}
     95
     96
     97void virtQueueReadDesc(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint32_t idx, PVIRTQ_DESC_T pDesc)
     98{
     99    //Log(("%s virtQueueReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVirtQ, idx));
    42100    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    43                       pVirtQueue->pGcPhysVirtqDescriptors + sizeof(VIRTQUEUEDESC) * (idx % pVirtQueue->cbQueue),
    44                       pDesc, sizeof(VIRTQUEUEDESC));
    45 }
    46 
    47 uint16_t virtQueueReadAvail(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue, uint32_t idx)
     101                      pVirtQ->pGcPhysVirtqDescriptors + sizeof(VIRTQ_DESC_T) * (idx % pVirtQ->cbQueue),
     102                      pDesc, sizeof(VIRTQ_DESC_T));
     103}
     104
     105uint16_t virtQueueReadAvail(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint32_t idx)
    48106{
    49107    uint16_t tmp;
    50108    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    51                       pVirtQueue->pGcPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQUEUEAVAIL, auRing[idx % pVirtQueue->cbQueue]),
     109                      pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[idx % pVirtQ->cbQueue]),
    52110                      &tmp, sizeof(tmp));
    53111    return tmp;
    54112}
    55113
    56 uint16_t virtQueueReadAvailFlags(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue)
     114uint16_t virtQueueReadAvailFlags(PVIRTIOSTATE pState, PVIRTQ pVirtQ)
    57115{
    58116    uint16_t tmp;
    59117    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    60                       pVirtQueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEAVAIL, fFlags),
     118                      pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
    61119                      &tmp, sizeof(tmp));
    62120    return tmp;
    63121}
    64122
    65 uint16_t virtQueueReadUsedIndex(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue)
     123uint16_t virtQueueReadUsedIndex(PVIRTIOSTATE pState, PVIRTQ pVirtQ)
    66124{
    67125    uint16_t tmp;
    68126    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    69                       pVirtQueue->pGcPhysVirtqUsed + RT_UOFFSETOF(VIRTQUEUEUSED, uIdx),
     127                      pVirtQ->pGcPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
    70128                      &tmp, sizeof(tmp));
    71129    return tmp;
    72130}
    73131
    74 void virtQueueWriteUsedIndex(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue, uint16_t u16Value)
     132void virtQueueWriteUsedIndex(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint16_t u16Value)
    75133{
    76134    PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns),
    77                           pVirtQueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEUSED, uIdx),
     135                          pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
    78136                          &u16Value, sizeof(u16Value));
    79137}
    80138
    81 void virtQueueWriteUsedElem(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue, uint32_t idx, uint32_t id, uint32_t uLen)
    82 {
    83 
    84     RT_NOREF5(pState, pVirtQueue, idx, id, uLen);
     139void virtQueueWriteUsedElem(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint32_t idx, uint32_t id, uint32_t uLen)
     140{
     141
     142    RT_NOREF5(pState, pVirtQ, idx, id, uLen);
    85143    /* PK TODO: Adapt to VirtIO 1.0
    86     VIRTQUEUEUSEDELEM elem;
     144    VIRTQ_USED_ELEM_T elem;
    87145
    88146    elem.id = id;
    89147    elem.uLen = uLen;
    90148    PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns),
    91                           pVirtQueue->pGcPhysVirtqUsed + RT_UOFFSETOF_DYN(VIRTQUEUEUSED, ring[idx % pVirtQueue->cbQueue]),
     149                          pVirtQ->pGcPhysVirtqUsed + RT_UOFFSETOF_DYN(VIRTQ_USED_T, ring[idx % pVirtQ->cbQueue]),
    92150                          &elem, sizeof(elem));
    93151    */
    94152}
    95153
    96 void virtQueueSetNotification(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue, bool fEnabled)
    97 {
    98     RT_NOREF3(pState, pVirtQueue, fEnabled);
     154void virtQueueSetNotification(PVIRTIOSTATE pState, PVIRTQ pVirtQ, bool fEnabled)
     155{
     156    RT_NOREF3(pState, pVirtQ, fEnabled);
    99157
    100158/* PK TODO: Adapt to VirtIO 1.0
     
    102160
    103161    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    104                       pVirtQueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEUSED, uFlags),
     162                      pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uFlags),
    105163                      &tmp, sizeof(tmp));
    106164
    107165    if (fEnabled)
    108         tmp &= ~ VIRTQUEUEUSED_F_NO_NOTIFY;
     166        tmp &= ~ VIRTQ_USED_T_F_NO_NOTIFY;
    109167    else
    110         tmp |= VIRTQUEUEUSED_F_NO_NOTIFY;
     168        tmp |= VIRTQ_USED_T_F_NO_NOTIFY;
    111169
    112170    PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns),
    113                           pVirtQueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEUSED, uFlags),
     171                          pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uFlags),
    114172                          &tmp, sizeof(tmp));
    115173*/
     
    145203          QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex));
    146204
    147     VIRTQUEUEDESC desc;
    148     uint16_t  idx = virtQueueReadAvail(pState, &pQueue->VirtQueue, pQueue->uNextAvailIndex);
     205    VIRTQ_DESC_T desc;
     206    uint16_t  idx = virtQueueReadAvail(pState, &pQueue->VirtQ, pQueue->uNextAvailIndex);
    149207    if (fRemove)
    150208        pQueue->uNextAvailIndex++;
     
    160218        // total number of descriptors in the ring (see @bugref{8620}).
    161219        ///
    162         if (pElem->nIn + pElem->nOut >= VIRTQUEUE_MAX_SIZE)
     220        if (pElem->nIn + pElem->nOut >= VIRTQ_MAX_SIZE)
    163221        {
    164222            static volatile uint32_t s_cMessages  = 0;
     
    177235        RT_UNTRUSTED_VALIDATED_FENCE();
    178236
    179         virtQueueReadDesc(pState, &pQueue->VirtQueue, idx, &desc);
    180         if (desc.u16Flags & VIRTQUEUEDESC_F_WRITE)
     237        virtQueueReadDesc(pState, &pQueue->VirtQ, idx, &desc);
     238        if (desc.u16Flags & VIRTQ_DESC_T_F_WRITE)
    181239        {
    182240            Log2(("%s virtQueueGet: %s IN  seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState),
     
    196254
    197255        idx = desc.next;
    198     } while (desc.u16Flags & VIRTQUEUEDESC_F_NEXT);
     256    } while (desc.u16Flags & VIRTQ_DESC_T_F_NEXT);
    199257
    200258    Log2(("%s virtQueueGet: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pState),
     
    261319          " used_idx=%u guest_used_idx=%u id=%u len=%u\n",
    262320          INSTANCE(pState), QUEUENAME(pState, pQueue),
    263           pQueue->uNextUsedIndex, virtQueueReadUsedIndex(pState, &pQueue->VirtQueue),
     321          pQueue->uNextUsedIndex, virtQueueReadUsedIndex(pState, &pQueue->VirtQ),
    264322          pElem->idx, uTotalLen));
    265323
    266     virtQueueWriteUsedElem(pState, &pQueue->VirtQueue,
     324    virtQueueWriteUsedElem(pState, &pQueue->VirtQ,
    267325                       pQueue->uNextUsedIndex++,
    268326                       pElem->idx, uTotalLen);
     
    279337    LogFlow(("%s virtQueueNotify: %s availFlags=%x guestFeatures=%x virtQueue is %sempty\n",
    280338             INSTANCE(pState), QUEUENAME(pState, pQueue),
    281              virtQueueReadAvailFlags(pState, &pQueue->VirtQueue),
     339             virtQueueReadAvailFlags(pState, &pQueue->VirtQ),
    282340             pState->uGuestFeatures, virtQueueIsEmpty(pState, pQueue)?"":"not "));
    283     if (!(virtQueueReadAvailFlags(pState, &pQueue->VirtQueue) & VIRTQUEUEAVAIL_F_NO_INTERRUPT)
     341    if (!(virtQueueReadAvailFlags(pState, &pQueue->VirtQ) & VIRTQ_AVAIL_T_F_NO_INTERRUPT)
    284342        || ((pState->uGuestFeatures & VIRTIO_F_NOTIFY_ON_EMPTY) && virtQueueIsEmpty(pState, pQueue)))
    285343    {
     
    296354/* PK TODO Adapt to VirtIO 1.0
    297355    Log2(("%s virtQueueSync: %s old_used_idx=%u new_used_idx=%u\n", INSTANCE(pState),
    298           QUEUENAME(pState, pQueue), virtQueueReadUsedIndex(pState, &pQueue->VirtQueue), pQueue->uNextUsedIndex));
    299     virtQueueWriteUsedIndex(pState, &pQueue->VirtQueue, pQueue->uNextUsedIndex);
     356          QUEUENAME(pState, pQueue), virtQueueReadUsedIndex(pState, &pQueue->VirtQ), pQueue->uNextUsedIndex));
     357    virtQueueWriteUsedIndex(pState, &pQueue->VirtQ, pQueue->uNextUsedIndex);
    300358    virtQueueNotify(pState, pQueue);
    301359*/
    302360}
    303361
    304 int virtioReset(PVIRTIOSTATE pVirtio)
    305 {
    306     RT_NOREF(pVirtio);
    307 /* PK TODO Adapt to VirtIO 1.09
    308     pState->uGuestFeatures = 0;
    309     pState->uQueueSelector = 0;
    310     pState->uStatus        = 0;
    311     pState->uISR           = 0;
    312 
    313     for (unsigned i = 0; i < pState->nQueues; i++)
    314         virtQueueReset(&pState->Queues[i]);
    315 */
    316     virtioNotify(pVirtio);
    317     return VINF_SUCCESS;
    318 }
     362
    319363
    320364/**
     
    383427 * @param   uPass       The data pass.
    384428 */
    385 int virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t nQueues)
    386 {
    387     RT_NOREF5(pVirtio, pSSM, uVersion, uPass, nQueues);
     429int virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t uNumQueues)
     430{
     431    RT_NOREF5(pVirtio, pSSM, uVersion, uPass, uNumQueues);
    388432    int rc = VINF_SUCCESS;
    389433    virtioDumpState(pVirtio, "virtioLoadExec");
     
    419463{
    420464    RT_NOREF(offDelta);
    421     VIRTIOSTATE *pState = PDMINS_2_DATA(pDevIns, VIRTIOSTATE*);
    422     pState->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
     465    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
     466
     467    pVirtio->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    423468    // TBD
    424469}
    425470
    426 PVQUEUE virtioAddQueue(VIRTIOSTATE* pState, unsigned cbQueue, PFNVIRTIOQUEUECALLBACK pfnCallback, const char *pcszName)
    427 {
    428 
    429     RT_NOREF4(pState, cbQueue, pfnCallback, pcszName);
     471PVQUEUE virtioAddQueue(VIRTIOSTATE* pState, unsigned cbQueue, const char *pcszName)
     472{
     473
     474    RT_NOREF3(pState, cbQueue, pcszName);
    430475/* PK TODO Adapt to VirtIO 1.0
    431476
    432477    PVQUEUE pQueue = NULL;
    433478    // Find an empty queue slot
    434     for (unsigned i = 0; i < pState->nQueues; i++)
    435     {
    436         if (pState->Queues[i].VirtQueue.cbQueue == 0)
     479    for (unsigned i = 0; i < pState->uNumQueues; i++)
     480    {
     481        if (pState->Queues[i].VirtQ.cbQueue == 0)
    437482        {
    438483            pQueue = &pState->Queues[i];
     
    447492    else
    448493    {
    449         pQueue->VirtQueue.cbQueue = cbQueue;
    450         pQueue->VirtQueue.addrDescriptors = 0;
     494        pQueue->VirtQ.cbQueue = cbQueue;
     495        pQueue->VirtQ.addrDescriptors = 0;
    451496        pQueue->uPageNumber = 0;
    452497        pQueue->pfnCallback = pfnCallback;
     
    459504
    460505
     506
     507__attribute__((unused))
     508static void virtQueueInit(PVQUEUE pQueue, uint32_t uPageNumber)
     509{
     510    RT_NOREF2(pQueue, uPageNumber);
     511
     512/* PK TODO, re-work this for VirtIO 1.0
     513    pQueue->VirtQ.addrDescriptors = (uint64_t)uPageNumber << PAGE_SHIFT;
     514
     515    pQueue->VirtQ.addrAvail = pQueue->VirtQ.addrDescriptors
     516                                + sizeof(VIRTQ_DESC_T) * pQueue->VirtQ.cbQueue;
     517
     518    pQueue->VirtQ.addrUsed  = RT_ALIGN(pQueue->VirtQ.addrAvail
     519            + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, ring[pQueue->VirtQ.cbQueue])
     520            + sizeof(uint16_t), // virtio 1.0 adds a 16-bit field following ring data
     521              PAGE_SIZE); // The used ring must start from the next page.
     522
     523    pQueue->uNextAvailIndex       = 0;
     524    pQueue->uNextUsedIndex        = 0;
     525*/
     526
     527}
     528
     529
    461530__attribute__((unused))
    462531static void virtQueueReset(PVQUEUE pQueue)
     
    464533    RT_NOREF(pQueue);
    465534/* PK TODO Adapt to VirtIO 1.0
    466     pQueue->VirtQueue.addrDescriptors = 0;
    467     pQueue->VirtQueue.addrAvail       = 0;
    468     pQueue->VirtQueue.addrUsed        = 0;
     535    pQueue->VirtQ.addrDescriptors = 0;
     536    pQueue->VirtQ.addrAvail       = 0;
     537    pQueue->VirtQ.addrUsed        = 0;
    469538    pQueue->uNextAvailIndex           = 0;
    470539    pQueue->uNextUsedIndex            = 0;
     
    473542}
    474543
     544/**
     545 * Notify driver of a configuration or queue event
     546 *
     547 * @param   pVirtio             - Pointer to instance state
     548 * @param   fConfigChange       - True if cfg change notification else, queue notification
     549 */
     550static void virtioNotifyDriver(VIRTIOHANDLE hVirtio, bool fConfigChange)
     551{
     552   RT_NOREF(hVirtio);
     553   LogFunc(("fConfigChange = %d\n", fConfigChange));
     554}
     555
     556
     557int virtioReset(VIRTIOHANDLE hVirtio)  /* Part of our "custom API" */
     558{
     559    PVIRTIOSTATE pVirtio = H2P(hVirtio);
     560
     561    RT_NOREF(pVirtio);
     562/* PK TODO Adapt to VirtIO 1.09
     563    pState->uGuestFeatures = 0;
     564    pState->uQueueSelector = 0;
     565    pState->uStatus        = 0;
     566    pState->uISR           = 0;
     567
     568    for (unsigned i = 0; i < pState->uNumQueues; i++)
     569        virtQueueReset(&pState->Queues[i]);
     570    virtioNotify(pVirtio);
     571*/
     572    return VINF_SUCCESS;
     573}
     574
    475575__attribute__((unused))
    476 static void virtQueueInit(PVQUEUE pQueue, uint32_t uPageNumber)
    477 {
    478     RT_NOREF2(pQueue, uPageNumber);
    479 
    480 /* PK TODO, re-work this for VirtIO 1.0
    481     pQueue->VirtQueue.addrDescriptors = (uint64_t)uPageNumber << PAGE_SHIFT;
    482 
    483     pQueue->VirtQueue.addrAvail = pQueue->VirtQueue.addrDescriptors
    484                                 + sizeof(VIRTQUEUEDESC) * pQueue->VirtQueue.cbQueue;
    485 
    486     pQueue->VirtQueue.addrUsed  = RT_ALIGN(pQueue->VirtQueue.addrAvail
    487             + RT_UOFFSETOF_DYN(VIRTQUEUEAVAIL, ring[pQueue->VirtQueue.cbQueue])
    488             + sizeof(uint16_t), // virtio 1.0 adds a 16-bit field following ring data
    489               PAGE_SIZE); // The used ring must start from the next page.
    490 
    491     pQueue->uNextAvailIndex       = 0;
    492     pQueue->uNextUsedIndex        = 0;
    493 */
    494 
    495 }
    496 
    497 void virtioNotify(PVIRTIOSTATE pVirtio)
    498 {
    499     RT_NOREF(pVirtio);
     576static void virtioSetNeedsReset(PVIRTIOSTATE pVirtio)
     577{
     578    pVirtio->uDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
     579    if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
     580    {
     581        pVirtio->fGenUpdatePending = true;
     582        virtioNotifyDriver(pVirtio, true);
     583    }
    500584}
    501585
    502586static void virtioResetDevice(PVIRTIOSTATE pVirtio)
    503587{
    504     RT_NOREF(pVirtio);
     588
    505589    LogFunc(("\n"));
    506     pVirtio->uDeviceStatus = 0;
     590    pVirtio->uDeviceStatus          = 0;
     591    pVirtio->uDeviceFeaturesSelect  = 0;
     592    pVirtio->uDriverFeaturesSelect  = 0;
     593    pVirtio->uConfigGeneration      = 0;
     594    pVirtio->uNumQueues             = VIRTIO_MAX_QUEUES;
     595
     596    for (uint32_t i = 0; i < pVirtio->uNumQueues; i++)
     597    {
     598        pVirtio->uQueueSize[i]      = VIRTQ_MAX_SIZE;
     599        pVirtio->uQueueNotifyOff[i] = i;
     600//      virtqNotify();
     601    }
    507602}
    508603
     
    603698        {
    604699            uint32_t uIntraOff = 0;
    605             *(uint16_t *)pv = MAX_QUEUES;
     700            *(uint16_t *)pv = VIRTIO_MAX_QUEUES;
    606701            LOG_ACCESSOR(uNumQueues);
    607702        }
     
    696791{
    697792    RT_NOREF(pvUser);
    698     PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);
     793    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
    699794    int rc = VINF_SUCCESS;
    700795
     
    710805    {
    711806        uint32_t uDevSpecificDataOffset = GCPhysAddr - pVirtio->pGcPhysDeviceCap;
     807        /**
     808         * Callback to client to manage device-specific configuration and changes to it.
     809         */
    712810        rc = pVirtio->virtioCallbacks.pfnVirtioDevCapRead(pDevIns, uDevSpecificDataOffset, pv, cb);
     811        /**
     812         * Anytime any part of the device-specific configuration (which our client maintains) is read
     813         * it needs to be checked to see if it changed since the last time any part was read, in
     814         * order to maintain the config generation (see VirtIO 1.0 spec, section 4.1.4.3.1)
     815         */
     816        uint32_t fDevSpecificFieldChanged = false;
     817
     818        if (memcmp((char *)pv + uDevSpecificDataOffset, (char *)pVirtio->pPrevDevSpecificCap + uDevSpecificDataOffset, cb))
     819            fDevSpecificFieldChanged = true;
     820
     821        memcpy(pVirtio->pPrevDevSpecificCap, pv, pVirtio->cbDevSpecificCap);
     822        if (pVirtio->fGenUpdatePending || fDevSpecificFieldChanged)
     823        {
     824            if (fDevSpecificFieldChanged)
     825                LogFunc(("Dev specific config field changed since last read, gen++ = %d\n",
     826                     pVirtio->uConfigGeneration));
     827            else
     828                LogFunc(("Config generation pending flag set, gen++ = %d\n",
     829                     pVirtio->uConfigGeneration));
     830            ++pVirtio->uConfigGeneration;
     831            pVirtio->fGenUpdatePending = false;
     832        }
    713833    }
    714834    else
     
    745865{
    746866    RT_NOREF(pvUser);
    747     PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);
     867    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
    748868    int rc = VINF_SUCCESS;
    749869
     
    790910{
    791911    RT_NOREF3(pPciDev, iRegion, enmType);
    792     PVIRTIOSTATE  pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);
     912    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
    793913    int rc = VINF_SUCCESS;
    794914
    795915    Assert(cb >= 32);
    796916
    797     if (iRegion == pVirtio->uVirtioCapRegion)
     917    if (iRegion == pVirtio->uVirtioCapBar)
    798918    {
    799919        /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
     
    815935        pVirtio->pGcPhysNotifyCap = GCPhysAddress + pVirtio->pNotifyCap->pciCap.uOffset;
    816936        pVirtio->pGcPhysIsrCap    = GCPhysAddress + pVirtio->pIsrCap->uOffset;
    817         if (pVirtio->fHaveDevSpecificCap)
     937        if (pVirtio->pDevSpecificCap)
    818938            pVirtio->pGcPhysDeviceCap = GCPhysAddress + pVirtio->pDeviceCap->uOffset;
    819939    }
     
    837957                                       uint32_t uAddress, unsigned cb)
    838958{
    839     PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);
     959//    PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);
     960    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
    840961
    841962    if (uAddress == (uint64_t)&pVirtio->pPciCfgCap->uPciCfgData)
     
    848969        uint8_t  uBar    = pVirtio->pPciCfgCap->pciCap.uBar;
    849970        uint32_t pv = 0;
    850         if (uBar == pVirtio->uVirtioCapRegion)
     971        if (uBar == pVirtio->uVirtioCapBar)
    851972            (void)virtioR3MmioRead(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->GCPhysPciCapBase + uOffset),
    852973                                    &pv, uLength);
     
    8821003                                        uint32_t uAddress, uint32_t u32Value, unsigned cb)
    8831004{
    884     PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);
     1005    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
    8851006
    8861007    if (uAddress == pVirtio->uPciCfgDataOff)
     
    8921013        uint32_t uOffset = pVirtio->pPciCfgCap->pciCap.uOffset;
    8931014        uint8_t  uBar    = pVirtio->pPciCfgCap->pciCap.uBar;
    894         if (uBar == pVirtio->uVirtioCapRegion)
     1015        if (uBar == pVirtio->uVirtioCapBar)
    8951016            (void)virtioR3MmioWrite(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->GCPhysPciCapBase + uOffset),
    8961017                                    (void *)&u32Value, uLength);
     
    9441065 */
    9451066
    946 void virtioSetHostFeatures(PVIRTIOSTATE pVirtio, uint64_t uDeviceFeatures)
    947 {
    948     pVirtio->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures;
     1067
     1068void virtioSetHostFeatures(VIRTIOHANDLE hVirtio, uint64_t uDeviceFeatures)
     1069{
     1070    H2P(hVirtio)->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures;
    9491071}
    9501072
     
    9881110 * @param   pPciParams            Values to populate industry standard PCI Configuration Space data structure
    9891111 * @param   pcszNameFmt           Device instance name (format-specifier)
    990  * @param   nQueues               Number of Virtio Queues created by consumer (driver)
     1112 * @param   uNumQueues               Number of Virtio Queues created by consumer (driver)
    9911113 * @param   uVirtioRegion         Region number to map for PCi Capabilities structs
    9921114 * @param   devCapReadCallback    Client function to call back to handle device specific capabilities
     
    9961118 */
    9971119
    998 int   virtioConstruct(PPDMDEVINS pDevIns, PVIRTIOSTATE pVirtio, int iInstance, PVIRTIOPCIPARAMS pPciParams,
    999                     const char *pcszNameFmt, uint32_t nQueues, uint32_t uVirtioCapRegion,
     1120int   virtioConstruct(PPDMDEVINS pDevIns, PVIRTIOHANDLE phVirtio, int iInstance, PVIRTIOPCIPARAMS pPciParams,
     1121                    const char *pcszNameFmt, uint32_t uNumQueues, uint32_t uVirtioCapBar, uint64_t uDeviceFeatures,
    10001122                    PFNVIRTIODEVCAPREAD devCapReadCallback, PFNVIRTIODEVCAPWRITE devCapWriteCallback,
    1001                     uint16_t cbDevSpecificCap, bool fHaveDevSpecificCap,  uint32_t uNotifyOffMultiplier)
    1002 {
    1003     pVirtio->nQueues = nQueues;
     1123                    uint16_t cbDevSpecificCap, void *pDevSpecificCap,  uint32_t uNotifyOffMultiplier)
     1124{
     1125
     1126    int rc = VINF_SUCCESS;
     1127
     1128    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)RTMemAlloc(sizeof(VIRTIOSTATE));
     1129    if (!pVirtio)
     1130    {
     1131        PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("virtio: out of memory"));
     1132        return VERR_NO_MEMORY;
     1133    }
     1134
     1135
     1136    pVirtio->uNumQueues = uNumQueues;
    10041137    pVirtio->uNotifyOffMultiplier = uNotifyOffMultiplier;
     1138    pVirtio->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures;
    10051139
    10061140    /* Init handles and log related stuff. */
     
    10121146    pVirtio->uDeviceStatus = 0;
    10131147    pVirtio->cbDevSpecificCap = cbDevSpecificCap;
    1014     pVirtio->uVirtioCapRegion = uVirtioCapRegion;
    1015     pVirtio->fHaveDevSpecificCap = fHaveDevSpecificCap;
     1148    pVirtio->pDevSpecificCap = pDevSpecificCap;
     1149    /**
     1150     * Need to keep a history of this relatively small virtio device-specific
     1151     * configuration buffer, which is opaque to this encapsulation of the generic
     1152     * part virtio operations, to track config changes to fields, in order to
     1153     * update the configuration generation each change. (See VirtIO 1.0 section 4.1.4.3.1)
     1154     */
     1155    pVirtio->pPrevDevSpecificCap = RTMemAlloc(cbDevSpecificCap);
     1156    if (!pVirtio->pPrevDevSpecificCap)
     1157    {
     1158        RTMemFree(pVirtio);
     1159        PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("virtio: out of memory"));
     1160        return VERR_NO_MEMORY;
     1161    }
     1162    memcpy(pVirtio->pPrevDevSpecificCap, pVirtio->pDevSpecificCap, cbDevSpecificCap);
     1163    pVirtio->uVirtioCapBar = uVirtioCapBar;
    10161164    pVirtio->virtioCallbacks.pfnVirtioDevCapRead = devCapReadCallback;
    10171165    pVirtio->virtioCallbacks.pfnVirtioDevCapWrite = devCapWriteCallback;
     
    10291177    PCIDevSetInterruptPin      (&pVirtio->dev, pPciParams->uInterruptPin);
    10301178
    1031     int rc = VINF_SUCCESS;
    10321179    /* Register PCI device */
    10331180    rc = PDMDevHlpPCIRegister(pDevIns, &pVirtio->dev);
    10341181    if (RT_FAILURE(rc))
     1182    {
     1183        RTMemFree(pVirtio);
    10351184        return PDMDEV_SET_ERROR(pDevIns, rc,
    10361185            N_("virtio: cannot register PCI Device")); /* can we put params in this error? */
     1186    }
    10371187
    10381188    pVirtio->IBase = pDevIns->IBase;
    1039 
    10401189
    10411190    PDMDevHlpPCISetConfigCallbacks(pDevIns, &pVirtio->dev,
     
    10501199    uint8_t fMsiSupport = false;
    10511200#endif
    1052 
    10531201
    10541202    /* The following capability mapped via VirtIO 1.0: struct virtio_pci_cfg_cap (VIRTIO_PCI_CFG_CAP_T)
     
    10681216    pCfg->uCapLen  = sizeof(VIRTIO_PCI_CAP_T);
    10691217    pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen;
    1070     pCfg->uBar     = uVirtioCapRegion;
     1218    pCfg->uBar     = uVirtioCapBar;
    10711219    pCfg->uOffset  = 0;
    10721220    pCfg->uLength  = sizeof(VIRTIO_PCI_COMMON_CFG_T);
     
    10791227    pCfg->uCapLen  = sizeof(VIRTIO_PCI_NOTIFY_CAP_T);
    10801228    pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen;
    1081     pCfg->uBar     = uVirtioCapRegion;
     1229    pCfg->uBar     = uVirtioCapBar;
    10821230    pCfg->uOffset  = pVirtio->pCommonCfgCap->uOffset + pVirtio->pCommonCfgCap->uLength;
    10831231    pCfg->uLength  = 4; /* This needs to be calculated differently */
     
    10911239    pCfg->uCapLen  = sizeof(VIRTIO_PCI_CAP_T);
    10921240    pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen;
    1093     pCfg->uBar     = uVirtioCapRegion;
     1241    pCfg->uBar     = uVirtioCapBar;
    10941242    pCfg->uOffset  = pVirtio->pNotifyCap->pciCap.uOffset + pVirtio->pNotifyCap->pciCap.uLength;
    10951243    pCfg->uLength  = sizeof(uint32_t);
     
    11011249    pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR;
    11021250    pCfg->uCapLen  = sizeof(VIRTIO_PCI_CFG_CAP_T);
    1103     pCfg->uCapNext = (fMsiSupport || pVirtio->fHaveDevSpecificCap) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;
    1104     pCfg->uBar     = uVirtioCapRegion;
     1251    pCfg->uCapNext = (fMsiSupport || pVirtio->pDevSpecificCap) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;
     1252    pCfg->uBar     = uVirtioCapBar;
    11051253    pCfg->uOffset  = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength;
    11061254    pCfg->uLength  = 4;  /* Initialize a non-zero 4-byte aligned so Linux virtio_pci module recognizes this cap */
    11071255    pVirtio->pPciCfgCap = (PVIRTIO_PCI_CFG_CAP_T)pCfg;
    11081256
    1109     if (pVirtio->fHaveDevSpecificCap)
     1257    if (pVirtio->pDevSpecificCap)
    11101258    {
    11111259        /* Following capability mapped via VirtIO 1.0: struct virtio_pci_dev_cap (VIRTIODEVCAP)*/
     
    11151263        pCfg->uCapLen  = sizeof(VIRTIO_PCI_CAP_T);
    11161264        pCfg->uCapNext = fMsiSupport ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;
    1117         pCfg->uBar     = uVirtioCapRegion;
     1265        pCfg->uBar     = uVirtioCapBar;
    11181266        pCfg->uOffset  = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength;
    11191267        pCfg->uLength  = cbDevSpecificCap;
     
    11391287    }
    11401288
    1141     rc = PDMDevHlpPCIIORegionRegister(pDevIns, uVirtioCapRegion, 4096,
     1289    rc = PDMDevHlpPCIIORegionRegister(pDevIns, uVirtioCapBar, 4096,
    11421290                                      PCI_ADDRESS_SPACE_MEM, virtioR3Map);
    11431291    if (RT_FAILURE(rc))
     1292    {
     1293        RTMemFree(pVirtio->pPrevDevSpecificCap);
     1294        RTMemFree(pVirtio);
    11441295        return PDMDEV_SET_ERROR(pDevIns, rc,
    11451296            N_("virtio: cannot register PCI Capabilities address space"));
    1146 
     1297    }
     1298    *phVirtio = (PVIRTIOHANDLE)pVirtio;
    11471299    return rc;
    11481300}
    1149 
    11501301#endif /* IN_RING3 */
    11511302
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h

    r80169 r80194  
    11/* $Id$ */
    22/** @file
    3  * Virtio_1_0p .h - Virtio Declarations
     3 * Virtio_1_0.h - Virtio Declarations
    44 */
    55
     
    2424#include <iprt/ctype.h>
    2525
    26 /** @name Saved state versions.
    27  * The saved state version is changed if either common or any of specific
    28  * parts are changed. That is, it is perfectly possible that the version
    29  * of saved vnet state will increase as a result of change in vblk structure
    30  * for example.
    31  */
    32 #define VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1 1
    33 #define VIRTIO_SAVEDSTATE_VERSION           2
    34 /** @} */
     26#define VIRTQ_MAX_SIZE                      1024
     27#define VIRTIO_MAX_QUEUES                   256     /** Max queues we allow guest to create      */
     28#define VIRTQ_DESC_MAX_SIZE                 (2 * 1024 * 1024)
     29
     30typedef void * VIRTIOHANDLE;                        /** opaque handle to the VirtIO framework */
     31typedef VIRTIOHANDLE *PVIRTIOHANDLE;
    3532
    3633/** Reserved Feature Bits */
     
    3936#define VIRTIO_F_VERSION_1                  RT_BIT_64(32)
    4037
    41 #define MAX_QUEUES                          5       /** Maximum number of queues we support     */
    42 
    43 /** Mandatory for Virtio PCI device identification, per spec */
    44 #define DEVICE_PCI_VENDOR_ID_VIRTIO         0x1AF4
    45 
    46 /** Virtio spec suggests >= 1 for non-transitional drivers */
    47 #define DEVICE_PCI_REVISION_ID_VIRTIO       1
    48 
    49 /* Virtio Device PCI Capabilities type codes */
    50 #define VIRTIO_PCI_CAP_COMMON_CFG           1
    51 #define VIRTIO_PCI_CAP_NOTIFY_CFG           2
    52 #define VIRTIO_PCI_CAP_ISR_CFG              3
    53 #define VIRTIO_PCI_CAP_DEVICE_CFG           4
    54 #define VIRTIO_PCI_CAP_PCI_CFG              5
     38#define VIRTIO_MSI_NO_VECTOR                0xffff  /* Vector value used to disable MSI for queue */
    5539
    5640/** Device Status field constants (from Virtio 1.0 spec) */
     
    6246#define VIRTIO_STATUS_DEVICE_NEEDS_RESET    0x40    /** Device experienced unrecoverable error   */
    6347
    64 #define VIRTIO_MAX_NQUEUES                  256     /** Max queues we allow guest to create      */
    65 #define VIRTQUEUEDESC_MAX_SIZE              (2 * 1024 * 1024)   /** Legacy only? */
    66 #define VIRTQUEUE_MAX_SIZE                  1024    /** According to? Legacy only? */
    67 #define VIRTIO_ISR_QUEUE                    0x1     /* Legacy only? Now derived from feature negotiation? */
    68 #define VIRTIO_ISR_CONFIG                   0x3     /* Legacy only? Now derived from feature negotiation? */
    69 
    70 #define VIRTIO_PCI_CAP_ID_VENDOR            0x09
    71 
    72 /* Vector value used to disable MSI for queue */
    73 #define VIRTIO_MSI_NO_VECTOR                0xffff
    74 
    75 /** Most of the following definitions attempt to adhere to the names and
    76  *  and forms used by the VirtIO 1.0 specification to increase the maintainability
    77  *  and speed of ramp-up, in other words, to as unambiguously as possible
    78  *  map the spec to the VirtualBox implementation of it */
    79 
    80 /** Indicates that this descriptor chains to another */
    81 #define VIRTQ_DESC_F_NEXT                   1
    82 
    83 /** Marks buffer as write-only (default ro) */
    84 #define VIRTQ_DESC_F_WRITE                  2
    85 
    86 /** This means the buffer contains a list of buffer descriptors. */
    87 #define VIRTQ_DESC_F_INDIRECT               4
    88 
    89 /** Optimization: Device advises driver (unreliably):  Don't kick me when adding buffer */
    90 #define VIRTQ_USED_F_NO_NOTIFY              1
    91 
    92 /** Optimization: Driver advises device (unreliably): Don't interrupt when buffer consumed */
    93 #define VIRTQ_AVAIL_F_NO_INTERRUPT          1
    94 
    95 /** Using indirect descriptors */
    96 #define VIRTIO_F_INDIRECT_DESC              28
    97 
    98 /** Indicates either avail_event, or used_event fields are in play */
    99 #define VIRTIO_F_EVENT_IDX                  29
    100 
    101 /** Allow aribtary descriptor layouts */
    102 #define VIRTIO_F_ANY_LAYOUT                 27
    103 
     48/** virtq related flags */
     49#define VIRTQ_DESC_F_NEXT                   1       /** Indicates this descriptor chains to next */
     50#define VIRTQ_DESC_F_WRITE                  2       /** Marks buffer as write-only (default ro)  */
     51#define VIRTQ_DESC_F_INDIRECT               4       /** Buffer is list of buffer descriptors     */
     52#define VIRTIO_F_INDIRECT_DESC              28      /** Using indirect descriptors               */
     53#define VIRTIO_F_EVENT_IDX                  29      /** avail_event, used_event in play          */
     54
     55#define VIRTQ_USED_F_NO_NOTIFY              1       /** Optimization: Device advises driver (unreliably):
     56                                                        Don't kick me when adding buffer */
     57
     58#define VIRTQ_AVAIL_F_NO_INTERRUPT          1       /** Optimization: Driver advises device (unreliably):
     59                                                        Don't interrupt when buffer consumed */
     60/**
     61 * virtq related structs
     62 *  (struct names follow VirtIO 1.0 spec, typedef use VBox style)
     63 */
     64typedef struct virtq_desc
     65{
     66    uint64_t  pGcPhysBuf;                   /** addr        GC physical address of buffer   */
     67    uint32_t  cbBuf;                        /** len         Buffer length                   */
     68    uint16_t  fFlags;                       /** flags       Buffer specific flags           */
     69    uint16_t  uNext;                        /** next        Chain idx if VIRTIO_DESC_F_NEXT */
     70} VIRTQ_DESC_T, *PVIRTQ_DESC_T;
     71
     72typedef struct virtq_avail  /* VirtIO 1.0 specification formal name of this struct    */
     73{
     74    uint16_t  fFlags;                       /** flags       avail ring guest-to-host flags */
     75    uint16_t  uIdx;                         /** idx         Index of next free ring slot    */
     76    uint16_t  auRing[1];                    /** ring        Ring: avail guest-to-host bufs  */
     77    uint16_t  uUsedEventIdx;                /** used_event  (if VIRTQ_USED_F_NO_NOTIFY)     */
     78} VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T;
     79
     80typedef struct virtq_used_elem /* VirtIO 1.0 specification formal name of this struct */
     81{
     82    uint32_t  uIdx;                         /** idx         Start of used descriptor chain  */
     83    uint32_t  cbElem;                       /** len         Total len of used desc chain    */
     84} VIRTQ_USED_ELEM_T;
     85
     86typedef struct virt_used  /* VirtIO 1.0 specification formal name of this struct */
     87{
     88    uint16_t  fFlags;                       /** flags       used ring host-to-guest flags  */
     89    uint16_t  uIdx;                         /** idx         Index of next ring slot        */
     90    VIRTQ_USED_ELEM_T aRing[1];             /** ring        Ring: used host-to-guest bufs  */
     91    uint16_t  uAvailEventIdx;               /** avail_event if (VIRTQ_USED_F_NO_NOTIFY)    */
     92} VIRTQ_USED_T, *PVIRTQ_USED_T;
     93
     94
     95typedef struct virtq
     96{
     97    uint16_t cbQueue;                       /** virtq size                                 */
     98    uint16_t padding[3];                    /** 64-bit-align phys ptrs to start of struct  */
     99    RTGCPHYS pGcPhysVirtqDescriptors;       /** (struct virtq_desc  *)                     */
     100    RTGCPHYS pGcPhysVirtqAvail;             /** (struct virtq_avail *)                     */
     101    RTGCPHYS pGcPhysVirtqUsed;              /** (struct virtq_used  *)                     */
     102} VIRTQ, *PVIRTQ;
     103
     104typedef struct VQueue
     105{
     106    VIRTQ VirtQ;
     107    uint16_t  uNextAvailIndex;
     108    uint16_t  uNextUsedIndex;
     109    uint32_t  uPageNumber;
     110    R3PTRTYPE(const char *) pcszName;
     111} VQUEUE;
     112
     113
     114typedef VQUEUE *PVQUEUE;
     115
     116typedef struct VQueueElemSeg
     117{
     118    RTGCPHYS addr;
     119    void    *pv;
     120    uint32_t cb;
     121} VQUEUESEG;
     122
     123typedef struct VQueueElem
     124{
     125    uint32_t  idx;
     126    uint32_t  cSegsIn;
     127    uint32_t  cSegsOut;
     128    VQUEUESEG aSegsIn[VIRTQ_MAX_SIZE];
     129    VQUEUESEG aSegsOut[VIRTQ_MAX_SIZE];
     130} VQUEUEELEM;
     131typedef VQUEUEELEM *PVQUEUEELEM;
     132
     133/**
     134 * The following structure is used to pass the PCI parameters from the consumer
     135 * to this generic VirtIO framework
     136 */
    104137typedef struct VIRTIOPCIPARAMS
    105138{
     
    115148} VIRTIOPCIPARAMS, *PVIRTIOPCIPARAMS;
    116149
    117 typedef struct virtio_pci_cap
    118 {
    119     /* All little-endian */
    120     uint8_t   uCapVndr;               /** Generic PCI field: PCI_CAP_ID_VNDR          */
    121     uint8_t   uCapNext;               /** Generic PCI field: next ptr.                */
    122     uint8_t   uCapLen;                /** Generic PCI field: capability length        */
    123     uint8_t   uCfgType;               /** Identifies the structure.                   */
    124     uint8_t   uBar;                   /** Where to find it.                           */
    125     uint8_t   uPadding[3];            /** Pad to full dword.                          */
    126     uint32_t  uOffset;                /** Offset within bar.  (L.E.)                  */
    127     uint32_t  uLength;                /** Length of struct, in bytes. (L.E.)          */
    128 }  VIRTIO_PCI_CAP_T, *PVIRTIO_PCI_CAP_T;
    129 
    130 typedef struct virtio_pci_common_cfg /* VirtIO 1.0 specification name of this struct  */
    131 {
    132     /**
    133      *
    134      * RW = driver (guest) writes value into this field.
    135      * RO = device (host)  writes value into this field.
    136      */
    137 
    138     /* Per device fields */
    139     uint32_t  uDeviceFeaturesSelect;   /** RW (driver selects device features)         */
    140     uint32_t  uDeviceFeatures;         /** RO (device reports features to driver)      */
    141     uint32_t  uDriverFeaturesSelect;   /** RW (driver selects driver features)         */
    142     uint32_t  uDriverFeatures;         /** RW (driver accepts device features)         */
    143     uint16_t  uMsixConfig;            /** RW (driver sets MSI-X config vector)        */
    144     uint16_t  uNumQueues;             /** RO (device specifies max queues)            */
    145     uint8_t   uDeviceStatus;          /** RW (driver writes device status, 0 resets)  */
    146     uint8_t   uConfigGeneration;      /** RO (device changes when changing configs)   */
    147 
    148     /* Per virtqueue fields (as determined by uQueueSelect) */
    149     uint16_t  uQueueSelect;           /** RW (selects queue focus for these fields)   */
    150     uint16_t  uQueueSize;             /** RW (queue size, 0 - 2^n)                    */
    151     uint16_t  uQueueMsixVector;       /** RW (driver selects MSI-X queue vector)      */
    152     uint16_t  uQueueEnable;           /** RW (driver controls usability of queue)     */
    153     uint16_t  uQueueNotifyOff;        /** RO (offset uto virtqueue; see spec)         */
    154     uint64_t  uQueueDesc;             /** RW (driver writes desc table phys addr)     */
    155     uint64_t  uQueueAvail;            /** RW (driver writes avail ring phys addr)     */
    156     uint64_t  uQueueUsed;             /** RW (driver writes used ring  phys addr)     */
    157 } VIRTIO_PCI_COMMON_CFG_T, *PVIRTIO_PCI_COMMON_CFG_T;
    158 
    159 /* The following two types are opaque here. The device-specific capabilities are handled
    160  * through a callback to the consumer host device driver, where the corresponding
    161  * struct is declared, since it cannot be defined in the host-generic section of
    162  * the VirtIO specification. */
    163 
    164 typedef void * PVIRTIO_PCI_DEVICE_CAP_T;
    165 typedef struct virtio_pci_device_cap
    166 {
    167 } VIRTIO_PCI_DEVICE_CAP_T;
    168 
    169 typedef struct virtio_pci_notify_cap
    170 {
    171         struct virtio_pci_cap pciCap;
    172         uint32_t uNotifyOffMultiplier; /* notify_off_multiplier                        */
    173 } VIRTIO_PCI_NOTIFY_CAP_T, *PVIRTIO_PCI_NOTIFY_CAP_T;
    174 
    175 /*
    176  * If the client of this library has any device-specific capabilities, it must define
    177  * and implement this struct and the macro
    178  */
    179 typedef struct virtio_pci_cfg_cap {
    180         struct virtio_pci_cap pciCap;
    181         uint8_t uPciCfgData[4]; /* Data for BAR access. */
    182 } VIRTIO_PCI_CFG_CAP_T, *PVIRTIO_PCI_CFG_CAP_T;
    183 
    184 typedef struct virtq_desc  /* VirtIO 1.0 specification formal name of this struct     */
    185 {
    186     uint64_t  pGcPhysBuf;             /** addr        GC physical address of buffer   */
    187     uint32_t  cbBuf;                  /** len         Buffer length                   */
    188     uint16_t  fFlags;                 /** flags       Buffer specific flags           */
    189     uint16_t  uNext;                  /** next        Chain idx if VIRTIO_DESC_F_NEXT */
    190 } VIRTQUEUEDESC, *PVIRTQUEUEDESC;
    191 
    192 typedef struct virtq_avail  /* VirtIO 1.0 specification formal name of this struct    */
    193 {
    194     uint16_t  fFlags;                 /** flags       avail ring guest-to-host flags */
    195     uint16_t  uIdx;                   /** idx         Index of next free ring slot    */
    196     uint16_t  auRing[1];              /** ring        Ring: avail guest-to-host bufs  */
    197     uint16_t  uUsedEventIdx;          /** used_event  (if VIRTQ_USED_F_NO_NOTIFY)     */
    198 } VIRTQUEUEAVAIL, *PVIRTQUEUEAVAIL;
    199 
    200 typedef struct virtq_used_elem /* VirtIO 1.0 specification formal name of this struct */
    201 {
    202     uint32_t  uIdx;                   /** idx         Start of used descriptor chain  */
    203     uint32_t  cbElem;                 /** len         Total len of used desc chain    */
    204 } VIRTQUEUEUSEDELEM;
    205 
    206 typedef struct virt_used  /* VirtIO 1.0 specification formal name of this struct */
    207 {
    208     uint16_t  fFlags;                 /** flags       used ring host-to-guest flags  */
    209     uint16_t  uIdx;                   /** idx         Index of next ring slot        */
    210     VIRTQUEUEUSEDELEM aRing[1];       /** ring        Ring: used host-to-guest bufs  */
    211     uint16_t  uAvailEventIdx;         /** avail_event if (VIRTQ_USED_F_NO_NOTIFY)    */
    212 } VIRTQUEUEUSED, *PVIRTQUEUEUSED;
    213 
    214 
    215 typedef struct virtq
    216 {
    217     uint16_t cbQueue;                 /** virtq size                                 */
    218     uint16_t padding[3];              /** 64-bit-align phys ptrs to start of struct  */
    219     RTGCPHYS pGcPhysVirtqDescriptors; /** (struct virtq_desc  *)                     */
    220     RTGCPHYS pGcPhysVirtqAvail;       /** (struct virtq_avail *)                     */
    221     RTGCPHYS pGcPhysVirtqUsed;        /** (struct virtq_used  *)                     */
    222 } VIRTQUEUE, *PVIRTQUEUE;
    223 
    224 /**
    225  * Queue callback (consumer?).
    226  *
    227  * @param   pvState         Pointer to the VirtIO PCI core state, VIRTIOSTATE.
    228  * @param   pQueue          Pointer to the queue structure.
    229  */
    230 typedef DECLCALLBACK(void) FNVIRTIOQUEUECALLBACK(void *pvState, struct VQueue *pQueue);
    231 /** Pointer to a VQUEUE callback function. */
    232 typedef FNVIRTIOQUEUECALLBACK *PFNVIRTIOQUEUECALLBACK;
    233 
    234 //PCIDevGetCapabilityList
    235 //PCIDevSetCapabilityList
    236 //DECLINLINE(void) PDMPciDevSetCapabilityList(PPDMPCIDEV pPciDev, uint8_t u8Offset)
    237 //    PDMPciDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset);
    238 //DECLINLINE(uint8_t) PDMPciDevGetCapabilityList(PPDMPCIDEV pPciDev)
    239 //    return PDMPciDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST);
    240 
    241 typedef struct VQueue
    242 {
    243     VIRTQUEUE    VirtQueue;
    244     uint16_t uNextAvailIndex;
    245     uint16_t uNextUsedIndex;
    246     uint32_t uPageNumber;
    247     R3PTRTYPE(PFNVIRTIOQUEUECALLBACK) pfnCallback;
    248     R3PTRTYPE(const char *)           pcszName;
    249 } VQUEUE;
    250 typedef VQUEUE *PVQUEUE;
    251 
    252 typedef struct VQueueElemSeg
    253 {
    254     RTGCPHYS addr;
    255     void    *pv;
    256     uint32_t cb;
    257 } VQUEUESEG;
    258 
    259 typedef struct VQueueElem
    260 {
    261     uint32_t  idx;
    262     uint32_t  nIn;
    263     uint32_t  nOut;
    264     VQUEUESEG aSegsIn[VIRTQUEUE_MAX_SIZE];
    265     VQUEUESEG aSegsOut[VIRTQUEUE_MAX_SIZE];
    266 } VQUEUEELEM;
    267 typedef VQUEUEELEM *PVQUEUEELEM;
    268 
    269 
    270 /**
    271  * Interface this library uses to let the client handle VirtioIO device-specific capabilities I/O
    272  */
    273 
    274150 /**
    275151 * VirtIO Device-specific capabilities read callback
     
    304180     DECLCALLBACKMEMBER(int,      pfnVirtioDevCapWrite)
    305181                                      (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbWrite);
    306 } VIRTIOCALLBACKS, *PVIRTALCALLBACKS;
     182} VIRTIOCALLBACKS, *PVIRTIOCALLBACKS;
    307183/** @} */
    308184
    309 /**
    310  * The core (/common) state of the VirtIO PCI device
    311  *
    312  * @implements  PDMILEDPORTS
    313  */
    314 typedef struct VIRTIOSTATE
    315 {
    316     PDMPCIDEV                    dev;
    317     PDMCRITSECT                  cs;                     /**< Critical section - what is it protecting? */
    318     /* Read-only part, never changes after initialization. */
    319     char                         szInstance[8];          /**< Instance name, e.g. VNet#1. */
    320 
    321 #if HC_ARCH_BITS != 64
    322     uint32_t                     padding1;
    323 #endif
    324 
    325     /** Status LUN: Base interface. */
    326     PDMIBASE                     IBase;
    327 
    328     /** Status LUN: LED port interface. */
    329     PDMILEDPORTS                 ILed;
    330 
    331     /* Read/write part, protected with critical section. */
    332     /** Status LED. */
    333     PDMLED                       led;
    334 
    335     VIRTIOCALLBACKS              virtioCallbacks;
    336 
    337     /** Status LUN: LED connector (peer). */
    338     R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
    339 
    340     PPDMDEVINSR3                 pDevInsR3;              /**< Device instance - R3. */
    341     PPDMDEVINSR0                 pDevInsR0;              /**< Device instance - R0. */
    342     PPDMDEVINSRC                 pDevInsRC;              /**< Device instance - RC. */
    343 
    344 
    345     uint8_t                      uPciCfgDataOff;
    346 #if HC_ARCH_BITS == 64
    347     uint32_t                     padding2;
    348 #endif
    349 
    350     /** Base port of I/O space region. */
    351     RTIOPORT                     IOPortBase;
    352 
    353     uint32_t                     uGuestFeatures;
    354     uint16_t                     uQueueSelector;             /** An index in aQueues array. */
    355     uint8_t                      uStatus;                    /** Device Status (bits are device-specific). */
    356     uint8_t                      uISR;                       /** Interrupt Status Register. */
    357 
    358 #if HC_ARCH_BITS != 64
    359     uint32_t                     padding3;
    360 #endif
    361 
    362     uint32_t                     nQueues;                    /** Actual number of queues used. */
    363     VQUEUE                       Queues[VIRTIO_MAX_NQUEUES];
    364 
    365     uint32_t                     uDeviceFeaturesSelect;     /** Select hi/lo 32-bit uDeviceFeatures to r/w */
    366     uint64_t                     uDeviceFeatures;           /** Host features offered */
    367     uint32_t                     uDriverFeaturesSelect;     /** Selects hi/lo 32-bit uDriverFeatures to r/w*/
    368     uint64_t                     uDriverFeatures;           /** Host features accepted by guest */
    369 
    370     uint32_t                     uMsixConfig;
    371     uint8_t                      uDeviceStatus;
    372     uint8_t                      uConfigGeneration;
    373     uint32_t                     uNotifyOffMultiplier;       /* Multiplier for uQueueNotifyOff[idx] */
    374 
    375     uint16_t                     uQueueSelect;
    376     uint16_t                     uQueueSize[MAX_QUEUES];
    377     uint16_t                     uQueueMsixVector[MAX_QUEUES];
    378     uint16_t                     uQueueEnable[MAX_QUEUES];
    379     uint16_t                     uQueueNotifyOff[MAX_QUEUES];
    380     uint64_t                     uQueueDesc[MAX_QUEUES];
    381     uint64_t                     uQueueAvail[MAX_QUEUES];
    382     uint64_t                     uQueueUsed[MAX_QUEUES];
    383 
    384 
    385     uint8_t                      uVirtioCapRegion;      /* Client assigned  Virtio dedicated capabilities region*/
    386 
    387     /** Callbacks when guest driver reads or writes VirtIO device-specific capabilities(s) */
    388     PFNPCICONFIGREAD             pfnPciConfigReadOld;
    389     PFNPCICONFIGWRITE            pfnPciConfigWriteOld;
    390 
    391     bool                         fHaveDevSpecificCap;
    392     uint32_t                     cbDevSpecificCap;
    393 
    394     PVIRTIO_PCI_CFG_CAP_T        pPciCfgCap;            /** Pointer to struct in configuration area */
    395     PVIRTIO_PCI_NOTIFY_CAP_T     pNotifyCap;            /** Pointer to struct in configuration area */
    396     PVIRTIO_PCI_CAP_T            pCommonCfgCap;         /** Pointer to struct in configuration area */
    397     PVIRTIO_PCI_CAP_T            pIsrCap;               /** Pointer to struct in configuration area */
    398     PVIRTIO_PCI_CAP_T            pDeviceCap;            /** Pointer to struct in configuration area */
    399 
    400     /** Base address of PCI capabilities */
    401     RTGCPHYS                     GCPhysPciCapBase;
    402     RTGCPHYS                     pGcPhysCommonCfg;      /** Pointer to MMIO mapped capability data */
    403     RTGCPHYS                     pGcPhysNotifyCap;      /** Pointer to MMIO mapped capability data */
    404     RTGCPHYS                     pGcPhysIsrCap;         /** Pointer to MMIO mapped capability data */
    405     RTGCPHYS                     pGcPhysDeviceCap;      /** Pointer to MMIO mapped capability data */
    406 
    407     bool fDeviceConfigInterrupt;
    408     bool fQueueInterrupt;
    409 
    410 } VIRTIOSTATE, *PVIRTIOSTATE;
    411 
    412 void    virtioRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta);
    413 void   *virtioQueryInterface(struct PDMIBASE *pInterface, const char *pszIID);
    414 
    415 int     virtioConstruct(PPDMDEVINS pDevIns, PVIRTIOSTATE pVirtio, int iInstance, PVIRTIOPCIPARAMS pPciParams,
    416                     const char *pcszNameFmt, uint32_t nQueues, uint32_t uVirtioCapRegion,
    417                     PFNVIRTIODEVCAPREAD devCapReadCallback, PFNVIRTIODEVCAPWRITE devCapWriteCallback,
    418                     uint16_t cbDevSpecificCap, bool fHaveDevSpecificCap, uint32_t uNotifyOffMultiplier);
    419 
    420 int     virtioDestruct(PVIRTIOSTATE pVirtio);
    421 int     virtioReset(PVIRTIOSTATE pVirtio);
    422 int     virtioSaveExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM);
    423 int     virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t nQueues);
    424 void    virtioSetReadLed(PVIRTIOSTATE pVirtio, bool fOn);
    425 void    virtioSetWriteLed(PVIRTIOSTATE pVirtio, bool fOn);
    426 int     virtioRaiseInterrupt(PVIRTIOSTATE pVirtio, int rcBusy, uint8_t uint8_tIntCause);
    427 void    virtioNotify(PVIRTIOSTATE pVirtio);
    428 void    virtioSetHostFeatures(PVIRTIOSTATE pVirtio, uint64_t uDeviceFeatures);
    429 
    430 PVQUEUE virtioAddQueue(PVIRTIOSTATE pVirtio, unsigned uSize, PFNVIRTIOQUEUECALLBACK pfnCallback, const char *pcszName);
    431 bool    virtQueueSkip(PVIRTIOSTATE pVirtio, PVQUEUE pQueue);
    432 bool    virtQueueGet(PVIRTIOSTATE pVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove = true);
    433 void    virtQueuePut(PVIRTIOSTATE pVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t len, uint32_t uReserved = 0);
    434 void    virtQueueNotify(PVIRTIOSTATE pVirtio, PVQUEUE pQueue);
    435 void    virtQueueSync(PVIRTIOSTATE pVirtio, PVQUEUE pQueue);
    436 void    vringSetNotification( PVIRTIOSTATE pVirtio, PVIRTQUEUE pVirtQueue, bool fEnabled);
    437 
    438 
    439 /*  FROM Virtio 1.0 SPEC, NYI
    440       static inline int virtq_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old_idx)
    441             return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old_idx);
    442       }
    443       // Get location of event indices (only with VIRTIO_F_EVENT_IDX)
    444       static inline le16 *virtq_used_event(struct virtq *vq)
    445       {
    446               // For backwards compat, used event index is at *end* of avail ring.
    447               return &vq->avail->ring[vq->num];
    448 }
    449       static inline le16 *virtq_avail_event(struct virtq *vq)
    450       {
    451               // For backwards compat, avail event index is at *end* of used ring.
    452               return (le16 *)&vq->used->ring[vq->num];
    453       }
    454 }
    455 */
    456 
    457 
     185PVQUEUE virtioAddQueue(         VIRTIOHANDLE hVirtio, uint32_t uSize, const char *pcszName);
     186int     virtioDestruct(         VIRTIOHANDLE hVirtio);
     187int     virtioReset(            VIRTIOHANDLE hVirtio);
     188void    virtioSetReadLed(       VIRTIOHANDLE hVirtio, bool fOn);
     189void    virtioSetWriteLed(      VIRTIOHANDLE hVirtio, bool fOn);
     190int     virtioRaiseInterrupt(   VIRTIOHANDLE hVirtio, int rcBusy, uint8_t uint8_tIntCause);
     191//void    virtioNotifyDriver(     VIRTIOHANDLE hVirtio);
     192void    virtioSetHostFeatures(  VIRTIOHANDLE hVirtio, uint64_t uDeviceFeatures);
     193
     194bool    virtQueueSkip(          VIRTIOHANDLE hVirtio, PVQUEUE pQueue);
     195bool    virtQueueGet(           VIRTIOHANDLE hVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove = true);
     196void    virtQueuePut(           VIRTIOHANDLE hVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t len, uint32_t uReserved = 0);
     197void    virtQueueNotify(        VIRTIOHANDLE hVirtio, PVQUEUE pQueue);
     198void    virtQueueSync(          VIRTIOHANDLE hVirtio, PVQUEUE pQueue);
     199void    vringSetNotification(   VIRTIOHANDLE hVirtio, PVIRTQ pVirtQ, bool fEnabled);
    458200
    459201/**
     
    469211 * @param   idx         - The index if fHasIndex
    470212 */
    471 DECLINLINE(void) virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, const void *pv, uint32_t cb,
    472                         uint32_t uOffset, bool fWrite, bool fHasIndex, uint32_t idx)
    473 {
    474 
    475 #define FMTHEX(fmtout, v, cNybs) \
    476     fmtout[cNybs] = '\0'; \
    477     for (uint8_t i = 0; i < cNybs; i++) \
    478         fmtout[(cNybs - i) -1] = "0123456789abcdef"[(val >> (i * 4)) & 0xf];
    479 
    480 #define MAX_STRING   64
    481     char pszIdx[MAX_STRING] = { 0 };
    482     char pszDepiction[MAX_STRING] = { 0 };
    483     char pszFormattedVal[MAX_STRING] = { 0 };
    484     if (fHasIndex)
    485         RTStrPrintf(pszIdx, sizeof(pszIdx), "[%d]", idx);
    486     if (cb == 1 || cb == 2 || cb == 4 || cb == 8)
    487     {
    488         /* manually padding with 0's instead of \b due to different impl of %x precision than printf() */
    489         uint64_t val = 0;
    490         memcpy((char *)&val, pv, cb);
    491         FMTHEX(pszFormattedVal, val, cb * 2);
    492         if (uOffset != 0) /* display bounds if partial member access */
    493             RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s[%d:%d]", pszMember, pszIdx, uOffset, uOffset + cb - 1);
    494         else
    495             RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s", pszMember, pszIdx);
    496         RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%-30s", pszDepiction);
    497         int first = 0;
    498         for (uint8_t i = 0; i < sizeof(pszDepiction); i++)
    499             if (pszDepiction[i] == ' ' && first++ != 0)
    500                 pszDepiction[i] = '.';
    501         Log(("%s: Guest %s %s 0x%s\n", \
    502                   pszFunc, fWrite ? "wrote" : "read ", pszDepiction, pszFormattedVal));
    503     }
    504     else /* odd number or oversized access, ... log inline hex-dump style */
    505     {
    506         Log(("%s: Guest %s %s%s[%d:%d]: %.*Rhxs\n", \
    507               pszFunc, fWrite ? "wrote" : "read ", pszMember,
    508               pszIdx, uOffset, uOffset + cb, cb, pv));
    509     }
    510 }
    511 
    512 typedef DECLCALLBACK(uint32_t) FNGETHOSTFEATURES(void *pvState);
    513 typedef FNGETHOSTFEATURES *PFNGETHOSTFEATURES;
    514 
    515 DECLINLINE(uint16_t) vringReadAvail(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue)
    516 {
    517     uint16_t dataWord;
    518     PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    519                       pVirtQueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEAVAIL, uIdx),
    520                       &dataWord, sizeof(dataWord));
    521     return dataWord;
    522 }
    523 
    524 DECLINLINE(bool) virtQueuePeek(PVIRTIOSTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem)
    525 {
    526     return virtQueueGet(pState, pQueue, pElem, /* fRemove */ false);
    527 }
    528 
    529 DECLINLINE(bool) virtQueueIsReady(PVIRTIOSTATE pState, PVQUEUE pQueue)
    530 {
    531     NOREF(pState);
    532     return !!pQueue->VirtQueue.pGcPhysVirtqAvail;
    533 }
    534 
    535 DECLINLINE(bool) virtQueueIsEmpty(PVIRTIOSTATE pState, PVQUEUE pQueue)
    536 {
    537     return (vringReadAvail(pState, &pQueue->VirtQueue) == pQueue->uNextAvailIndex);
    538 }
     213void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember,
     214                            const void *pv, uint32_t cb, uint32_t uOffset,
     215                            bool fWrite, bool fHasIndex, uint32_t idx);
     216
     217int     virtioConstruct(
     218            PPDMDEVINS           pDevIns,
     219            PVIRTIOHANDLE        phVirtio,
     220            int                  iInstance,
     221            PVIRTIOPCIPARAMS     pPciParams,
     222            const char           *pcszNameFmt,
     223            uint32_t             nQueues,
     224            uint32_t             uVirtioCapBar,
     225            uint64_t             uDeviceFeatures,
     226            PFNVIRTIODEVCAPREAD  devCapReadCallback,
     227            PFNVIRTIODEVCAPWRITE devCapWriteCallback,
     228            uint16_t             cbDevSpecificCap,
     229            void                 *pDevSpecificCap,
     230            uint32_t             uNotifyOffMultiplier);
     231
     232//PCIDevGetCapabilityList
     233//PCIDevSetCapabilityList
     234//DECLINLINE(void) PDMPciDevSetCapabilityList(PPDMPCIDEV pPciDev, uint8_t u8Offset)
     235//    PDMPciDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset);
     236//DECLINLINE(uint8_t) PDMPciDevGetCapabilityList(PPDMPCIDEV pPciDev)
     237//    return PDMPciDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST);
    539238
    540239#endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_h */
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h

    r80169 r80194  
    2222#endif
    2323
     24#include "Virtio_1_0.h"
     25
     26
     27
     28/** @name Saved state versions.
     29 * The saved state version is changed if either common or any of specific
     30 * parts are changed. That is, it is perfectly possible that the version
     31 * of saved vnet state will increase as a result of change in vblk structure
     32 * for example.
     33 */
     34#define VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1 1
     35#define VIRTIO_SAVEDSTATE_VERSION           2
     36/** @} */
     37
     38#define DEVICE_PCI_VENDOR_ID_VIRTIO         0x1AF4  /** Mandatory, so VirtIO driver can find this device */
     39#define DEVICE_PCI_REVISION_ID_VIRTIO       1       /** Virtio spec suggests >= 1 for non-transitional drivers */
     40
     41
     42/**
     43 * The following is the PCI capability struct common to all VirtIO capability types
     44 */
     45#define VIRTIO_PCI_CAP_ID_VENDOR       0x09 /** Vendor-specific PCI CFG Device Capability ID */
     46
     47typedef struct virtio_pci_cap
     48{
     49    /* All little-endian */
     50    uint8_t   uCapVndr;                     /** Generic PCI field: PCI_CAP_ID_VNDR          */
     51    uint8_t   uCapNext;                     /** Generic PCI field: next ptr.                */
     52    uint8_t   uCapLen;                      /** Generic PCI field: capability length        */
     53    uint8_t   uCfgType;                     /** Identifies the structure.                   */
     54    uint8_t   uBar;                         /** Where to find it.                           */
     55    uint8_t   uPadding[3];                  /** Pad to full dword.                          */
     56    uint32_t  uOffset;                      /** Offset within bar.  (L.E.)                  */
     57    uint32_t  uLength;                      /** Length of struct, in bytes. (L.E.)          */
     58}  VIRTIO_PCI_CAP_T, *PVIRTIO_PCI_CAP_T;
     59
     60/**
     61 * The following structs correspond to the VirtIO capability types and describe
     62 * fields accessed by MMIO via the relevant BAR. virtio_pci_dev_cap is not listed
     63 * here because it is device specific, thus the device specific implementation
     64 * consumer of this framework passes a ref/size in the constructor
     65 *
     66 */
     67
     68/* Virtio Device PCI Capabilities type codes */
     69#define VIRTIO_PCI_CAP_COMMON_CFG      1    /** Common configuration PCI capability ID */
     70#define VIRTIO_PCI_CAP_NOTIFY_CFG      2    /** Notification area PCI capability ID */
     71#define VIRTIO_PCI_CAP_ISR_CFG         3    /** ISR PCI capability id */
     72#define VIRTIO_PCI_CAP_DEVICE_CFG      4    /** Device specific configuration PCI capability ID */
     73#define VIRTIO_PCI_CAP_PCI_CFG         5    /** PCI CFG capability ID */
     74
     75typedef struct virtio_pci_common_cfg /* VirtIO 1.0 specification name of this struct  */
     76{
     77    /* Per device fields */
     78    uint32_t  uDeviceFeaturesSelect;        /** RW (driver selects device features)         */
     79    uint32_t  uDeviceFeatures;              /** RO (device reports features to driver)      */
     80    uint32_t  uDriverFeaturesSelect;        /** RW (driver selects driver features)         */
     81    uint32_t  uDriverFeatures;              /** RW (driver accepts device features)         */
     82    uint16_t  uMsixConfig;                  /** RW (driver sets MSI-X config vector)        */
     83    uint16_t  uNumQueues;                   /** RO (device specifies max queues)            */
     84    uint8_t   uDeviceStatus;                /** RW (driver writes device status, 0 resets)  */
     85    uint8_t   uConfigGeneration;            /** RO (device changes when changing configs)   */
     86
     87    /* Per virtqueue fields (as determined by uQueueSelect) */
     88    uint16_t  uQueueSelect;                 /** RW (selects queue focus for these fields)   */
     89    uint16_t  uQueueSize;                   /** RW (queue size, 0 - 2^n)                    */
     90    uint16_t  uQueueMsixVector;             /** RW (driver selects MSI-X queue vector)      */
     91    uint16_t  uQueueEnable;                 /** RW (driver controls usability of queue)     */
     92    uint16_t  uQueueNotifyOff;              /** RO (offset uto virtqueue; see spec)         */
     93    uint64_t  uQueueDesc;                   /** RW (driver writes desc table phys addr)     */
     94    uint64_t  uQueueAvail;                  /** RW (driver writes avail ring phys addr)     */
     95    uint64_t  uQueueUsed;                   /** RW (driver writes used ring  phys addr)     */
     96} VIRTIO_PCI_COMMON_CFG_T, *PVIRTIO_PCI_COMMON_CFG_T;
     97
     98typedef struct virtio_pci_notify_cap
     99{
     100    struct virtio_pci_cap pciCap;
     101    uint32_t uNotifyOffMultiplier;          /* notify_off_multiplier                       */
     102} VIRTIO_PCI_NOTIFY_CAP_T, *PVIRTIO_PCI_NOTIFY_CAP_T;
     103
     104typedef struct virtio_pci_cfg_cap
     105{
     106    struct virtio_pci_cap pciCap;
     107    uint8_t uPciCfgData[4]; /* Data for BAR access. */
     108} VIRTIO_PCI_CFG_CAP_T, *PVIRTIO_PCI_CFG_CAP_T;
     109
     110/**
     111 * The core (/common) state of the VirtIO PCI device
     112 *
     113 * @implements  PDMILEDPORTS
     114 */
     115typedef struct VIRTIOSTATE
     116{
     117    PDMPCIDEV                    dev;
     118    PDMCRITSECT                  cs;                                    /**< Critical section - what is it protecting? */
     119    /* Read-only part, never changes after initialization. */
     120    char                         szInstance[8];                         /**< Instance name, e.g. VNet#1. */
     121
     122#if HC_ARCH_BITS != 64
     123    uint32_t                     padding1;
     124#endif
     125
     126    /** Status LUN: Base interface. */
     127    PDMIBASE                     IBase;
     128
     129    /** Status LUN: LED port interface. */
     130    PDMILEDPORTS                 ILed;
     131
     132    /* Read/write part, protected with critical section. */
     133    /** Status LED. */
     134    PDMLED                       led;
     135
     136    VIRTIOCALLBACKS              virtioCallbacks;
     137
     138    /** Status LUN: LED connector (peer). */
     139    R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
     140
     141    PPDMDEVINSR3                 pDevInsR3;                           /**< Device instance - R3. */
     142    PPDMDEVINSR0                 pDevInsR0;                           /**< Device instance - R0. */
     143    PPDMDEVINSRC                 pDevInsRC;                           /**< Device instance - RC. */
     144
     145
     146    uint8_t                      uPciCfgDataOff;
     147#if HC_ARCH_BITS == 64
     148    uint32_t                     padding2;
     149#endif
     150
     151    /** Base port of I/O space region. */
     152    RTIOPORT                     IOPortBase;
     153
     154    uint32_t                     uGuestFeatures;
     155    uint16_t                     uQueueSelector;                      /** An index in aQueues array. */
     156    uint8_t                      uStatus;                             /** Device Status (bits are device-specific). */
     157    uint8_t                      uISR;                                /** Interrupt Status Register. */
     158
     159#if HC_ARCH_BITS != 64
     160    uint32_t                     padding3;
     161#endif
     162
     163    VQUEUE                       Queues[VIRTIO_MAX_QUEUES];
     164    uint32_t                     uNotifyOffMultiplier;                /* Multiplier for uQueueNotifyOff[idx] */
     165
     166    /** Whole virtio device */
     167    uint32_t                     uDeviceFeaturesSelect;               /** Select hi/lo 32-bit uDeviceFeatures to r/w */
     168    uint64_t                     uDeviceFeatures;                     /** Host features offered */
     169    uint32_t                     uDriverFeaturesSelect;               /** Selects hi/lo 32-bit uDriverFeatures to r/w*/
     170    uint64_t                     uDriverFeatures;                     /** Host features accepted by guest */
     171    uint32_t                     uMsixConfig;
     172    uint32_t                     uNumQueues;                          /** Actual number of queues used. */
     173    uint8_t                      uDeviceStatus;
     174    uint8_t                      uConfigGeneration;
     175
     176    /** Specific virtqueue */
     177    uint16_t                     uQueueSelect;
     178    uint16_t                     uQueueSize[VIRTIO_MAX_QUEUES];       /** Device sets on reset, driver can modify */
     179    uint16_t                     uQueueNotifyOff[VIRTIO_MAX_QUEUES];  /** Device sets this */
     180    uint16_t                     uQueueMsixVector[VIRTIO_MAX_QUEUES]; /** Driver specifies queue vector for MSI-X */
     181    uint16_t                     uQueueEnable[VIRTIO_MAX_QUEUES];     /** Driver controls device access to queue */
     182    uint64_t                     uQueueDesc[VIRTIO_MAX_QUEUES];       /** Driver provides this */
     183    uint64_t                     uQueueAvail[VIRTIO_MAX_QUEUES];      /** Driver provides this */
     184    uint64_t                     uQueueUsed[VIRTIO_MAX_QUEUES];       /** Driver provides this */
     185
     186
     187    uint8_t                      uVirtioCapBar;                       /* Capabilities BAR (region) assigned by client */
     188
     189    /** Callbacks when guest driver reads or writes VirtIO device-specific capabilities(s) */
     190    PFNPCICONFIGREAD             pfnPciConfigReadOld;
     191    PFNPCICONFIGWRITE            pfnPciConfigWriteOld;
     192
     193    uint32_t                     cbDevSpecificCap;                    /* Size of client's dev-specific config data  */
     194    void                        *pDevSpecificCap;                     /* Pointer to client's struct                 */
     195    void                        *pPrevDevSpecificCap;                 /* Previous read dev-specific cfg of client */
     196    bool                         fGenUpdatePending;                   /* If set, update cfg gen. after driver reads */
     197
     198    PVIRTIO_PCI_CFG_CAP_T        pPciCfgCap;                          /** Pointer to struct in configuration area */
     199    PVIRTIO_PCI_NOTIFY_CAP_T     pNotifyCap;                          /** Pointer to struct in configuration area */
     200    PVIRTIO_PCI_CAP_T            pCommonCfgCap;                       /** Pointer to struct in configuration area */
     201    PVIRTIO_PCI_CAP_T            pIsrCap;                             /** Pointer to struct in configuration area */
     202    PVIRTIO_PCI_CAP_T            pDeviceCap;                          /** Pointer to struct in configuration area */
     203
     204    /** Base address of PCI capabilities */
     205    RTGCPHYS                     GCPhysPciCapBase;
     206    RTGCPHYS                     pGcPhysCommonCfg;                    /** Pointer to MMIO mapped capability data */
     207    RTGCPHYS                     pGcPhysNotifyCap;                    /** Pointer to MMIO mapped capability data */
     208    RTGCPHYS                     pGcPhysIsrCap;                       /** Pointer to MMIO mapped capability data */
     209    RTGCPHYS                     pGcPhysDeviceCap;                    /** Pointer to MMIO mapped capability data */
     210
     211    bool fDeviceConfigInterrupt;
     212    bool fQueueInterrupt;
     213
     214} VIRTIOSTATE, *PVIRTIOSTATE;
     215
     216DECLINLINE(uint16_t) vringReadAvail(PVIRTIOSTATE pVirtio, PVIRTQ pVirtQ)
     217{
     218    uint16_t dataWord;
     219    PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
     220                      pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),
     221                      &dataWord, sizeof(dataWord));
     222    return dataWord;
     223}
     224
     225DECLINLINE(bool) virtQueuePeek(PVIRTIOSTATE pVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem)
     226{
     227    return virtQueueGet(pVirtio, pQueue, pElem, /* fRemove */ false);
     228}
     229
     230DECLINLINE(bool) virtQueueIsReady(PVIRTIOSTATE pVirtio, PVQUEUE pQueue)
     231{
     232    NOREF(pVirtio);
     233    return !!pQueue->VirtQ.pGcPhysVirtqAvail;
     234}
     235
     236DECLINLINE(bool) virtQueueIsEmpty(PVIRTIOSTATE pVirtio, PVQUEUE pQueue)
     237{
     238    return (vringReadAvail(pVirtio, &pQueue->VirtQ) == pQueue->uNextAvailIndex);
     239}
    24240/**
    25241* This macro returns true if physical address and access length are within the mapped capability struct.
     
    146362}
    147363
     364/*  FROM Virtio 1.0 SPEC, NYI
     365      static inline int virtq_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old_idx)
     366            return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old_idx);
     367      }
     368      // Get location of event indices (only with VIRTIO_F_EVENT_IDX)
     369      static inline le16 *virtq_used_event(struct virtq *vq)
     370      {
     371              // For backwards compat, used event index is at *end* of avail ring.
     372              return &vq->avail->ring[vq->num];
     373}
     374      static inline le16 *virtq_avail_event(struct virtq *vq)
     375      {
     376              // For backwards compat, avail event index is at *end* of used ring.
     377              return (le16 *)&vq->used->ring[vq->num];
     378      }
     379}
     380*/
     381void    virtioRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta);
     382void   *virtioQueryInterface(struct PDMIBASE *pInterface, const char *pszIID);
     383int     virtioSaveExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM);
     384int     virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t uNumQueues);
     385
    148386#endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_impl_h */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette