@@ -346,7 +346,6 @@ static void set_vbar_base(struct pci_bar *vbar, uint32_t base)
346
346
347
347
/**
348
348
* @pre vdev != NULL
349
- * @pre (vdev->bar[idx].type == PCIBAR_NONE) || (vdev->bar[idx].type == PCIBAR_MEM32)
350
349
*/
351
350
static void vdev_pt_write_vbar (struct pci_vdev * vdev , uint32_t offset , uint32_t val )
352
351
{
@@ -361,22 +360,41 @@ static void vdev_pt_write_vbar(struct pci_vdev *vdev, uint32_t offset, uint32_t
361
360
362
361
vbar = & vdev -> bar [idx ];
363
362
364
- switch ( vdev -> bar [ idx ]. type ) {
365
- case PCIBAR_NONE :
366
- break ;
363
+ if ( vbar -> is_64bit_high ) {
364
+ if ( idx > 0U ) {
365
+ uint32_t prev_idx = idx - 1U ;
367
366
368
- case PCIBAR_MEM32 :
369
- base = pci_base_from_size_mask (vbar -> size , (uint64_t )val );
370
- set_vbar_base (vbar , (uint32_t )base );
367
+ base = git_size_masked_bar_base (vdev -> bar [prev_idx ].size , ((uint64_t )val ) << 32U ) >> 32U ;
368
+ set_vbar_base (vbar , (uint32_t )base );
371
369
372
- if (bar_update_normal ) {
373
- vdev_pt_remap_mem_vbar (vdev , idx );
370
+ if (bar_update_normal ) {
371
+ vdev_pt_remap_mem_vbar (vdev , prev_idx );
372
+ }
373
+ } else {
374
+ ASSERT (false, "idx for upper 32-bit of the 64-bit bar should be greater than 0!" );
374
375
}
375
- break ;
376
+ } else {
377
+ enum pci_bar_type type = pci_get_bar_type (vbar -> reg .value );
378
+
379
+ switch (type ) {
380
+ case PCIBAR_MEM32 :
381
+ base = git_size_masked_bar_base (vbar -> size , (uint64_t )val );
382
+ set_vbar_base (vbar , (uint32_t )base );
376
383
377
- default :
378
- /* Should never reach here, init_vdev_pt() only sets vbar type to PCIBAR_NONE and PCIBAR_MEM32 */
379
- break ;
384
+ if (bar_update_normal ) {
385
+ vdev_pt_remap_mem_vbar (vdev , idx );
386
+ }
387
+ break ;
388
+
389
+ case PCIBAR_MEM64 :
390
+ base = git_size_masked_bar_base (vbar -> size , (uint64_t )val );
391
+ set_vbar_base (vbar , (uint32_t )base );
392
+ break ;
393
+
394
+ default :
395
+ /* Nothing to do */
396
+ break ;
397
+ }
380
398
}
381
399
382
400
/* Write the vbar value to corresponding virtualized vbar reg */
@@ -403,15 +421,6 @@ int32_t vdev_pt_write_cfg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes
403
421
return ret ;
404
422
}
405
423
406
- /**
407
- * For bar emulation, currently only MMIO is supported and bar size cannot be greater than 4GB
408
- * @pre bar != NULL
409
- */
410
- static inline bool is_bar_supported (const struct pci_bar * bar )
411
- {
412
- return (is_mmio_bar (bar ) && is_valid_bar_size (bar ));
413
- }
414
-
415
424
/**
416
425
* PCI base address register (bar) virtualization:
417
426
*
@@ -453,40 +462,47 @@ void init_vdev_pt(struct pci_vdev *vdev)
453
462
pbar = & vdev -> pdev -> bar [idx ];
454
463
vbar = & vdev -> bar [idx ];
455
464
456
- if (is_bar_supported (pbar )) {
457
- vbar -> reg .value = pbar -> reg .value ;
458
- vbar -> reg .bits .mem .base = 0x0U ; /* clear vbar base */
459
- if (vbar -> reg .bits .mem .type == 0x2U ) {
460
- /* Clear vbar 64-bit flag and set it to 32-bit */
461
- vbar -> reg .bits .mem .type = 0x0U ;
462
- }
463
-
464
- /**
465
- * If vbar->base is 0 (unassigned), Linux kernel will reprogram the vbar on
466
- * its bar size boundary, so in order to ensure the MMIO vbar allocated by guest
467
- * is 4k aligned, set its size to be 4K aligned.
468
- */
469
- vbar -> size = round_page_up (pbar -> size );
470
-
471
- /**
472
- * Only 32-bit bar is supported for now so both PCIBAR_MEM32 and PCIBAR_MEM64
473
- * are reported to guest as PCIBAR_MEM32
474
- */
475
- vbar -> type = PCIBAR_MEM32 ;
465
+ vbar -> size = 0UL ;
466
+ vbar -> reg .value = pbar -> reg .value ;
467
+ vbar -> is_64bit_high = pbar -> is_64bit_high ;
476
468
477
- /* For pre-launched VMs: vbar base is predefined in vm_config */
478
- vbar_base = vdev -> ptdev_config -> vbar_base [ idx ] ;
469
+ if ( pbar -> is_64bit_high ) {
470
+ ASSERT ( idx > 0U , "idx for upper 32-bit of the 64-bit bar should be greater than 0!" ) ;
479
471
480
- /* Set the new vbar base */
481
- vdev_pt_write_vbar (vdev , pci_bar_offset (idx ), (uint32_t )vbar_base );
472
+ if (idx > 0U ) {
473
+ /* For pre-launched VMs: vbar base is predefined in vm_config */
474
+ vbar_base = vdev -> ptdev_config -> vbar_base [idx - 1U ];
475
+ /* Write the upper 32-bit of a 64-bit bar */
476
+ vdev_pt_write_vbar (vdev , pci_bar_offset (idx ), (uint32_t )(vbar_base >> 32U ));
477
+ }
482
478
} else {
483
- vbar -> reg .value = 0x0U ;
484
- vbar -> size = 0UL ;
485
- vbar -> type = PCIBAR_NONE ;
479
+ enum pci_bar_type type = pci_get_bar_type (pbar -> reg .value );
480
+
481
+ switch (type ) {
482
+ case PCIBAR_MEM32 :
483
+ case PCIBAR_MEM64 :
484
+ /**
485
+ * If vbar->base is 0 (unassigned), Linux kernel will reprogram the vbar on
486
+ * its bar size boundary, so in order to ensure the MMIO vbar allocated by guest
487
+ * is 4k aligned, set its size to be 4K aligned.
488
+ */
489
+ vbar -> size = round_page_up (pbar -> size );
490
+
491
+ /* For pre-launched VMs: vbar base is predefined in vm_config */
492
+ vbar_base = vdev -> ptdev_config -> vbar_base [idx ];
493
+ vdev_pt_write_vbar (vdev , pci_bar_offset (idx ), (uint32_t )vbar_base );
494
+ break ;
495
+
496
+ default :
497
+ vbar -> reg .value = 0x0U ;
498
+ vbar -> size = 0UL ;
499
+ break ;
500
+ }
486
501
}
487
502
}
488
503
489
504
pci_command = (uint16_t )pci_pdev_read_cfg (vdev -> pdev -> bdf , PCIR_COMMAND , 2U );
505
+
490
506
/* Disable INTX */
491
507
pci_command |= 0x400U ;
492
508
pci_pdev_write_cfg (vdev -> pdev -> bdf , PCIR_COMMAND , 2U , pci_command );
0 commit comments