Skip to content

Commit 6643c3e

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 bef3b9d commit 6643c3e

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)]
@@ -280,6 +281,8 @@ pub struct VirtioPciDevice {
280281

281282
// BARs region for the device
282283
pub bars: Bars,
284+
pub msix_config_cap_offset: u16,
285+
pub msix_config: Arc<Mutex<MsixConfig>>,
283286
}
284287

285288
impl Debug for VirtioPciDevice {
@@ -319,7 +322,6 @@ impl VirtioPciDevice {
319322
subclass,
320323
VIRTIO_PCI_VENDOR_ID,
321324
pci_device_id,
322-
Some(msix_config.clone()),
323325
)
324326
}
325327

@@ -396,6 +398,8 @@ impl VirtioPciDevice {
396398
memory,
397399
cap_pci_cfg_info: VirtioPciCfgCapInfo::default(),
398400
bars: Bars::default(),
401+
msix_config,
402+
msix_config_cap_offset: 0,
399403
};
400404

401405
Ok(virtio_pci_device)
@@ -411,10 +415,7 @@ impl VirtioPciDevice {
411415
let vectors = msix_config.vectors.clone();
412416
let msix_config = Arc::new(Mutex::new(msix_config));
413417

414-
let pci_config = PciConfiguration::type0_from_state(
415-
state.pci_configuration_state,
416-
Some(msix_config.clone()),
417-
)?;
418+
let pci_config = PciConfiguration::type0_from_state(state.pci_configuration_state)?;
418419
let virtio_common_config = VirtioPciCommonConfig::new(state.pci_dev_state);
419420
let cap_pci_cfg_info = VirtioPciCfgCapInfo {
420421
offset: state.cap_pci_cfg_offset,
@@ -442,6 +443,8 @@ impl VirtioPciDevice {
442443
memory: vm.guest_memory().clone(),
443444
cap_pci_cfg_info,
444445
bars: state.bars,
446+
msix_config,
447+
msix_config_cap_offset: state.msix_config_cap_offset,
445448
};
446449

447450
if state.device_activated {
@@ -523,7 +526,10 @@ impl VirtioPciDevice {
523526
VIRTIO_BAR_INDEX,
524527
MSIX_PBA_BAR_OFFSET,
525528
);
526-
self.configuration.add_capability(&msix_cap);
529+
// The whole Configuration region is 4K, so u16 can address it all
530+
#[allow(clippy::cast_possible_truncation)]
531+
let offset = self.configuration.add_capability(&msix_cap) as u16;
532+
self.msix_config_cap_offset = offset;
527533
}
528534
}
529535

@@ -626,6 +632,7 @@ impl VirtioPciDevice {
626632
.expect("Poisoned lock")
627633
.state(),
628634
bars: self.bars,
635+
msix_config_cap_offset: self.msix_config_cap_offset,
629636
}
630637
}
631638
}
@@ -736,16 +743,21 @@ impl PciDevice for VirtioPciDevice {
736743
self.bars.write(bar_idx, offset, data);
737744
None
738745
} else {
739-
// Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
740-
// is accessed. This capability has a special meaning as it allows the
741-
// guest to access other capabilities without mapping the PCI BAR.
742-
let base = reg_idx as usize * 4;
743-
if base + offset as usize >= self.cap_pci_cfg_info.offset as usize
744-
&& base + offset as usize + data.len()
746+
// Handle access to the header of the MsixCapability. The rest of the
747+
// capability is handled by the PciConfiguration.
748+
let base = reg_idx * 4;
749+
if base == self.msix_config_cap_offset {
750+
self.msix_config
751+
.lock()
752+
.unwrap()
753+
.write_msg_ctl_register(offset, data);
754+
}
755+
if base + u16::from(offset) >= self.cap_pci_cfg_info.offset
756+
&& (base + u16::from(offset)) as usize + data.len()
745757
<= self.cap_pci_cfg_info.offset as usize
746758
+ self.cap_pci_cfg_info.cap.bytes().len()
747759
{
748-
let offset = base + offset as usize - self.cap_pci_cfg_info.offset as usize;
760+
let offset = (base + u16::from(offset) - self.cap_pci_cfg_info.offset) as usize;
749761
self.write_cap_pci_cfg(offset, data)
750762
} else {
751763
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

@@ -175,7 +172,6 @@ pub struct PciConfigurationState {
175172
registers: Vec<u32>,
176173
writable_bits: Vec<u32>,
177174
last_capability: Option<(u8, u8)>,
178-
msix_cap_reg_idx: Option<u16>,
179175
}
180176

181177
#[derive(Debug)]
@@ -188,8 +184,6 @@ pub struct PciConfiguration {
188184
writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
189185
// Contains the byte offset and size of the last capability.
190186
last_capability: Option<(u8, u8)>,
191-
msix_cap_reg_idx: Option<u16>,
192-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
193187
}
194188

195189
impl PciConfiguration {
@@ -203,7 +197,6 @@ impl PciConfiguration {
203197
subclass: u8,
204198
subsystem_vendor_id: u16,
205199
subsystem_id: u16,
206-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
207200
) -> Self {
208201
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
209202
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
@@ -222,16 +215,11 @@ impl PciConfiguration {
222215
registers,
223216
writable_bits,
224217
last_capability: None,
225-
msix_cap_reg_idx: None,
226-
msix_config,
227218
}
228219
}
229220

230221
/// Create a type 0 PCI configuration from snapshot state
231-
pub fn type0_from_state(
232-
state: PciConfigurationState,
233-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
234-
) -> Result<Self, PciConfigurationError> {
222+
pub fn type0_from_state(state: PciConfigurationState) -> Result<Self, PciConfigurationError> {
235223
let reg_len = state.registers.len();
236224
let registers = state
237225
.registers
@@ -248,8 +236,6 @@ impl PciConfiguration {
248236
registers,
249237
writable_bits,
250238
last_capability: state.last_capability,
251-
msix_cap_reg_idx: state.msix_cap_reg_idx,
252-
msix_config,
253239
})
254240
}
255241

@@ -259,7 +245,6 @@ impl PciConfiguration {
259245
registers: self.registers.to_vec(),
260246
writable_bits: self.writable_bits.to_vec(),
261247
last_capability: self.last_capability,
262-
msix_cap_reg_idx: self.msix_cap_reg_idx,
263248
}
264249
}
265250

@@ -373,9 +358,7 @@ impl PciConfiguration {
373358
self.writable_bits[(cap_offset / 4) as usize] = MSI_CAPABILITY_REGISTER_MASK;
374359
}
375360
PciCapabilityId::MsiX => {
376-
self.msix_cap_reg_idx = Some(u16::from(cap_offset) / 4);
377-
self.writable_bits[self.msix_cap_reg_idx.unwrap() as usize] =
378-
MSIX_CAPABILITY_REGISTER_MASK;
361+
self.writable_bits[(cap_offset / 4) as usize] = MSIX_CAPABILITY_REGISTER_MASK;
379362
}
380363
_ => {}
381364
}
@@ -399,26 +382,6 @@ impl PciConfiguration {
399382
return;
400383
}
401384

402-
// Handle potential write to MSI-X message control register
403-
if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx
404-
&& let Some(msix_config) = &self.msix_config
405-
{
406-
if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 {
407-
// 2-bytes write in the Message Control field
408-
msix_config
409-
.lock()
410-
.unwrap()
411-
.set_msg_ctl(LittleEndian::read_u16(data));
412-
} else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
413-
// 4 bytes write at the beginning. Ignore the first 2 bytes which are the
414-
// capability id and next capability pointer
415-
msix_config
416-
.lock()
417-
.unwrap()
418-
.set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
419-
}
420-
}
421-
422385
match data.len() {
423386
1 => self.write_byte(reg_idx * 4 + offset as u16, data[0]),
424387
2 => self.write_word(
@@ -636,7 +599,6 @@ mod tests {
636599
PciMultimediaSubclass::AudioController as u8,
637600
0xABCD,
638601
0x2468,
639-
None,
640602
)
641603
}
642604

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)