@@ -924,9 +924,15 @@ impl PciConfiguration {
924
924
region_type,
925
925
} ) ;
926
926
} else if ( reg_idx > BAR0_REG )
927
- && ( ( self . registers [ reg_idx - 1 ] & self . writable_bits [ reg_idx - 1 ] )
928
- != ( self . bars [ bar_idx - 1 ] . addr & self . writable_bits [ reg_idx - 1 ] )
929
- || ( value & mask) != ( self . bars [ bar_idx] . addr & mask) )
927
+ && (
928
+ // The lower BAR (of this 64bit BAR) has been reprogrammed to a different value
929
+ // than it used to be
930
+ ( self . registers [ reg_idx - 1 ] & self . writable_bits [ reg_idx - 1 ] )
931
+ != ( self . bars [ bar_idx - 1 ] . addr & self . writable_bits [ reg_idx - 1 ] ) ||
932
+ // Or the lower BAR hasn't been changed but the upper one is being reprogrammed
933
+ // now to a different value
934
+ ( value & mask) != ( self . bars [ bar_idx] . addr & mask)
935
+ )
930
936
{
931
937
info ! (
932
938
"Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}" ,
@@ -1451,4 +1457,134 @@ mod tests {
1451
1457
assert_eq ! ( * reg, pci_config. read_reg( reg_idx) ) ;
1452
1458
}
1453
1459
}
1460
+
1461
+ #[ test]
1462
+ fn test_detect_bar_reprogramming ( ) {
1463
+ let mut pci_config = PciConfiguration :: new (
1464
+ 0x42 ,
1465
+ 0x0 ,
1466
+ 0x0 ,
1467
+ PciClassCode :: MassStorage ,
1468
+ & PciMassStorageSubclass :: SerialScsiController ,
1469
+ None ,
1470
+ PciHeaderType :: Device ,
1471
+ 0x13 ,
1472
+ 0x12 ,
1473
+ None ,
1474
+ None ,
1475
+ ) ;
1476
+
1477
+ // Trying to reprogram with something less than 4 bytes (length of the address) should fail
1478
+ assert ! ( pci_config
1479
+ . detect_bar_reprogramming( BAR0_REG , & [ 0x13 ] )
1480
+ . is_none( ) ) ;
1481
+ assert ! ( pci_config
1482
+ . detect_bar_reprogramming( BAR0_REG , & [ 0x13 , 0x12 ] )
1483
+ . is_none( ) ) ;
1484
+ assert ! ( pci_config
1485
+ . detect_bar_reprogramming( BAR0_REG , & [ 0x13 , 0x12 ] )
1486
+ . is_none( ) ) ;
1487
+ assert ! ( pci_config
1488
+ . detect_bar_reprogramming( BAR0_REG , & [ 0x13 , 0x12 , 0x16 ] )
1489
+ . is_none( ) ) ;
1490
+
1491
+ // Writing all 1s is a special case where we're actually asking for the size of the BAR
1492
+ assert ! ( pci_config
1493
+ . detect_bar_reprogramming( BAR0_REG , & u32 :: to_le_bytes( 0xffff_ffff ) )
1494
+ . is_none( ) ) ;
1495
+
1496
+ // Trying to reprogram a BAR that hasn't be initialized does nothing
1497
+ for reg_idx in BAR0_REG ..BAR0_REG + NUM_BAR_REGS {
1498
+ assert ! ( pci_config
1499
+ . detect_bar_reprogramming( reg_idx, & u32 :: to_le_bytes( 0x1312_4243 ) )
1500
+ . is_none( ) ) ;
1501
+ }
1502
+
1503
+ // Reprogramming of a 32bit BAR
1504
+ pci_config
1505
+ . add_pci_bar ( & PciBarConfiguration {
1506
+ addr : 0x1000 ,
1507
+ size : 0x1000 ,
1508
+ idx : 0 ,
1509
+ region_type : PciBarRegionType :: Memory32BitRegion ,
1510
+ prefetchable : PciBarPrefetchable :: Prefetchable ,
1511
+ } )
1512
+ . unwrap ( ) ;
1513
+
1514
+ assert_eq ! (
1515
+ pci_config. detect_bar_reprogramming( BAR0_REG , & u32 :: to_le_bytes( 0x2000 ) ) ,
1516
+ Some ( BarReprogrammingParams {
1517
+ old_base: 0x1000 ,
1518
+ new_base: 0x2000 ,
1519
+ len: 0x1000 ,
1520
+ region_type: PciBarRegionType :: Memory32BitRegion
1521
+ } )
1522
+ ) ;
1523
+
1524
+ pci_config. write_config_register ( BAR0_REG , 0 , & u32:: to_le_bytes ( 0x2000 ) ) ;
1525
+ assert_eq ! ( pci_config. read_reg( BAR0_REG ) & 0xffff_fff0 , 0x2000 ) ;
1526
+
1527
+ // Attempting to reprogram the BAR with the same address should not have any effect
1528
+ assert ! ( pci_config
1529
+ . detect_bar_reprogramming( BAR0_REG , & u32 :: to_le_bytes( 0x2000 ) )
1530
+ . is_none( ) ) ;
1531
+
1532
+ // Reprogramming of a 64bit BAR
1533
+ pci_config
1534
+ . add_pci_bar ( & PciBarConfiguration {
1535
+ addr : 0x13_1200_0000 ,
1536
+ size : 0x8000 ,
1537
+ idx : 1 ,
1538
+ region_type : PciBarRegionType :: Memory64BitRegion ,
1539
+ prefetchable : PciBarPrefetchable :: Prefetchable ,
1540
+ } )
1541
+ . unwrap ( ) ;
1542
+
1543
+ assert_eq ! ( pci_config. read_reg( BAR0_REG + 1 ) & 0xffff_fff0 , 0x1200_0000 ) ;
1544
+ assert_eq ! (
1545
+ pci_config. bars[ 1 ] . r#type,
1546
+ Some ( PciBarRegionType :: Memory64BitRegion )
1547
+ ) ;
1548
+ assert_eq ! ( pci_config. read_reg( BAR0_REG + 2 ) , 0x13 ) ;
1549
+ assert ! ( pci_config. bars[ 2 ] . r#type. is_none( ) ) ;
1550
+
1551
+ // First we write the lower 32 bits and this shouldn't cause any reprogramming
1552
+ assert ! ( pci_config
1553
+ . detect_bar_reprogramming( BAR0_REG + 1 , & u32 :: to_le_bytes( 0x4200_0000 ) )
1554
+ . is_none( ) ) ;
1555
+ pci_config. write_config_register ( BAR0_REG + 1 , 0 , & u32:: to_le_bytes ( 0x4200_0000 ) ) ;
1556
+
1557
+ // Writing the upper 32 bits should trigger the reprogramming
1558
+ assert_eq ! (
1559
+ pci_config. detect_bar_reprogramming( BAR0_REG + 2 , & u32 :: to_le_bytes( 0x84 ) ) ,
1560
+ Some ( BarReprogrammingParams {
1561
+ old_base: 0x13_1200_0000 ,
1562
+ new_base: 0x84_4200_0000 ,
1563
+ len: 0x8000 ,
1564
+ region_type: PciBarRegionType :: Memory64BitRegion
1565
+ } )
1566
+ ) ;
1567
+ pci_config. write_config_register ( BAR0_REG + 2 , 0 , & u32:: to_le_bytes ( 0x84 ) ) ;
1568
+
1569
+ // Trying to reprogram the upper bits directly (without first touching the lower bits)
1570
+ // should trigger a reprogramming
1571
+ assert_eq ! (
1572
+ pci_config. detect_bar_reprogramming( BAR0_REG + 2 , & u32 :: to_le_bytes( 0x1312 ) ) ,
1573
+ Some ( BarReprogrammingParams {
1574
+ old_base: 0x84_4200_0000 ,
1575
+ new_base: 0x1312_4200_0000 ,
1576
+ len: 0x8000 ,
1577
+ region_type: PciBarRegionType :: Memory64BitRegion
1578
+ } )
1579
+ ) ;
1580
+ pci_config. write_config_register ( BAR0_REG + 2 , 0 , & u32:: to_le_bytes ( 0x1312 ) ) ;
1581
+
1582
+ // Attempting to reprogram the BAR with the same address should not have any effect
1583
+ assert ! ( pci_config
1584
+ . detect_bar_reprogramming( BAR0_REG + 1 , & u32 :: to_le_bytes( 0x4200_0000 ) )
1585
+ . is_none( ) ) ;
1586
+ assert ! ( pci_config
1587
+ . detect_bar_reprogramming( BAR0_REG + 2 , & u32 :: to_le_bytes( 0x1312 ) )
1588
+ . is_none( ) ) ;
1589
+ }
1454
1590
}
0 commit comments