Skip to content

Commit 65843de

Browse files
authored
Move PCI from bitflags to bitfield-struct (#462)
Part of moving all of our bitfield types to bitfield-struct. Only IDE is left I think. There could definitely be more cleanup here to make things more idiomatic, but I'm just trying to do a minimum viable change here for now.
1 parent 0dffce5 commit 65843de

File tree

10 files changed

+170
-116
lines changed

10 files changed

+170
-116
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4953,7 +4953,7 @@ dependencies = [
49534953
name = "pci_core"
49544954
version = "0.0.0"
49554955
dependencies = [
4956-
"bitflags 1.3.2",
4956+
"bitfield-struct",
49574957
"chipset_device",
49584958
"guestmem",
49594959
"inspect",

vm/devices/pci/pci_core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ chipset_device.workspace = true
1111
guestmem.workspace = true
1212
vmcore.workspace = true
1313

14+
bitfield-struct.workspace = true
1415
inspect.workspace = true
1516
mesh.workspace = true
1617
open_enum.workspace = true
17-
bitflags.workspace = true
1818
parking_lot.workspace = true
1919
thiserror.workspace = true
2020
tracelimit.workspace = true

vm/devices/pci/pci_core/src/bar_mapping.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl BarMappings {
4242
let bar_address;
4343
let mut bar_mask;
4444
let len;
45-
if bar_masks[i] & cfg_space::BarEncodingBits::TYPE_64_BIT.bits() != 0 {
45+
if cfg_space::BarEncodingBits::from_bits(bar_masks[i]).type_64_bit() {
4646
bar_mask = (bar_masks[i + 1] as u64) << 32 | bar_masks[i] as u64;
4747
bar_address = (base_addresses[i + 1] as u64) << 32 | base_addresses[i] as u64;
4848
len = 2;

vm/devices/pci/pci_core/src/cfg_space_emu.rs

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ use std::sync::atomic::Ordering;
2323
use std::sync::Arc;
2424
use vmcore::line_interrupt::LineInterrupt;
2525

26+
const SUPPORTED_COMMAND_BITS: u16 = cfg_space::Command::new()
27+
.with_pio_enabled(true)
28+
.with_mmio_enabled(true)
29+
.with_bus_master(true)
30+
.with_special_cycles(true)
31+
.with_enable_memory_write_invalidate(true)
32+
.with_vga_palette_snoop(true)
33+
.with_parity_error_response(true)
34+
.with_enable_serr(true)
35+
.with_enable_fast_b2b(true)
36+
.with_intx_disable(true)
37+
.into_bits();
38+
2639
/// A wrapper around a [`LineInterrupt`] that considers PCI configuration space
2740
/// interrupt control bits.
2841
#[derive(Debug, Inspect)]
@@ -98,7 +111,7 @@ impl ConfigSpaceType0EmulatorState {
98111
fn new() -> Self {
99112
Self {
100113
latency_timer: 0,
101-
command: cfg_space::Command::empty(),
114+
command: cfg_space::Command::new(),
102115
base_addresses: [0; 6],
103116
interrupt_line: 0,
104117
}
@@ -247,7 +260,9 @@ impl ConfigSpaceType0Emulator {
247260
const MIN_BAR_SIZE: u64 = 4096;
248261
let len = std::cmp::max(len.next_power_of_two(), MIN_BAR_SIZE);
249262
let mask64 = !(len - 1);
250-
bar_masks[bar_index] = mask64 as u32 | cfg_space::BarEncodingBits::TYPE_64_BIT.bits();
263+
bar_masks[bar_index] = cfg_space::BarEncodingBits::from_bits(mask64 as u32)
264+
.with_type_64_bit(true)
265+
.into_bits();
251266
bar_masks[bar_index + 1] = (mask64 >> 32) as u32;
252267
mapped_memory[bar_index] = Some(mapped);
253268
}
@@ -264,7 +279,7 @@ impl ConfigSpaceType0Emulator {
264279
intx_interrupt: None,
265280

266281
state: ConfigSpaceType0EmulatorState {
267-
command: cfg_space::Command::empty(),
282+
command: cfg_space::Command::new(),
268283
base_addresses: [0; 6],
269284
interrupt_line: 0,
270285
latency_timer: 0,
@@ -332,18 +347,16 @@ impl ConfigSpaceType0Emulator {
332347
(self.hardware_ids.device_id as u32) << 16 | self.hardware_ids.vendor_id as u32
333348
}
334349
HeaderType00::STATUS_COMMAND => {
335-
let mut status = cfg_space::Status::empty();
336-
if !self.capabilities.is_empty() {
337-
status |= cfg_space::Status::CAPABILITIES_LIST;
338-
}
350+
let mut status =
351+
cfg_space::Status::new().with_capabilities_list(!self.capabilities.is_empty());
339352

340353
if let Some(intx_interrupt) = &self.intx_interrupt {
341354
if intx_interrupt.interrupt_status.load(Ordering::SeqCst) {
342-
status |= cfg_space::Status::INTERRUPT_STATUS;
355+
status.set_interrupt_status(true);
343356
}
344357
}
345358

346-
(status.bits() as u32) << 16 | self.state.command.bits() as u32
359+
(status.into_bits() as u32) << 16 | self.state.command.into_bits() as u32
347360
}
348361
HeaderType00::CLASS_REVISION => {
349362
(u8::from(self.hardware_ids.base_class) as u32) << 24
@@ -436,12 +449,12 @@ impl ConfigSpaceType0Emulator {
436449

437450
fn update_intx_disable(&mut self, command: cfg_space::Command) {
438451
if let Some(intx_interrupt) = &self.intx_interrupt {
439-
intx_interrupt.set_disabled(command.contains(cfg_space::Command::INTX_DISABLE))
452+
intx_interrupt.set_disabled(command.intx_disable())
440453
}
441454
}
442455

443456
fn update_mmio_enabled(&mut self, command: cfg_space::Command) {
444-
if command.contains(cfg_space::Command::MMIO_ENABLED) {
457+
if command.mmio_enabled() {
445458
self.active_bars = BarMappings::parse(&self.state.base_addresses, &self.bar_masks);
446459
for (bar, mapping) in self.mapped_memory.iter_mut().enumerate() {
447460
if let Some(mapping) = mapping {
@@ -478,30 +491,19 @@ impl ConfigSpaceType0Emulator {
478491

479492
match HeaderType00(offset) {
480493
HeaderType00::STATUS_COMMAND => {
481-
let command = match cfg_space::Command::from_bits(val as u16) {
482-
Some(command) => command,
483-
None => {
484-
tracelimit::warn_ratelimited!(offset, val, "setting invalid command bits");
485-
// still do our best
486-
cfg_space::Command::from_bits_truncate(val as u16)
487-
}
494+
let mut command = cfg_space::Command::from_bits(val as u16);
495+
if command.into_bits() & !SUPPORTED_COMMAND_BITS != 0 {
496+
tracelimit::warn_ratelimited!(offset, val, "setting invalid command bits");
497+
// still do our best
498+
command =
499+
cfg_space::Command::from_bits(command.into_bits() & SUPPORTED_COMMAND_BITS);
488500
};
489501

490-
if self
491-
.state
492-
.command
493-
.contains(cfg_space::Command::INTX_DISABLE)
494-
!= command.contains(cfg_space::Command::INTX_DISABLE)
495-
{
502+
if self.state.command.intx_disable() != command.intx_disable() {
496503
self.update_intx_disable(command)
497504
}
498505

499-
if self
500-
.state
501-
.command
502-
.contains(cfg_space::Command::MMIO_ENABLED)
503-
!= command.contains(cfg_space::Command::MMIO_ENABLED)
504-
{
506+
if self.state.command.mmio_enabled() != command.mmio_enabled() {
505507
self.update_mmio_enabled(command)
506508
}
507509

@@ -518,15 +520,13 @@ impl ConfigSpaceType0Emulator {
518520
| HeaderType00::BAR3
519521
| HeaderType00::BAR4
520522
| HeaderType00::BAR5 => {
521-
if !self
522-
.state
523-
.command
524-
.contains(cfg_space::Command::MMIO_ENABLED)
525-
{
523+
if !self.state.command.mmio_enabled() {
526524
let bar_index = (offset - HeaderType00::BAR0.0) as usize / 4;
527525
let mut bar_value = val & self.bar_masks[bar_index];
528526
if bar_index & 1 == 0 && self.bar_masks[bar_index] != 0 {
529-
bar_value |= cfg_space::BarEncodingBits::TYPE_64_BIT.bits();
527+
bar_value = cfg_space::BarEncodingBits::from_bits(bar_value)
528+
.with_type_64_bit(true)
529+
.into_bits();
530530
}
531531
self.state.base_addresses[bar_index] = bar_value;
532532
}
@@ -623,7 +623,7 @@ mod save_restore {
623623
} = self.state;
624624

625625
let saved_state = state::SavedState {
626-
command: command.bits(),
626+
command: command.into_bits(),
627627
base_addresses,
628628
interrupt_line,
629629
latency_timer,
@@ -650,16 +650,18 @@ mod save_restore {
650650
} = state;
651651

652652
self.state = ConfigSpaceType0EmulatorState {
653-
command: cfg_space::Command::from_bits(command).ok_or(
654-
RestoreError::InvalidSavedState(
655-
ConfigSpaceRestoreError::InvalidConfigBits.into(),
656-
),
657-
)?,
653+
command: cfg_space::Command::from_bits(command),
658654
base_addresses,
659655
interrupt_line,
660656
latency_timer,
661657
};
662658

659+
if command & !SUPPORTED_COMMAND_BITS != 0 {
660+
return Err(RestoreError::InvalidSavedState(
661+
ConfigSpaceRestoreError::InvalidConfigBits.into(),
662+
));
663+
}
664+
663665
self.sync_command_register(self.state.command);
664666
for (id, entry) in capabilities {
665667
tracing::debug!(save_id = id.as_str(), "restoring pci capability");

vm/devices/pci/pci_core/src/spec.rs

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ pub mod hwid {
186186
/// Sources: PCI 2.3 Spec - Chapter 6
187187
#[allow(missing_docs)] // primarily enums/structs with self-explanatory variants
188188
pub mod cfg_space {
189+
use bitfield_struct::bitfield;
189190
use inspect::Inspect;
190191
use zerocopy::AsBytes;
191192
use zerocopy::FromBytes;
@@ -236,63 +237,92 @@ pub mod cfg_space {
236237

237238
pub const HEADER_TYPE_00_SIZE: u16 = 0x40;
238239

239-
bitflags::bitflags! {
240-
/// BAR in-band encoding bits.
241-
///
242-
/// The low bits of the BAR are not actually part of the address.
243-
/// Instead, they are used to in-band encode various bits of
244-
/// metadata about the BAR, and are masked off when determining the
245-
/// actual address.
246-
pub struct BarEncodingBits: u32 {
247-
const USE_PIO = 1 << 0;
248-
// only used in MMIO
249-
const TYPE_32_BIT = 0b00 << 1;
250-
const TYPE_64_BIT = 0b10 << 1;
251-
const PREFETCHABLE = 1 << 3;
252-
}
240+
/// BAR in-band encoding bits.
241+
///
242+
/// The low bits of the BAR are not actually part of the address.
243+
/// Instead, they are used to in-band encode various bits of
244+
/// metadata about the BAR, and are masked off when determining the
245+
/// actual address.
246+
#[bitfield(u32)]
247+
pub struct BarEncodingBits {
248+
pub use_pio: bool,
249+
250+
_reserved: bool,
251+
252+
/// False indicates 32 bit.
253+
/// Only used in MMIO
254+
pub type_64_bit: bool,
255+
pub prefetchable: bool,
256+
257+
#[bits(28)]
258+
_reserved2: u32,
253259
}
254260

255-
bitflags::bitflags! {
256-
/// Command Register
257-
#[derive(AsBytes, FromBytes, FromZeroes, Inspect)]
258-
#[repr(transparent)]
259-
#[inspect(debug)]
260-
pub struct Command: u16 {
261-
const PIO_ENABLED = 1 << 0;
262-
const MMIO_ENABLED = 1 << 1;
263-
const BUS_MASTER = 1 << 2;
264-
const SPECIAL_CYCLES = 1 << 3;
265-
const ENABLE_MEMORY_WRITE_INVALIDATE = 1 << 4;
266-
const VGA_PALETTE_SNOOP = 1 << 5;
267-
const PARITY_ERROR_RESPONSE = 1 << 6;
268-
// const RESERVED = 1 << 7; // must be 0
269-
const ENABLE_SERR = 1 << 8;
270-
const ENABLE_FAST_B2B = 1 << 9;
271-
const INTX_DISABLE = 1 << 10;
272-
// rest of bits are reserved
273-
}
261+
/// Command Register
262+
#[derive(Inspect)]
263+
#[bitfield(u16)]
264+
#[derive(AsBytes, FromBytes, FromZeroes)]
265+
pub struct Command {
266+
pub pio_enabled: bool,
267+
pub mmio_enabled: bool,
268+
pub bus_master: bool,
269+
pub special_cycles: bool,
270+
pub enable_memory_write_invalidate: bool,
271+
pub vga_palette_snoop: bool,
272+
pub parity_error_response: bool,
273+
/// must be 0
274+
#[bits(1)]
275+
_reserved: u16,
276+
pub enable_serr: bool,
277+
pub enable_fast_b2b: bool,
278+
pub intx_disable: bool,
279+
#[bits(5)]
280+
_reserved2: u16,
281+
}
282+
283+
/// Status Register
284+
#[bitfield(u16)]
285+
#[derive(AsBytes, FromBytes, FromZeroes)]
286+
pub struct Status {
287+
#[bits(3)]
288+
_reserved: u16,
289+
pub interrupt_status: bool,
290+
pub capabilities_list: bool,
291+
pub capable_mhz_66: bool,
292+
_reserved2: bool,
293+
pub capable_fast_b2b: bool,
294+
pub err_master_parity: bool,
295+
296+
#[bits(2)]
297+
pub devsel: DevSel,
298+
299+
pub abort_target_signaled: bool,
300+
pub abort_target_received: bool,
301+
pub abort_master_received: bool,
302+
pub err_signaled: bool,
303+
pub err_detected_parity: bool,
274304
}
275305

276-
bitflags::bitflags! {
277-
/// Status Register
278-
#[derive(AsBytes, FromBytes, FromZeroes)]
279-
#[repr(transparent)]
280-
pub struct Status: u16 {
281-
// const RESERVED = 0b000 << 0;
282-
const INTERRUPT_STATUS = 1 << 3;
283-
const CAPABILITIES_LIST = 1 << 4;
284-
const CAPABLE_MHZ_66 = 1 << 5;
285-
// const RESERVED = 1 << 6;
286-
const CAPABLE_FAST_B2B = 1 << 7;
287-
const ERR_MASTER_PARITY = 1 << 8;
288-
const DEVSEL_FAST = 0b00 << 10;
289-
const DEVSEL_MED = 0b01 << 10;
290-
const DEVSEL_SLOW = 0b10 << 10;
291-
const ABORT_TARGET_SIGNALED = 1 << 11;
292-
const ABORT_TARGET_RECEIVED = 1 << 12;
293-
const ABORT_MASTER_RECEIVED = 1 << 13;
294-
const ERR_SIGNALED = 1 << 14;
295-
const ERR_DETECTED_PARITY = 1 << 15;
306+
#[derive(Debug)]
307+
#[repr(u16)]
308+
pub enum DevSel {
309+
Fast = 0b00,
310+
Medium = 0b01,
311+
Slow = 0b10,
312+
}
313+
314+
impl DevSel {
315+
const fn from_bits(bits: u16) -> Self {
316+
match bits {
317+
0b00 => DevSel::Fast,
318+
0b01 => DevSel::Medium,
319+
0b10 => DevSel::Slow,
320+
_ => unreachable!(),
321+
}
322+
}
323+
324+
const fn into_bits(self) -> u16 {
325+
self as u16
296326
}
297327
}
298328
}

0 commit comments

Comments
 (0)