summary refs log tree commit diff
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2019-06-14 13:31:04 -0700
committerCommit Bot <commit-bot@chromium.org>2019-06-25 04:36:47 +0000
commitdade4c7425d44033f6a312209cf0a5d6a69a31ca (patch)
treea1a0efef605dc3f903b3899d041a3d9a3638b9b8
parent5e3442e67519caa018c3ec51d7105b03ea648e4d (diff)
downloadcrosvm-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.rs21
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);
+    }
 }