VirtualBox

Changeset 81135 in vbox for trunk/src/VBox/Devices/PC


Ignore:
Timestamp:
Oct 8, 2019 8:19:38 AM (5 years ago)
Author:
vboxsync
Message:

BIOS/virtio.c: Updates, can submit requests to the device now

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/BIOS/virtio.c

    r81129 r81135  
    3131#endif
    3232
     33#define SCSI_INQUIRY       0x12
     34
    3335/* The maximum CDB size. */
    3436#define VIRTIO_SCSI_CDB_SZ      16
    3537/** Maximum sense data to return. */
    3638#define VIRTIO_SCSI_SENSE_SZ    32
     39
     40#define VIRTIO_SCSI_RING_ELEM    3
    3741
    3842/**
     
    6670    uint16_t        idxNextFree;
    6771    /** The ring - we only provide one entry. */
    68     uint16_t        au16Ring[1];
     72    uint16_t        au16Ring[VIRTIO_SCSI_RING_ELEM];
    6973    /** Used event index. */
    7074    uint16_t        u16EvtUsed;
     
    8892{
    8993    /** Flags. */
    90     uint16_t             fFlags;
     94    volatile uint16_t    fFlags;
    9195    /** Index where the next entry would be written by the device. */
    92     uint16_t             idxNextUsed;
     96    volatile uint16_t    idxNextUsed;
    9397    /** The used ring. */
    94     virtio_q_used_elem_t aRing[1];
     98    virtio_q_used_elem_t aRing[VIRTIO_SCSI_RING_ELEM];
    9599} virtio_q_used_t;
    96100
     
    106110    /** Used ring. */
    107111    virtio_q_used_t      UsedRing;
     112    /** The notification offset for the queue. */
     113    uint32_t             offNotify;
    108114} virtio_q_t;
    109115
     
    198204     * capability for the alternate access method to the registers. */
    199205    uint8_t          u8PciCfgOff;
     206    /** The notification offset multiplier. */
     207    uint32_t         u32NotifyOffMult;
    200208    /** PCI bus where the device is located. */
    201209    uint8_t          u8Bus;
     
    204212    /** Saved high bits of EAX. */
    205213    uint16_t         saved_eax_hi;
     214    /** The current executed command structure. */
     215    virtio_scsi_req_hdr_t ScsiReqHdr;
     216    virtio_scsi_req_sts_t ScsiReqSts;
    206217} virtio_t;
    207218
     
    295306}
    296307
    297 static void virtio_reg_set_bar_offset_length(virtio_t __far *virtio, uint8_t u8Bar, uint32_t offReg, uint8_t cb)
     308static void virtio_reg_set_bar_offset_length(virtio_t __far *virtio, uint8_t u8Bar, uint32_t offReg, uint32_t cb)
    298309{
    299310    pci_write_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff  +  4, u8Bar);
    300311    pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff +  8, offReg);
    301     pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 12, (uint32_t)cb);
    302 }
    303 
    304 static void virtio_reg_common_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint16_t cbAcc)
     312    pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 12, cb);
     313}
     314
     315static void virtio_reg_common_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc)
    305316{
    306317    virtio_reg_set_bar_offset_length(virtio,
     
    310321}
    311322
    312 static void virtio_reg_dev_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint16_t cbAcc)
     323static void virtio_reg_dev_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc)
    313324{
    314325    virtio_reg_set_bar_offset_length(virtio,
     
    318329}
    319330
     331static void virtio_reg_notify_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc)
     332{
     333    virtio_reg_set_bar_offset_length(virtio,
     334                                     virtio->aBarCfgs[VIRTIO_PCI_CAP_NOTIFY_CFG - 1].u8Bar,
     335                                     virtio->aBarCfgs[VIRTIO_PCI_CAP_NOTIFY_CFG - 1].u32Offset + offReg,
     336                                     cbAcc);
     337}
     338
    320339static uint8_t virtio_reg_common_read_u8(virtio_t __far *virtio, uint16_t offReg)
    321340{
     
    372391}
    373392
     393static void virtio_reg_notify_write_u16(virtio_t __far *virtio, uint16_t offReg, uint16_t u16Val)
     394{
     395    virtio_reg_notify_access_prepare(virtio, offReg, sizeof(uint16_t));
     396    pci_write_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u16Val);
     397}
     398
    374399/**
    375400 * Allocates 1K of conventional memory.
     
    401426{
    402427    return ((uint32_t)FP_SEG(ptr) << 4) + FP_OFF(ptr);
     428}
     429
     430int virtio_scsi_cmd_data_in(virtio_t __far *virtio, uint8_t idTgt, uint8_t __far *aCDB,
     431                            uint8_t cbCDB, uint8_t __far *buffer, uint32_t length)
     432{
     433    uint16_t idxUsedOld = virtio->Queue.UsedRing.idxNextUsed;
     434
     435    _fmemset(&virtio->ScsiReqHdr, 0, sizeof(virtio->ScsiReqHdr));
     436    _fmemset(&virtio->ScsiReqSts, 0, sizeof(virtio->ScsiReqSts));
     437
     438    virtio->ScsiReqHdr.au8Lun[0] = 0x1;
     439    virtio->ScsiReqHdr.au8Lun[1] = idTgt;
     440    virtio->ScsiReqHdr.au8Lun[2] = 0;
     441    virtio->ScsiReqHdr.au8Lun[3] = 0;
     442    _fmemcpy(&virtio->ScsiReqHdr.abCdb[0], aCDB, cbCDB);
     443
     444    /* Fill in the descriptors. */
     445    virtio->Queue.aDescTbl[0].GCPhysBufLow  = virtio_addr_to_phys(&virtio->ScsiReqHdr);
     446    virtio->Queue.aDescTbl[0].GCPhysBufHigh = 0;
     447    virtio->Queue.aDescTbl[0].cbBuf         = sizeof(virtio->ScsiReqHdr);
     448    virtio->Queue.aDescTbl[0].fFlags        = VIRTIO_Q_DESC_F_NEXT;
     449    virtio->Queue.aDescTbl[0].idxNext       = 1;
     450
     451    /* No data out buffer, the status comes right after this in the next descriptor. */
     452    virtio->Queue.aDescTbl[1].GCPhysBufLow  = virtio_addr_to_phys(&virtio->ScsiReqSts);
     453    virtio->Queue.aDescTbl[1].GCPhysBufHigh = 0;
     454    virtio->Queue.aDescTbl[1].cbBuf         = sizeof(virtio->ScsiReqHdr);
     455    virtio->Queue.aDescTbl[1].fFlags        = VIRTIO_Q_DESC_F_WRITE | VIRTIO_Q_DESC_F_NEXT;
     456    virtio->Queue.aDescTbl[1].idxNext       = 2;
     457
     458    virtio->Queue.aDescTbl[2].GCPhysBufLow  = virtio_addr_to_phys(buffer);
     459    virtio->Queue.aDescTbl[2].GCPhysBufHigh = 0;
     460    virtio->Queue.aDescTbl[2].cbBuf         = length;
     461    virtio->Queue.aDescTbl[2].fFlags        = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */
     462    virtio->Queue.aDescTbl[2].idxNext       = 0;
     463
     464    /* Put it into the queue. */
     465    virtio->Queue.AvailRing.au16Ring[virtio->Queue.AvailRing.idxNextFree] = 0;
     466    virtio->Queue.AvailRing.idxNextFree++;
     467    virtio->Queue.AvailRing.idxNextFree %= VIRTIO_SCSI_RING_ELEM;
     468
     469    /* Notify the device about the new command. */
     470    DBG_VIRTIO("VirtIO: Submitting new request, Queue.offNotify=0x%x\n", virtio->Queue.offNotify);
     471    virtio_reg_notify_write_u16(virtio, virtio->Queue.offNotify, 0);
     472
     473    /* Wait for it to complete. */
     474    while (idxUsedOld == virtio->Queue.UsedRing.idxNextUsed);
     475
     476    DBG_VIRTIO("VirtIO: Request complete\n");
     477
     478    return 0;
     479}
     480
     481static int virtio_scsi_detect_devices(virtio_t __far *virtio)
     482{
     483    uint8_t     buffer[0x0200];
     484    uint8_t     rc;
     485    uint8_t     aCDB[16];
     486
     487    aCDB[0] = SCSI_INQUIRY;
     488    aCDB[1] = 0;
     489    aCDB[2] = 0;
     490    aCDB[3] = 0;
     491    aCDB[4] = 5; /* Allocation length. */
     492    aCDB[5] = 0;
     493
     494    rc = virtio_scsi_cmd_data_in(virtio, 0, aCDB, 6, buffer, 5);
     495    if (rc != 0)
     496        BX_PANIC("%s: SCSI_INQUIRY failed\n", __func__);
     497
     498    return rc;
    403499}
    404500
     
    467563                    pBarCfg->u32Offset = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 8);
    468564                    pBarCfg->u32Length = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 12);
     565                    if (u8PciVirtioCfg == VIRTIO_PCI_CAP_NOTIFY_CFG)
     566                    {
     567                        virtio->u32NotifyOffMult = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 16);
     568                        DBG_VIRTIO("VirtIO: u32NotifyOffMult 0x%x\n", virtio->u32NotifyOffMult);
     569                    }
    469570                    break;
    470571                }
     
    529630    /* Setup the request queue. */
    530631    virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SELECT, VIRTIO_SCSI_Q_REQUEST);
    531     virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, 1);
     632    virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, VIRTIO_SCSI_RING_ELEM);
    532633    virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 1);
    533634
     
    545646    virtio_reg_dev_cfg_write_u32(virtio, VIRTIO_DEV_CFG_REG_SENSE_SZ, VIRTIO_SCSI_SENSE_SZ);
    546647
     648    DBG_VIRTIO("VirtIO: Q notify offset 0x%x\n", virtio_reg_common_read_u16(virtio, VIRTIO_COMMON_REG_Q_NOTIFY_OFF));
     649    virtio->Queue.offNotify = virtio_reg_common_read_u16(virtio, VIRTIO_COMMON_REG_Q_NOTIFY_OFF) * virtio->u32NotifyOffMult;
     650
    547651    /* Bring the device into operational mode. */
    548652    u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_DRV_OK;
    549653    virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
    550654
    551     /** @todo Detect attached devices. */
    552 
    553     return 0;
     655    return virtio_scsi_detect_devices(virtio);
    554656}
    555657
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