Changeset 81129 in vbox for trunk/src/VBox
- Timestamp:
- Oct 7, 2019 1:41:26 PM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 133761
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/BIOS/virtio.c
r81090 r81129 30 30 # define DBG_VIRTIO(...) 31 31 #endif 32 33 /* The maximum CDB size. */ 34 #define VIRTIO_SCSI_CDB_SZ 16 35 /** Maximum sense data to return. */ 36 #define VIRTIO_SCSI_SENSE_SZ 32 37 38 /** 39 * VirtIO queue descriptor. 40 */ 41 typedef struct 42 { 43 /** 64bit guest physical address of the buffer, split into high and low part because we work in real mode. */ 44 uint32_t GCPhysBufLow; 45 uint32_t GCPhysBufHigh; 46 /** Length of the buffer in bytes. */ 47 uint32_t cbBuf; 48 /** Flags for the buffer. */ 49 uint16_t fFlags; 50 /** Next field where the buffer is continued if _NEXT flag is set. */ 51 uint16_t idxNext; 52 } virtio_q_desc_t; 53 54 #define VIRTIO_Q_DESC_F_NEXT 0x1 55 #define VIRTIO_Q_DESC_F_WRITE 0x2 56 #define VIRTIO_Q_DESC_F_INDIRECT 0x4 57 58 /** 59 * VirtIO available ring. 60 */ 61 typedef struct 62 { 63 /** Flags. */ 64 uint16_t fFlags; 65 /** Next index to write an available buffer by the driver. */ 66 uint16_t idxNextFree; 67 /** The ring - we only provide one entry. */ 68 uint16_t au16Ring[1]; 69 /** Used event index. */ 70 uint16_t u16EvtUsed; 71 } virtio_q_avail_t; 72 73 /** 74 * VirtIO queue used element. 75 */ 76 typedef struct 77 { 78 /** Index of the start of the descriptor chain. */ 79 uint32_t u32Id; 80 /** Number of bytes used in the descriptor chain. */ 81 uint32_t cbUsed; 82 } virtio_q_used_elem_t; 83 84 /** 85 * VirtIo used ring. 86 */ 87 typedef struct 88 { 89 /** Flags. */ 90 uint16_t fFlags; 91 /** Index where the next entry would be written by the device. */ 92 uint16_t idxNextUsed; 93 /** The used ring. */ 94 virtio_q_used_elem_t aRing[1]; 95 } virtio_q_used_t; 96 97 /** 98 * VirtIO queue structure we are using, needs to be aligned on a 16byte boundary. 99 */ 100 typedef struct 101 { 102 /** The descriptor table, using 4 max. */ 103 virtio_q_desc_t aDescTbl[4]; 104 /** Available ring. */ 105 virtio_q_avail_t AvailRing; 106 /** Used ring. */ 107 virtio_q_used_t UsedRing; 108 } virtio_q_t; 109 110 /** 111 * VirtIO SCSI request structure passed in the queue. 112 */ 113 typedef struct 114 { 115 /** The LUN to address. */ 116 uint8_t au8Lun[8]; 117 /** Request ID - split into low and high part. */ 118 uint32_t u32IdLow; 119 uint32_t u32IdHigh; 120 /** Task attributes. */ 121 uint8_t u8TaskAttr; 122 /** Priority. */ 123 uint8_t u8Prio; 124 /** CRN value, usually 0. */ 125 uint8_t u8Crn; 126 /** The CDB. */ 127 uint8_t abCdb[VIRTIO_SCSI_CDB_SZ]; 128 } virtio_scsi_req_hdr_t; 129 130 /** 131 * VirtIO SCSI status structure filled by the device. 132 */ 133 typedef struct 134 { 135 /** Returned sense length. */ 136 uint32_t cbSense; 137 /** Residual amount of bytes left. */ 138 uint32_t cbResidual; 139 /** Status qualifier. */ 140 uint16_t u16StatusQual; 141 /** Status code. */ 142 uint8_t u8Status; 143 /** Response code. */ 144 uint8_t u8Response; 145 /** Sense data. */ 146 uint8_t abSense[VIRTIO_SCSI_SENSE_SZ]; 147 } virtio_scsi_req_sts_t; 148 149 /** 150 * VirtIO config for the different data structures. 151 */ 152 typedef struct 153 { 154 /** BAR where to find it. */ 155 uint8_t u8Bar; 156 /** Padding. */ 157 uint8_t abPad[3]; 158 /** Offset within the bar. */ 159 uint32_t u32Offset; 160 /** Length of the structure in bytes. */ 161 uint32_t u32Length; 162 } virtio_bar_cfg_t; 32 163 33 164 /** … … 55 186 56 187 /** 57 * VirtIO config for the different data structures.58 */59 typedef struct60 {61 /** BAR where to find it. */62 uint8_t u8Bar;63 /** Padding. */64 uint8_t abPad[3];65 /** Offset within the bar. */66 uint32_t u32Offset;67 /** Length of the structure in bytes. */68 uint32_t u32Length;69 } virtio_bar_cfg_t;70 71 /**72 188 * VirtIO-SCSI controller data. 73 189 */ 74 190 typedef struct 75 191 { 192 /** The queue used - must be first for alignment reasons. */ 193 virtio_q_t Queue; 76 194 /** The BAR configs read from the PCI configuration space, see VIRTIO_PCI_CAP_*_CFG, 77 195 * only use 4 because VIRTIO_PCI_CAP_PCI_CFG is not part of this. */ … … 88 206 } virtio_t; 89 207 90 /* The AHCIspecific data must fit into 1KB (statically allocated). */208 /* The VirtIO specific data must fit into 1KB (statically allocated). */ 91 209 ct_assert(sizeof(virtio_t) <= 1024); 92 210 … … 107 225 #define RT_BIT_32(bit) ((uint32_t)(1L << (bit))) 108 226 109 /* Warning: Destroys high bits of EAX. */ 110 uint32_t inpd(uint16_t port); 111 #pragma aux inpd = \ 112 ".386" \ 113 "in eax, dx" \ 114 "mov dx, ax" \ 115 "shr eax, 16" \ 116 "xchg ax, dx" \ 117 parm [dx] value [dx ax] modify nomemory; 118 119 /* Warning: Destroys high bits of EAX. */ 120 void outpd(uint16_t port, uint32_t val); 121 #pragma aux outpd = \ 122 ".386" \ 123 "xchg ax, cx" \ 124 "shl eax, 16" \ 125 "mov ax, cx" \ 126 "out dx, eax" \ 127 parm [dx] [cx ax] modify nomemory; 128 227 #define VIRTIO_COMMON_REG_DEV_FEAT_SLCT 0x00 228 #define VIRTIO_COMMON_REG_DEV_FEAT 0x04 229 # define VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT 0x01 230 #define VIRTIO_COMMON_REG_DRV_FEAT_SLCT 0x08 231 #define VIRTIO_COMMON_REG_DRV_FEAT 0x0c 232 #define VIRTIO_COMMON_REG_MSIX_CFG 0x10 233 #define VIRTIO_COMMON_REG_NUM_QUEUES 0x12 234 #define VIRTIO_COMMON_REG_DEV_STS 0x14 235 # define VIRTIO_CMN_REG_DEV_STS_F_RST 0x00 236 # define VIRTIO_CMN_REG_DEV_STS_F_ACK 0x01 237 # define VIRTIO_CMN_REG_DEV_STS_F_DRV 0x02 238 # define VIRTIO_CMN_REG_DEV_STS_F_DRV_OK 0x04 239 # define VIRTIO_CMN_REG_DEV_STS_F_FEAT_OK 0x08 240 # define VIRTIO_CMN_REG_DEV_STS_F_DEV_RST 0x40 241 # define VIRTIO_CMN_REG_DEV_STS_F_FAILED 0x80 242 #define VIRTIO_COMMON_REG_CFG_GEN 0x15 243 244 #define VIRTIO_COMMON_REG_Q_SELECT 0x16 245 #define VIRTIO_COMMON_REG_Q_SIZE 0x18 246 #define VIRTIO_COMMON_REG_Q_MSIX_VEC 0x1a 247 #define VIRTIO_COMMON_REG_Q_ENABLE 0x1c 248 #define VIRTIO_COMMON_REG_Q_NOTIFY_OFF 0x1e 249 #define VIRTIO_COMMON_REG_Q_DESC 0x20 250 #define VIRTIO_COMMON_REG_Q_DRIVER 0x28 251 #define VIRTIO_COMMON_REG_Q_DEVICE 0x30 252 253 #define VIRTIO_DEV_CFG_REG_Q_NUM 0x00 254 #define VIRTIO_DEV_CFG_REG_SEG_MAX 0x04 255 #define VIRTIO_DEV_CFG_REG_SECT_MAX 0x08 256 #define VIRTIO_DEV_CFG_REG_CMD_PER_LUN 0x0c 257 #define VIRTIO_DEV_CFG_REG_EVT_INFO_SZ 0x10 258 #define VIRTIO_DEV_CFG_REG_SENSE_SZ 0x14 259 #define VIRTIO_DEV_CFG_REG_CDB_SZ 0x18 260 #define VIRTIO_DEV_CFG_REG_MAX_CHANNEL 0x1c 261 #define VIRTIO_DEV_CFG_REG_MAX_TGT 0x1e 262 #define VIRTIO_DEV_CFG_REG_MAX_LUN 0x20 263 264 #define VIRTIO_SCSI_Q_CONTROL 0x00 265 #define VIRTIO_SCSI_Q_EVENT 0x01 266 #define VIRTIO_SCSI_Q_REQUEST 0x02 129 267 130 268 /* Machinery to save/restore high bits of EAX. 32-bit port I/O needs to use … … 157 295 } 158 296 297 static void virtio_reg_set_bar_offset_length(virtio_t __far *virtio, uint8_t u8Bar, uint32_t offReg, uint8_t cb) 298 { 299 pci_write_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 4, u8Bar); 300 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) 305 { 306 virtio_reg_set_bar_offset_length(virtio, 307 virtio->aBarCfgs[VIRTIO_PCI_CAP_COMMON_CFG - 1].u8Bar, 308 virtio->aBarCfgs[VIRTIO_PCI_CAP_COMMON_CFG - 1].u32Offset + offReg, 309 cbAcc); 310 } 311 312 static void virtio_reg_dev_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint16_t cbAcc) 313 { 314 virtio_reg_set_bar_offset_length(virtio, 315 virtio->aBarCfgs[VIRTIO_PCI_CAP_DEVICE_CFG - 1].u8Bar, 316 virtio->aBarCfgs[VIRTIO_PCI_CAP_DEVICE_CFG - 1].u32Offset + offReg, 317 cbAcc); 318 } 319 320 static uint8_t virtio_reg_common_read_u8(virtio_t __far *virtio, uint16_t offReg) 321 { 322 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint8_t)); 323 return pci_read_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t)); 324 } 325 326 static void virtio_reg_common_write_u8(virtio_t __far *virtio, uint16_t offReg, uint8_t u8Val) 327 { 328 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint8_t)); 329 pci_write_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u8Val); 330 } 331 332 static uint16_t virtio_reg_common_read_u16(virtio_t __far *virtio, uint16_t offReg) 333 { 334 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint16_t)); 335 return pci_read_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t)); 336 } 337 338 static void virtio_reg_common_write_u16(virtio_t __far *virtio, uint16_t offReg, uint16_t u16Val) 339 { 340 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint16_t)); 341 pci_write_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u16Val); 342 } 343 344 static uint32_t virtio_reg_common_read_u32(virtio_t __far *virtio, uint16_t offReg) 345 { 346 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint32_t)); 347 return pci_read_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t)); 348 } 349 350 static void virtio_reg_common_write_u32(virtio_t __far *virtio, uint16_t offReg, uint32_t u32Val) 351 { 352 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint32_t)); 353 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u32Val); 354 } 355 356 static uint16_t virtio_reg_dev_cfg_read_u16(virtio_t __far *virtio, uint16_t offReg) 357 { 358 virtio_reg_dev_access_prepare(virtio, offReg, sizeof(uint16_t)); 359 return pci_read_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t)); 360 } 361 362 static uint32_t virtio_reg_dev_cfg_read_u32(virtio_t __far *virtio, uint16_t offReg) 363 { 364 virtio_reg_dev_access_prepare(virtio, offReg, sizeof(uint32_t)); 365 return pci_read_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t)); 366 } 367 368 static void virtio_reg_dev_cfg_write_u32(virtio_t __far *virtio, uint16_t offReg, uint32_t u32Val) 369 { 370 virtio_reg_dev_access_prepare(virtio, offReg, sizeof(uint32_t)); 371 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u32Val); 372 } 373 159 374 /** 160 375 * Allocates 1K of conventional memory. … … 167 382 base_mem_kb = read_word(0x00, 0x0413); 168 383 169 DBG_VIRTIO(" AHCI: %dK of base mem\n", base_mem_kb);384 DBG_VIRTIO("VirtIO: %dK of base mem\n", base_mem_kb); 170 385 171 386 if (base_mem_kb == 0) … … 178 393 179 394 return virtio_seg; 395 } 396 397 /** 398 * Converts a segment:offset pair into a 32bit physical address. 399 */ 400 static uint32_t virtio_addr_to_phys(void __far *ptr) 401 { 402 return ((uint32_t)FP_SEG(ptr) << 4) + FP_OFF(ptr); 180 403 } 181 404 … … 188 411 uint16_t ebda_seg; 189 412 uint16_t virtio_seg; 413 uint32_t fFeatures; 414 uint8_t u8DevStat; 190 415 bio_dsk_t __far *bios_dsk; 191 416 virtio_t __far *virtio; … … 215 440 * this time and fill in the data. 216 441 */ 217 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOffVirtIo); 218 442 u8PciCapOff = u8PciCapOffVirtIo; 219 443 while (u8PciCapOff != 0) 220 444 { … … 222 446 uint8_t cbPciCap = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 2); /* Capability length. */ 223 447 448 DBG_VIRTIO("Capability ID 0x%x at 0x%x\n", u8PciCapId, u8PciCapOff); 449 224 450 if ( u8PciCapId == PCI_CAP_ID_VNDR 225 && cbPciCap == sizeof(virtio_pci_cap_t))451 && cbPciCap >= sizeof(virtio_pci_cap_t)) 226 452 { 227 453 /* Read in the config type and see what we got. */ 228 uint8_t i; 229 virtio_pci_cap_t VirtIoPciCap; 230 uint8_t *pbTmp = (uint8_t *)&VirtIoPciCap; 231 232 for (i = 0; i < sizeof(VirtIoPciCap); i++) 233 *pbTmp++ = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 1); 234 235 switch (VirtIoPciCap.u8VirtIoCfgType) 454 uint8_t u8PciVirtioCfg = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 3); 455 456 DBG_VIRTIO("VirtIO: CFG ID 0x%x\n", u8PciVirtioCfg); 457 switch (u8PciVirtioCfg) 236 458 { 237 459 case VIRTIO_PCI_CAP_COMMON_CFG: … … 240 462 case VIRTIO_PCI_CAP_DEVICE_CFG: 241 463 { 242 virtio_bar_cfg_t *pBarCfg = &virtio->aBarCfgs[VirtIoPciCap.u8VirtIoCfgType- 1];243 244 pBarCfg->u8Bar = VirtIoPciCap.u8Bar;245 pBarCfg->u32Offset = VirtIoPciCap.u32Offset;246 pBarCfg->u32Length = VirtIoPciCap.u32Length;464 virtio_bar_cfg_t __far *pBarCfg = &virtio->aBarCfgs[u8PciVirtioCfg - 1]; 465 466 pBarCfg->u8Bar = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 4); 467 pBarCfg->u32Offset = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 8); 468 pBarCfg->u32Length = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 12); 247 469 break; 248 470 } 249 471 case VIRTIO_PCI_CAP_PCI_CFG: 250 472 virtio->u8PciCfgOff = u8PciCapOff; 473 DBG_VIRTIO("VirtIO PCI CAP window offset: %x\n", u8PciCapOff); 251 474 break; 252 475 default: 253 DBG_VIRTIO("VirtIO SCSI HBA with unknown PCI capability type 0x%x\n", VirtIoPciCap.u8VirtIoCfgType);476 DBG_VIRTIO("VirtIO SCSI HBA with unknown PCI capability type 0x%x\n", u8PciVirtioCfg); 254 477 } 255 256 u8PciCapOff = VirtIoPciCap.u8PciCapNext; /* Saves one VM exit. */257 478 } 258 else 259 479 480 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 1); 260 481 } 261 482 262 /** @todo Start reading actual registers, initializing the controller, detecting disks, etc. */ 483 /* Reset the device. */ 484 u8DevStat = VIRTIO_CMN_REG_DEV_STS_F_RST; 485 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat); 486 /* Acknowledge presence. */ 487 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_ACK; 488 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat); 489 /* Our driver knows how to operatet the device. */ 490 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_DRV; 491 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat); 492 493 /* Read the feature bits and only program the VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT bit if available. */ 494 fFeatures = virtio_reg_common_read_u32(virtio, VIRTIO_COMMON_REG_DEV_FEAT); 495 fFeatures &= VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT; 496 497 /* Check that the device is sane. */ 498 if ( virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_Q_NUM) < 1 499 || virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_CDB_SZ) < 16 500 || virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_SENSE_SZ) < 32 501 || virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_SECT_MAX) < 1) 502 { 503 DBG_VIRTIO("VirtIO-SCSI: Invalid SCSI device configuration, ignoring device\n"); 504 return 0; 505 } 506 507 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_DEV_FEAT, fFeatures); 508 509 /* Set the features OK bit. */ 510 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_FEAT_OK; 511 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat); 512 513 /* Read again and check the the okay bit is still set. */ 514 if (!(virtio_reg_common_read_u8(virtio, VIRTIO_COMMON_REG_DEV_STS) & VIRTIO_CMN_REG_DEV_STS_F_FEAT_OK)) 515 { 516 DBG_VIRTIO("VirtIO-SCSI: Device doesn't accept our feature set, ignoring device\n"); 517 return 0; 518 } 519 520 /* Disable event and control queue. */ 521 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SELECT, VIRTIO_SCSI_Q_CONTROL); 522 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, 0); 523 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 0); 524 525 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SELECT, VIRTIO_SCSI_Q_EVENT); 526 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, 0); 527 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 0); 528 529 /* Setup the request queue. */ 530 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); 532 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 1); 533 534 /* Set queue area addresses (only low part, leave high part 0). */ 535 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DESC, virtio_addr_to_phys(&virtio->Queue.aDescTbl[0])); 536 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DESC + 4, 0); 537 538 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DRIVER, virtio_addr_to_phys(&virtio->Queue.AvailRing)); 539 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DRIVER + 4, 0); 540 541 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DEVICE, virtio_addr_to_phys(&virtio->Queue.UsedRing)); 542 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DEVICE + 4, 0); 543 544 virtio_reg_dev_cfg_write_u32(virtio, VIRTIO_DEV_CFG_REG_CDB_SZ, VIRTIO_SCSI_CDB_SZ); 545 virtio_reg_dev_cfg_write_u32(virtio, VIRTIO_DEV_CFG_REG_SENSE_SZ, VIRTIO_SCSI_SENSE_SZ); 546 547 /* Bring the device into operational mode. */ 548 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_DRV_OK; 549 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat); 550 551 /** @todo Detect attached devices. */ 263 552 264 553 return 0;
Note:
See TracChangeset
for help on using the changeset viewer.