Skip to content

Commit 95c5a2b

Browse files
committed
fix(pci): correct shift size when setting config address
We were shifting by the wrong number of bits for 2-byte accesses. Signed-off-by: Babis Chalios <[email protected]>
1 parent 14e8b37 commit 95c5a2b

File tree

1 file changed

+118
-2
lines changed

1 file changed

+118
-2
lines changed

src/pci/src/bus.rs

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,8 @@ impl PciConfigIo {
291291
u32::from(data[0]) << (offset * 8),
292292
),
293293
2 => (
294-
0x0000_ffff << (offset * 16),
295-
((u32::from(data[1]) << 8) | u32::from(data[0])) << (offset * 16),
294+
0x0000_ffff << (offset * 8),
295+
((u32::from(data[1]) << 8) | u32::from(data[0])) << (offset * 8),
296296
),
297297
4 => (0xffff_ffff, LittleEndian::read_u32(data)),
298298
_ => return,
@@ -475,3 +475,119 @@ fn parse_io_config_address(config_address: u32) -> (usize, usize, usize, usize)
475475
shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK),
476476
)
477477
}
478+
479+
#[cfg(test)]
480+
mod tests {
481+
use std::sync::{Arc, Mutex};
482+
483+
use vm_device::BusDevice;
484+
485+
use super::{PciBus, PciConfigIo, PciRoot};
486+
use crate::DeviceRelocation;
487+
488+
struct RelocationMock;
489+
490+
impl DeviceRelocation for RelocationMock {
491+
fn move_bar(
492+
&self,
493+
_old_base: u64,
494+
_new_base: u64,
495+
_len: u64,
496+
_pci_dev: &mut dyn crate::PciDevice,
497+
_region_type: crate::PciBarRegionType,
498+
) -> std::result::Result<(), std::io::Error> {
499+
Ok(())
500+
}
501+
}
502+
503+
#[test]
504+
fn test_writing_config_address() {
505+
let mock = Arc::new(RelocationMock);
506+
let root = PciRoot::new(None);
507+
let mut bus = PciConfigIo::new(Arc::new(Mutex::new(PciBus::new(root, mock))));
508+
509+
assert_eq!(bus.config_address, 0);
510+
// Writing more than 32 bits will should fail
511+
bus.write(0, 0, &[0x42; 8]);
512+
assert_eq!(bus.config_address, 0);
513+
// Write all the address at once
514+
bus.write(0, 0, &[0x13, 0x12, 0x11, 0x10]);
515+
assert_eq!(bus.config_address, 0x10111213);
516+
// Not writing 32bits at offset 0 should have no effect
517+
bus.write(0, 1, &[0x0; 4]);
518+
assert_eq!(bus.config_address, 0x10111213);
519+
520+
// Write two bytes at a time
521+
bus.write(0, 0, &[0x42, 0x42]);
522+
assert_eq!(bus.config_address, 0x10114242);
523+
bus.write(0, 1, &[0x43, 0x43]);
524+
assert_eq!(bus.config_address, 0x10434342);
525+
bus.write(0, 2, &[0x44, 0x44]);
526+
assert_eq!(bus.config_address, 0x44444342);
527+
// Writing two bytes at offset 3 should overflow, so it shouldn't have any effect
528+
bus.write(0, 3, &[0x45, 0x45]);
529+
assert_eq!(bus.config_address, 0x44444342);
530+
531+
// Write one byte at a time
532+
bus.write(0, 0, &[0x0]);
533+
assert_eq!(bus.config_address, 0x44444300);
534+
bus.write(0, 1, &[0x0]);
535+
assert_eq!(bus.config_address, 0x44440000);
536+
bus.write(0, 2, &[0x0]);
537+
assert_eq!(bus.config_address, 0x44000000);
538+
bus.write(0, 3, &[0x0]);
539+
assert_eq!(bus.config_address, 0x00000000);
540+
// Writing past 4 bytes should have no effect
541+
bus.write(0, 4, &[0x13]);
542+
assert_eq!(bus.config_address, 0x0);
543+
}
544+
545+
#[test]
546+
fn test_reading_config_address() {
547+
let mock = Arc::new(RelocationMock);
548+
let root = PciRoot::new(None);
549+
let mut bus = PciConfigIo::new(Arc::new(Mutex::new(PciBus::new(root, mock))));
550+
551+
let mut buffer = [0u8; 4];
552+
553+
bus.config_address = 0x13121110;
554+
555+
// First 4 bytes are the config address
556+
// Next 4 bytes are the values read from the configuration space.
557+
//
558+
// Reading past offset 7 should not return nothing (all 1s)
559+
bus.read(0, 8, &mut buffer);
560+
assert_eq!(buffer, [0xff; 4]);
561+
562+
// offset + buffer.len() needs to be smaller or equal than 4
563+
bus.read(0, 1, &mut buffer);
564+
assert_eq!(buffer, [0xff; 4]);
565+
bus.read(0, 2, &mut buffer[..3]);
566+
assert_eq!(buffer, [0xff; 4]);
567+
bus.read(0, 3, &mut buffer[..2]);
568+
assert_eq!(buffer, [0xff; 4]);
569+
570+
// reading one byte at a time
571+
bus.read(0, 0, &mut buffer[0..1]);
572+
assert_eq!(buffer, [0x10, 0xff, 0xff, 0xff]);
573+
bus.read(0, 1, &mut buffer[1..2]);
574+
assert_eq!(buffer, [0x10, 0x11, 0xff, 0xff]);
575+
bus.read(0, 2, &mut buffer[2..3]);
576+
assert_eq!(buffer, [0x10, 0x11, 0x12, 0xff]);
577+
bus.read(0, 3, &mut buffer[3..4]);
578+
assert_eq!(buffer, [0x10, 0x11, 0x12, 0x13]);
579+
580+
// reading two bytes at a time
581+
bus.config_address = 0x42434445;
582+
bus.read(0, 0, &mut buffer[..2]);
583+
assert_eq!(buffer, [0x45, 0x44, 0x12, 0x13]);
584+
bus.read(0, 1, &mut buffer[..2]);
585+
assert_eq!(buffer, [0x44, 0x43, 0x12, 0x13]);
586+
bus.read(0, 2, &mut buffer[..2]);
587+
assert_eq!(buffer, [0x43, 0x42, 0x12, 0x13]);
588+
589+
// reading all of it at once
590+
bus.read(0, 0, &mut buffer);
591+
assert_eq!(buffer, [0x45, 0x44, 0x43, 0x42]);
592+
}
593+
}

0 commit comments

Comments
 (0)