Skip to content

feat: Refine capability and introduce ext cap#72

Merged
junyu0312 merged 1 commit intomainfrom
dev
Feb 15, 2026
Merged

feat: Refine capability and introduce ext cap#72
junyu0312 merged 1 commit intomainfrom
dev

Conversation

@junyu0312
Copy link
Owner

@junyu0312 junyu0312 commented Feb 15, 2026

Summary by CodeRabbit

  • New Features

    • Extended PCI capability support and made configuration-space and error types public.
  • Bug Fixes

    • Improved validation with clear error variants for capability allocation (no space, invalid id/version).
    • Corrected bit masking in MSI‑X capability handling.
  • Refactor

    • Capabilities now get allocated into a provided configuration space and initialization uses Result-based error handling; constructors and call sites updated accordingly.

@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Refactors PCI capability handling: removes the Capability type, introduces a crate Error enum, changes the function trait to init_capability(&mut ConfigurationSpace) -> Result<(), Error>, and implements in-place capability allocation (alloc_capability / alloc_ext_capability) with extended-capability support and header/layout changes.

Changes

Cohort / File(s) Summary
Workspace / dependency
crates/vm-pci/Cargo.toml
Added thiserror.workspace = true to enable workspace usage of thiserror.
Error type
crates/vm-pci/src/error.rs
Added public Error enum with variants CapNoSpace, InvalidCapId, and InvalidCapVersion.
Capability removal & enum adjust
crates/vm-pci/src/device/capability.rs
Removed public Capability(pub Vec<u8>), its From impl and zerocopy imports; changed PciCapId attributes to #[derive(Clone, Copy)] #[repr(u16)].
MSI-X masking tweak
crates/vm-pci/src/device/capability/msix.rs
Masking applied to table_bar and pba_offset when computing table_offset/pba_offset during MSIx capability init.
Trait & constructor changes
crates/vm-pci/src/device/function.rs, crates/vm-pci/src/device/function/type0.rs
Replaced capabilities() -> Vec<Capability> with init_capability(&self, cfg: &mut ConfigurationSpace) -> Result<(), Error>; Type0Function::new now returns Result<Self, Error> and callers must handle errors.
Host bridge update
crates/vm-pci/src/host_bridge.rs
HostBridgeFunction implements init_capability(...)->Result<(), Error) (no allocations); new_host_bridge() updated to return Result<PciDevice, Error> and propagate errors from Type0Function::new.
Public API visibility changes
crates/vm-pci/src/lib.rs, crates/vm-pci/src/types.rs
Exported error and types modules (pub mod); made configuration_space public.
Configuration space refactor
crates/vm-pci/src/types/configuration_space.rs, crates/vm-pci/src/types/configuration_space/header.rs
Reworked layout to track last_capability_next_pointer: u8, next_available_capability_pointer: u16, last_ext_capability_next_pointer: Option<u16>, next_available_ext_capability_pointer: u16; removed capability list init; added public alloc_capability and alloc_ext_capability (with alignment, 2-/4-byte headers, validation, pointer chaining); added ExtendedCapabilityStart = 0x100.
VirtIO PCI integration
crates/vm-virtio/src/transport/pci.rs, crates/vm-virtio/src/device/pci.rs
Replaced vector-based capability construction with sequential cfg.alloc_capability(...) calls and init_capability(...) -> Result<(), Error); some callers now unwrap() the fallible Type0Function::new, introducing potential panics.
Root complex usage
crates/vm-pci/src/root_complex.rs
Changed host bridge creation call site to unwrap the Result from new_host_bridge(), causing a panic on creation error.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 I nibbled bytes and hopped in space,
I swapped out vectors for a steadier pace.
Pointers now link and errors sing,
Caps align with a tidy ring.
Hooray — our PCI garden grows in place! 🌱

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (13 files):

⚔️ Cargo.lock (content)
⚔️ crates/vm-pci/Cargo.toml (content)
⚔️ crates/vm-pci/src/device/capability.rs (content)
⚔️ crates/vm-pci/src/device/capability/msix.rs (content)
⚔️ crates/vm-pci/src/device/function.rs (content)
⚔️ crates/vm-pci/src/device/function/type0.rs (content)
⚔️ crates/vm-pci/src/host_bridge.rs (content)
⚔️ crates/vm-pci/src/lib.rs (content)
⚔️ crates/vm-pci/src/types.rs (content)
⚔️ crates/vm-pci/src/types/configuration_space.rs (content)
⚔️ crates/vm-pci/src/types/configuration_space/header.rs (content)
⚔️ crates/vm-virtio/src/device/pci.rs (content)
⚔️ crates/vm-virtio/src/transport/pci.rs (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: refining the capability system and introducing extended capability support across multiple files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@crates/vm-pci/src/device/capability/msix.rs`:
- Line 31: The pba_offset assignment incorrectly ORs pba_offset with itself
instead of embedding the BAR indicator; update the computation in the msix
capability so pba_offset encodes the BIR in the low 3 bits by ORing the shifted
offset with pba_bar (similar to table_offset logic). In other words, change the
pba_offset expression to use pba_bar as the low bits so the PBA field is formed
by (pba_offset << 3) | pba_bar.

In `@crates/vm-pci/src/types/configuration_space.rs`:
- Around line 91-92: The doc comment above the alloc_ext_capability function is
stale and doesn't match the current signature; update the comment to accurately
describe the parameters and return value of alloc_ext_capability (use the real
parameter names and types and state what the function returns, e.g., allocated
capability offset/region or Result type), and remove or correct the incorrect
phrase "cap_len: The whole length including cap_id and next, return data region"
so the docs reflect the function's actual behavior and error handling in
alloc_ext_capability.
- Around line 65-66: The doc comment for alloc_capability is stale: it mentions
"return data region" but the function signature is pub fn alloc_capability(&mut
self, cap_id: PciCapId, data: &[u8]) -> Result<(), Error>. Update the doc to
accurately describe what alloc_capability does (allocates a PCI capability with
the given cap_id and data), clarify what cap_len means (the total length
including cap_id and next), and state that the function returns Result<(),
Error> (Ok(()) on success or an Error on failure) instead of suggesting it
returns a data region; reference the alloc_capability function and PciCapId
parameter when making the change.
- Around line 92-97: The PciCapId enum is currently #[repr(u8)] which cannot
represent 16-bit extended capability IDs; update the code so
alloc_ext_capability can accept full 16-bit IDs (avoid truncation). Either
change PciCapId to #[repr(u16)] and update all uses, or create a new typed
alias/newtype (e.g., ExtendedPciCapId(u16)) and change the alloc_ext_capability
signature to accept that type (and convert/validate existing 8-bit standard IDs
where needed); ensure any packing/serialization logic that reads/writes
capability IDs (including in configuration_space.rs and functions that iterate
or write capabilities) uses u16 for extended IDs.
🧹 Nitpick comments (4)
crates/vm-virtio/src/device/pci.rs (1)

19-19: Consider propagating the error instead of panicking.

Using .unwrap() will panic if capability allocation fails (e.g., CapNoSpace). While this may be acceptable during development, consider updating into_pci_device to return Result<PciDevice, Error> to properly propagate allocation failures to callers.

♻️ Suggested signature change
-    fn into_pci_device(self) -> PciDevice {
+    fn into_pci_device(self) -> Result<PciDevice, vm_pci::error::Error> {
         let virtio_function = VirtIoPciFunction {
             transport: Arc::new(Mutex::new(self.into())),
         };
-        let function = Type0Function::new(virtio_function).unwrap();
-        PciDevice::from_single_function(Box::new(function))
+        let function = Type0Function::new(virtio_function)?;
+        Ok(PciDevice::from_single_function(Box::new(function)))
     }
crates/vm-pci/src/error.rs (1)

1-7: LGTM with optional enhancement suggestion.

The error enum is well-structured. For debugging purposes, you might consider adding context fields (e.g., requested capability size, available space) to CapNoSpace, though this is optional.

💡 Optional: Add context to error variants
 #[derive(Debug, thiserror::Error)]
 pub enum Error {
-    #[error("no space to allocate capability")]
-    CapNoSpace,
+    #[error("no space to allocate capability (need {needed} bytes, have {available})")]
+    CapNoSpace { needed: usize, available: usize },
     #[error("the cap_version is invalid")]
     InvalidCapVersion,
 }
crates/vm-pci/src/host_bridge.rs (1)

35-35: Consider using expect() instead of unwrap() for clearer panic messages.

While this unwrap() is currently safe (since HostBridgeFunction::init_capability always returns Ok(())), using expect() provides better context if future changes introduce failure paths.

Suggested improvement
 pub fn new_host_bridge() -> PciDevice {
-    let function = Type0Function::new(HostBridgeFunction).unwrap();
+    let function = Type0Function::new(HostBridgeFunction)
+        .expect("host bridge function creation should not fail");
     PciDevice::from_single_function(Box::new(function))
 }
crates/vm-virtio/src/transport/pci.rs (1)

168-180: Assertion validates device config length - consider making this a compile-time check if possible.

The runtime assertion D::DEVICE_SPECIFICATION_CONFIGURATION_LEN <= 0x1000 correctly validates the device configuration size before allocation. If this constant is known at compile time for all device types, a const_assert! would catch violations earlier.

Comment on lines +92 to +97
pub fn alloc_ext_capability(
&mut self,
cap_id: PciCapId,
cap_version: u8,
data: &[u8],
) -> Result<(), Error> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the PciCapId enum definition
fd -t rust . crates/vm-pci/src | xargs rg -l 'enum PciCapId' | head -5

# Search for PciCapId definition with context
rg -n 'enum PciCapId' -A 20 --type rust

Repository: junyu0312/rust-vm

Length of output: 635


🏁 Script executed:

#!/bin/bash
# Check for repr attributes on PciCapId
rg -n '#\[repr' -B 2 -A 15 --type rust | rg -B 5 -A 15 'PciCapId'

Repository: junyu0312/rust-vm

Length of output: 1173


PciCapId must support 16-bit extended capability IDs, but it's defined as #[repr(u8)].

Extended PCI capabilities use 16-bit IDs (0x0000–0xFFFF), while standard capabilities use 8-bit IDs (0x00–0xFF). The PciCapId enum is currently #[repr(u8)], limiting it to 0–255. While example extended capability IDs like AER (0x0001) and DVSEC (0x0023) fit within this range, the type cannot represent the full 16-bit space. Extended capability IDs ≥ 256 will be truncated. Use a separate type or expand PciCapId to #[repr(u16)] for extended capabilities.

🤖 Prompt for AI Agents
In `@crates/vm-pci/src/types/configuration_space.rs` around lines 92 - 97, The
PciCapId enum is currently #[repr(u8)] which cannot represent 16-bit extended
capability IDs; update the code so alloc_ext_capability can accept full 16-bit
IDs (avoid truncation). Either change PciCapId to #[repr(u16)] and update all
uses, or create a new typed alias/newtype (e.g., ExtendedPciCapId(u16)) and
change the alloc_ext_capability signature to accept that type (and
convert/validate existing 8-bit standard IDs where needed); ensure any
packing/serialization logic that reads/writes capability IDs (including in
configuration_space.rs and functions that iterate or write capabilities) uses
u16 for extended IDs.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@crates/vm-pci/src/host_bridge.rs`:
- Around line 34-36: Change new_host_bridge to return Result<PciDevice, Error>
instead of panicking: update the signature pub fn new_host_bridge() ->
Result<PciDevice, Error>, call Type0Function::new(HostBridgeFunction)? to
propagate its Result, then wrap the created function with
PciDevice::from_single_function(Box::new(function)) and return Ok(device). This
replaces the unwrap() and lets callers (e.g., root_complex.rs) handle
initialization errors.

In `@crates/vm-virtio/src/device/pci.rs`:
- Around line 19-20: Type0Function::new(...) is being unwrapped which can panic
on allocation/ID errors; change the PCI constructor to propagate errors by
updating the method that currently returns PciDevice to return Result<PciDevice,
Error>, call Type0Function::new(...) ? instead of unwrap, and return
PciDevice::from_single_function(Box::new(function)) wrapped in Ok(...); also
update the caller in crates/vm-machine/src/device/aarch64.rs to handle the
Result (propagate with ? or handle the Error) so allocation failures from
Type0Function are no longer panics.

Comment on lines +19 to 20
let function = Type0Function::new(virtio_function).unwrap();
PciDevice::from_single_function(Box::new(function))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n crates/vm-virtio/src/device/pci.rs | head -50

Repository: junyu0312/rust-vm

Length of output: 883


🏁 Script executed:

rg -n 'into_pci_device' crates/vm-virtio/src/device/pci.rs -B5 -A5

Repository: junyu0312/rust-vm

Length of output: 535


🏁 Script executed:

rg -n 'Type0Function::new' --type rust -A3 -B3

Repository: junyu0312/rust-vm

Length of output: 970


🏁 Script executed:

rg -n 'fn into_pci_device' --type rust -B5 -A10

Repository: junyu0312/rust-vm

Length of output: 1004


🏁 Script executed:

find crates -name "*.rs" -type f | xargs rg -l "impl.*Type0Function" | head -5

Repository: junyu0312/rust-vm

Length of output: 270


🏁 Script executed:

rg -n "pub fn new" crates/vm-pci/src/device/function/type0.rs -A10 | head -30

Repository: junyu0312/rust-vm

Length of output: 610


🏁 Script executed:

rg -n "Type0Function" crates/vm-pci/src/device/function/type0.rs -B3 -A3 | head -40

Repository: junyu0312/rust-vm

Length of output: 979


🏁 Script executed:

rg -n 'into_pci_device\(\)' --type rust -B2 -A2

Repository: junyu0312/rust-vm

Length of output: 428


🏁 Script executed:

rg -n 'into_pci_device' --type rust

Repository: junyu0312/rust-vm

Length of output: 275


🏁 Script executed:

rg -n 'pub fn from_single_function' crates/vm-pci/src/ -A5

Repository: junyu0312/rust-vm

Length of output: 563


🏁 Script executed:

rg -n 'enum Error' crates/vm-pci/src/error.rs -A10

Repository: junyu0312/rust-vm

Length of output: 281


🏁 Script executed:

rg -n 'fn init_capability' --type rust -B2 -A5 | head -30

Repository: junyu0312/rust-vm

Length of output: 1427


🏁 Script executed:

cat crates/vm-machine/src/device/aarch64.rs | sed -n '30,45p'

Repository: junyu0312/rust-vm

Length of output: 481


Replace unwrap() with error propagation on Type0Function::new().

Type0Function::new() returns Result<Self, Error> with real failure modes (capability allocation exhaustion, invalid IDs). The current unwrap() at line 19 will panic on CapNoSpace, InvalidCapId, or InvalidCapVersion errors instead of propagating them. Update the trait method signature to return Result<PciDevice, Error> so callers can handle these allocation failures gracefully.

Suggested fix
+use vm_pci::error::Error;
@@
-    fn into_pci_device(self) -> PciDevice {
+    fn into_pci_device(self) -> Result<PciDevice, Error> {
         let virtio_function = VirtIoPciFunction {
             transport: Arc::new(Mutex::new(self.into())),
         };
-        let function = Type0Function::new(virtio_function).unwrap();
-        PciDevice::from_single_function(Box::new(function))
+        let function = Type0Function::new(virtio_function)?;
+        Ok(PciDevice::from_single_function(Box::new(function)))
     }

Update the call site in crates/vm-machine/src/device/aarch64.rs:36 to handle the Result.

🤖 Prompt for AI Agents
In `@crates/vm-virtio/src/device/pci.rs` around lines 19 - 20,
Type0Function::new(...) is being unwrapped which can panic on allocation/ID
errors; change the PCI constructor to propagate errors by updating the method
that currently returns PciDevice to return Result<PciDevice, Error>, call
Type0Function::new(...) ? instead of unwrap, and return
PciDevice::from_single_function(Box::new(function)) wrapped in Ok(...); also
update the caller in crates/vm-machine/src/device/aarch64.rs to handle the
Result (propagate with ? or handle the Error) so allocation failures from
Type0Function are no longer panics.

@junyu0312 junyu0312 merged commit a43d298 into main Feb 15, 2026
1 check was pending
@coderabbitai coderabbitai bot mentioned this pull request Mar 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant