mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: Respect PCI CFG cap.length for BAR access
The VIRTIO_PCI_CAP_PCI_CFG indirect access mechanism was ignoring the cap.length field written by the guest driver. PCI config register reads always produce a 4 byte buffer, so when a driver set cap.length to 1 for a byte wide access to device_status at common config offset 0x14, the VMM passed all 4 bytes to read_bar, dispatching to the dword handler which does not cover that offset. Use cap.length to determine the actual BAR access width per virtio spec 4.1.4.9.1. Also replace the unsafe transmute with the safe Le32::to_native() conversion. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
cc2e528c88
commit
feb1c4a2d6
@@ -221,6 +221,14 @@ impl VirtioPciCfgCap {
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the BAR offset and clamped access length for a PCI CFG cap
|
||||
/// indirect BAR access.
|
||||
fn bar_access_params(&self, data_len: usize) -> (u64, usize) {
|
||||
let bar_offset = self.cap.offset.to_native() as u64;
|
||||
let cap_length = self.cap.length.to_native() as usize;
|
||||
(bar_offset, cmp::min(cap_length, data_len))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
@@ -771,10 +779,10 @@ impl VirtioPciDevice {
|
||||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
let bar_offset: u32 =
|
||||
// SAFETY: we know self.cap_pci_cfg_info.cap.cap.offset is 32bits long.
|
||||
unsafe { std::mem::transmute(self.cap_pci_cfg_info.cap.cap.offset) };
|
||||
self.read_bar(0, bar_offset as u64, data);
|
||||
let (bar_offset, access_len) = self.cap_pci_cfg_info.cap.bar_access_params(data_len);
|
||||
if access_len > 0 {
|
||||
self.read_bar(0, bar_offset, &mut data[..access_len]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,10 +800,12 @@ impl VirtioPciDevice {
|
||||
right[..data_len].copy_from_slice(data);
|
||||
None
|
||||
} else {
|
||||
let bar_offset: u32 =
|
||||
// SAFETY: we know self.cap_pci_cfg_info.cap.cap.offset is 32bits long.
|
||||
unsafe { std::mem::transmute(self.cap_pci_cfg_info.cap.cap.offset) };
|
||||
self.write_bar(0, bar_offset as u64, data)
|
||||
let (bar_offset, access_len) = self.cap_pci_cfg_info.cap.bar_access_params(data_len);
|
||||
if access_len > 0 {
|
||||
self.write_bar(0, bar_offset, &data[..access_len])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user