Skip to content

Commit 9128923

Browse files
committed
pci: virtio: refactor: move MsixConfig interaction to VirtioPciDevice
Following previous commits notion, move MsixConfig handling out of PciConfiguration into VirtioPciDevice. Signed-off-by: Egor Lazarchuk <yegorlz@amazon.co.uk>
1 parent c2f10a0 commit 9128923

4 files changed

Lines changed: 40 additions & 55 deletions

File tree

src/vmm/src/devices/virtio/transport/pci/device.rs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ pub struct VirtioPciDeviceState {
233233
pub pci_dev_state: VirtioPciCommonConfigState,
234234
pub msix_state: MsixConfigState,
235235
pub bars: Bars,
236+
pub msix_config_cap_offset: u16,
236237
}
237238

238239
#[derive(Debug, thiserror::Error, displaydoc::Display)]
@@ -279,6 +280,8 @@ pub struct VirtioPciDevice {
279280
// needed when the guest tries to early access the virtio configuration of
280281
// a device.
281282
cap_pci_cfg_info: VirtioPciCfgCapInfo,
283+
msix_config_cap_offset: u16,
284+
msix_config: Arc<Mutex<MsixConfig>>,
282285
}
283286

284287
impl Debug for VirtioPciDevice {
@@ -318,7 +321,6 @@ impl VirtioPciDevice {
318321
subclass,
319322
VIRTIO_PCI_VENDOR_ID,
320323
pci_device_id,
321-
Some(msix_config.clone()),
322324
)
323325
}
324326

@@ -394,6 +396,8 @@ impl VirtioPciDevice {
394396
memory,
395397
cap_pci_cfg_info: VirtioPciCfgCapInfo::default(),
396398
bars: Bars::default(),
399+
msix_config,
400+
msix_config_cap_offset: 0,
397401
};
398402

399403
Ok(virtio_pci_device)
@@ -409,10 +413,7 @@ impl VirtioPciDevice {
409413
let vectors = msix_config.vectors.clone();
410414
let msix_config = Arc::new(Mutex::new(msix_config));
411415

412-
let pci_config = PciConfiguration::type0_from_state(
413-
state.pci_configuration_state,
414-
Some(msix_config.clone()),
415-
)?;
416+
let pci_config = PciConfiguration::type0_from_state(state.pci_configuration_state)?;
416417
let virtio_common_config = VirtioPciCommonConfig::new(state.pci_dev_state);
417418
let cap_pci_cfg_info = VirtioPciCfgCapInfo {
418419
offset: state.cap_pci_cfg_offset,
@@ -440,6 +441,8 @@ impl VirtioPciDevice {
440441
memory: vm.guest_memory().clone(),
441442
cap_pci_cfg_info,
442443
bars: state.bars,
444+
msix_config,
445+
msix_config_cap_offset: state.msix_config_cap_offset,
443446
};
444447

445448
if state.device_activated {
@@ -521,7 +524,10 @@ impl VirtioPciDevice {
521524
VIRTIO_BAR_INDEX,
522525
MSIX_PBA_BAR_OFFSET,
523526
);
524-
self.configuration.add_capability(&msix_cap);
527+
// The whole Configuration region is 4K, so u16 can address it all
528+
#[allow(clippy::cast_possible_truncation)]
529+
let offset = self.configuration.add_capability(&msix_cap) as u16;
530+
self.msix_config_cap_offset = offset;
525531
}
526532
}
527533

@@ -624,6 +630,7 @@ impl VirtioPciDevice {
624630
.expect("Poisoned lock")
625631
.state(),
626632
bars: self.bars,
633+
msix_config_cap_offset: self.msix_config_cap_offset,
627634
}
628635
}
629636
}
@@ -734,16 +741,21 @@ impl PciDevice for VirtioPciDevice {
734741
self.bars.write(bar_idx, offset, data);
735742
None
736743
} else {
737-
// Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
738-
// is accessed. This capability has a special meaning as it allows the
739-
// guest to access other capabilities without mapping the PCI BAR.
740-
let base = reg_idx as usize * 4;
741-
if base + offset as usize >= self.cap_pci_cfg_info.offset as usize
742-
&& base + offset as usize + data.len()
744+
// Handle access to the header of the MsixCapability. The rest of the
745+
// capability is handled by the PciConfiguration.
746+
let base = reg_idx * 4;
747+
if base == self.msix_config_cap_offset {
748+
self.msix_config
749+
.lock()
750+
.unwrap()
751+
.write_msg_ctl_register(offset, data);
752+
}
753+
if base + u16::from(offset) >= self.cap_pci_cfg_info.offset
754+
&& (base + u16::from(offset)) as usize + data.len()
743755
<= self.cap_pci_cfg_info.offset as usize
744756
+ self.cap_pci_cfg_info.cap.bytes().len()
745757
{
746-
let offset = base + offset as usize - self.cap_pci_cfg_info.offset as usize;
758+
let offset = (base + u16::from(offset) - self.cap_pci_cfg_info.offset) as usize;
747759
self.write_cap_pci_cfg(offset, data)
748760
} else {
749761
self.configuration

src/vmm/src/pci/bus.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ impl PciRoot {
5151
PciBridgeSubclass::HostBridge as u8,
5252
0,
5353
0,
54-
None,
5554
),
5655
}
5756
}
@@ -518,7 +517,6 @@ mod tests {
518517
PciMassStorageSubclass::SerialScsiController as u8,
519518
0x13,
520519
0x12,
521-
None,
522520
);
523521
PciDevMock(config)
524522
}

src/vmm/src/pci/configuration.rs

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55
//
66
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
77

8-
use std::sync::{Arc, Mutex};
9-
108
use byteorder::{ByteOrder, LittleEndian};
119
use serde::{Deserialize, Serialize};
1210
use zerocopy::{FromBytes, IntoBytes};
1311

14-
use super::msix::MsixConfig;
1512
use crate::logger::warn;
1613
use crate::pci::{PciCapabilityId, PciClassCode};
1714

@@ -186,7 +183,6 @@ pub struct PciConfigurationState {
186183
registers: Vec<u32>,
187184
writable_bits: Vec<u32>,
188185
last_capability: Option<(u8, u8)>,
189-
msix_cap_reg_idx: Option<u16>,
190186
}
191187

192188
#[derive(Debug)]
@@ -199,8 +195,6 @@ pub struct PciConfiguration {
199195
writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
200196
// Contains the byte offset and size of the last capability.
201197
last_capability: Option<(u8, u8)>,
202-
msix_cap_reg_idx: Option<u16>,
203-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
204198
}
205199

206200
impl PciConfiguration {
@@ -214,7 +208,6 @@ impl PciConfiguration {
214208
subclass: u8,
215209
subsystem_vendor_id: u16,
216210
subsystem_id: u16,
217-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
218211
) -> Self {
219212
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
220213
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
@@ -233,16 +226,11 @@ impl PciConfiguration {
233226
registers,
234227
writable_bits,
235228
last_capability: None,
236-
msix_cap_reg_idx: None,
237-
msix_config,
238229
}
239230
}
240231

241232
/// Create a type 0 PCI configuration from snapshot state
242-
pub fn type0_from_state(
243-
state: PciConfigurationState,
244-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
245-
) -> Result<Self, PciConfigurationError> {
233+
pub fn type0_from_state(state: PciConfigurationState) -> Result<Self, PciConfigurationError> {
246234
let reg_len = state.registers.len();
247235
let registers = state
248236
.registers
@@ -259,8 +247,6 @@ impl PciConfiguration {
259247
registers,
260248
writable_bits,
261249
last_capability: state.last_capability,
262-
msix_cap_reg_idx: state.msix_cap_reg_idx,
263-
msix_config,
264250
})
265251
}
266252

@@ -270,7 +256,6 @@ impl PciConfiguration {
270256
registers: self.registers.to_vec(),
271257
writable_bits: self.writable_bits.to_vec(),
272258
last_capability: self.last_capability,
273-
msix_cap_reg_idx: self.msix_cap_reg_idx,
274259
}
275260
}
276261

@@ -384,9 +369,7 @@ impl PciConfiguration {
384369
self.writable_bits[(cap_offset / 4) as usize] = MSI_CAPABILITY_REGISTER_MASK;
385370
}
386371
PciCapabilityId::MsiX => {
387-
self.msix_cap_reg_idx = Some(u16::from(cap_offset) / 4);
388-
self.writable_bits[self.msix_cap_reg_idx.unwrap() as usize] =
389-
MSIX_CAPABILITY_REGISTER_MASK;
372+
self.writable_bits[(cap_offset / 4) as usize] = MSIX_CAPABILITY_REGISTER_MASK;
390373
}
391374
_ => {}
392375
}
@@ -410,26 +393,6 @@ impl PciConfiguration {
410393
return;
411394
}
412395

413-
// Handle potential write to MSI-X message control register
414-
if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx
415-
&& let Some(msix_config) = &self.msix_config
416-
{
417-
if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 {
418-
// 2-bytes write in the Message Control field
419-
msix_config
420-
.lock()
421-
.unwrap()
422-
.set_msg_ctl(LittleEndian::read_u16(data));
423-
} else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
424-
// 4 bytes write at the beginning. Ignore the first 2 bytes which are the
425-
// capability id and next capability pointer
426-
msix_config
427-
.lock()
428-
.unwrap()
429-
.set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
430-
}
431-
}
432-
433396
match data.len() {
434397
1 => self.write_byte(reg_idx * 4 + offset as u16, data[0]),
435398
2 => self.write_word(
@@ -647,7 +610,6 @@ mod tests {
647610
PciMultimediaSubclass::AudioController as u8,
648611
0xABCD,
649612
0x2468,
650-
None,
651613
)
652614
}
653615

src/vmm/src/pci/msix.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::sync::Arc;
99
use byteorder::{ByteOrder, LittleEndian};
1010
use serde::{Deserialize, Serialize};
1111
use vm_memory::ByteValued;
12+
use zerocopy::FromBytes;
1213

1314
use crate::Vm;
1415
use crate::logger::{debug, error, warn};
@@ -209,6 +210,18 @@ impl MsixConfig {
209210
}
210211
}
211212

213+
/// Write to the Message Control register
214+
pub fn write_msg_ctl_register(&mut self, offset: u8, data: &[u8]) {
215+
if offset == 2 && data.len() == 2 {
216+
// 2-bytes write in the Message Control field
217+
self.set_msg_ctl(u16::read_from_bytes(data).unwrap());
218+
} else if offset == 0 && data.len() == 4 {
219+
// 4 bytes write at the beginning. Ignore the first 2 bytes which are the
220+
// capability id and next capability pointer
221+
self.set_msg_ctl((u32::read_from_bytes(data).unwrap() >> 16) as u16);
222+
}
223+
}
224+
212225
/// Read an MSI-X table entry
213226
pub fn read_table(&self, offset: u64, data: &mut [u8]) {
214227
assert!(data.len() <= 8);

0 commit comments

Comments
 (0)