diff options
author | Daniel Verkamp <dverkamp@chromium.org> | 2019-06-14 13:31:04 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-06-25 04:36:47 +0000 |
commit | dade4c7425d44033f6a312209cf0a5d6a69a31ca (patch) | |
tree | a1a0efef605dc3f903b3899d041a3d9a3638b9b8 | |
parent | 5e3442e67519caa018c3ec51d7105b03ea648e4d (diff) | |
download | crosvm-dade4c7425d44033f6a312209cf0a5d6a69a31ca.tar crosvm-dade4c7425d44033f6a312209cf0a5d6a69a31ca.tar.gz crosvm-dade4c7425d44033f6a312209cf0a5d6a69a31ca.tar.bz2 crosvm-dade4c7425d44033f6a312209cf0a5d6a69a31ca.tar.lz crosvm-dade4c7425d44033f6a312209cf0a5d6a69a31ca.tar.xz crosvm-dade4c7425d44033f6a312209cf0a5d6a69a31ca.tar.zst crosvm-dade4c7425d44033f6a312209cf0a5d6a69a31ca.zip |
devices: pci: preserve read-only bits in write_reg
The 32-bit write_reg() function for PCI configuration space masked off non-writable (read-only) bits from the incoming value, but it did not preserve the original bits from the register; this results in writes to read-only registers to clear all read-only bits to 0 instead. Preserve the original value of the read-only bits and add a test to verify that this works. BUG=None TEST=./build_test Change-Id: Icc67b429f17d519ec4e9090f8e0ce48aaff76491 Signed-off-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1660204 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Dylan Reid <dgreid@chromium.org>
-rw-r--r-- | devices/src/pci/pci_configuration.rs | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs index 5f230af..566d9b8 100644 --- a/devices/src/pci/pci_configuration.rs +++ b/devices/src/pci/pci_configuration.rs @@ -291,7 +291,7 @@ impl PciConfiguration { /// Writes a 32bit register to `reg_idx` in the register map. pub fn write_reg(&mut self, reg_idx: usize, value: u32) { if let Some(r) = self.registers.get_mut(reg_idx) { - *r = value & self.writable_bits[reg_idx]; + *r = (*r & !self.writable_bits[reg_idx]) | (value & self.writable_bits[reg_idx]); } else { warn!("bad PCI register write {}", reg_idx); } @@ -626,4 +626,23 @@ mod tests { assert_eq!(subclass, 0x01); assert_eq!(prog_if, 0x5a); } + + #[test] + fn read_only_bits() { + let mut cfg = PciConfiguration::new( + 0x1234, + 0x5678, + PciClassCode::MultimediaController, + &PciMultimediaSubclass::AudioController, + Some(&TestPI::Test), + PciHeaderType::Device, + 0xABCD, + 0x2468, + ); + + // Attempt to overwrite vendor ID and device ID, which are read-only + cfg.write_reg(0, 0xBAADF00D); + // The original vendor and device ID should remain. + assert_eq!(cfg.read_reg(0), 0x56781234); + } } |