Changeset 81135 in vbox for trunk/src/VBox/Devices/PC
- Timestamp:
- Oct 8, 2019 8:19:38 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/BIOS/virtio.c
r81129 r81135 31 31 #endif 32 32 33 #define SCSI_INQUIRY 0x12 34 33 35 /* The maximum CDB size. */ 34 36 #define VIRTIO_SCSI_CDB_SZ 16 35 37 /** Maximum sense data to return. */ 36 38 #define VIRTIO_SCSI_SENSE_SZ 32 39 40 #define VIRTIO_SCSI_RING_ELEM 3 37 41 38 42 /** … … 66 70 uint16_t idxNextFree; 67 71 /** The ring - we only provide one entry. */ 68 uint16_t au16Ring[ 1];72 uint16_t au16Ring[VIRTIO_SCSI_RING_ELEM]; 69 73 /** Used event index. */ 70 74 uint16_t u16EvtUsed; … … 88 92 { 89 93 /** Flags. */ 90 uint16_tfFlags;94 volatile uint16_t fFlags; 91 95 /** Index where the next entry would be written by the device. */ 92 uint16_tidxNextUsed;96 volatile uint16_t idxNextUsed; 93 97 /** The used ring. */ 94 virtio_q_used_elem_t aRing[ 1];98 virtio_q_used_elem_t aRing[VIRTIO_SCSI_RING_ELEM]; 95 99 } virtio_q_used_t; 96 100 … … 106 110 /** Used ring. */ 107 111 virtio_q_used_t UsedRing; 112 /** The notification offset for the queue. */ 113 uint32_t offNotify; 108 114 } virtio_q_t; 109 115 … … 198 204 * capability for the alternate access method to the registers. */ 199 205 uint8_t u8PciCfgOff; 206 /** The notification offset multiplier. */ 207 uint32_t u32NotifyOffMult; 200 208 /** PCI bus where the device is located. */ 201 209 uint8_t u8Bus; … … 204 212 /** Saved high bits of EAX. */ 205 213 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; 206 217 } virtio_t; 207 218 … … 295 306 } 296 307 297 static void virtio_reg_set_bar_offset_length(virtio_t __far *virtio, uint8_t u8Bar, uint32_t offReg, uint 8_t cb)308 static void virtio_reg_set_bar_offset_length(virtio_t __far *virtio, uint8_t u8Bar, uint32_t offReg, uint32_t cb) 298 309 { 299 310 pci_write_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 4, u8Bar); 300 311 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, uint 16_t cbAcc)312 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 12, cb); 313 } 314 315 static void virtio_reg_common_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc) 305 316 { 306 317 virtio_reg_set_bar_offset_length(virtio, … … 310 321 } 311 322 312 static void virtio_reg_dev_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint 16_t cbAcc)323 static void virtio_reg_dev_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc) 313 324 { 314 325 virtio_reg_set_bar_offset_length(virtio, … … 318 329 } 319 330 331 static 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 320 339 static uint8_t virtio_reg_common_read_u8(virtio_t __far *virtio, uint16_t offReg) 321 340 { … … 372 391 } 373 392 393 static 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 374 399 /** 375 400 * Allocates 1K of conventional memory. … … 401 426 { 402 427 return ((uint32_t)FP_SEG(ptr) << 4) + FP_OFF(ptr); 428 } 429 430 int 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 481 static 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; 403 499 } 404 500 … … 467 563 pBarCfg->u32Offset = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 8); 468 564 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 } 469 570 break; 470 571 } … … 529 630 /* Setup the request queue. */ 530 631 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); 532 633 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 1); 533 634 … … 545 646 virtio_reg_dev_cfg_write_u32(virtio, VIRTIO_DEV_CFG_REG_SENSE_SZ, VIRTIO_SCSI_SENSE_SZ); 546 647 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 547 651 /* Bring the device into operational mode. */ 548 652 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_DRV_OK; 549 653 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat); 550 654 551 /** @todo Detect attached devices. */ 552 553 return 0; 655 return virtio_scsi_detect_devices(virtio); 554 656 } 555 657
Note:
See TracChangeset
for help on using the changeset viewer.