Skip to content

openhcl_tdisp: Add support for TDISP interfaces for VPCI relay layer #2829

Open
mfrohlich-msft wants to merge 20 commits intomicrosoft:mainfrom
mfrohlich-msft:tdisp_openhcl_side
Open

openhcl_tdisp: Add support for TDISP interfaces for VPCI relay layer #2829
mfrohlich-msft wants to merge 20 commits intomicrosoft:mainfrom
mfrohlich-msft:tdisp_openhcl_side

Conversation

@mfrohlich-msft
Copy link
Contributor

@mfrohlich-msft mfrohlich-msft commented Feb 24, 2026

Description:
This PR adds dependencies for OpenHCL clientside functionality for the TDISP protocol. This adds the interfaces which send and receive TDISP packets over the VPCI VMBUS channel while in a relayed Host->VTL2->VTL0 VPCI session.

This PR also implements the VMBUS VPCI server side components of VpciTdispCommand packet processing. This is only used for unit testing flows and is not a plan of record for production.

This still doesn't exercise any functionality of TDISP quite yet. This is still the process of merging in the interface definitions and bindings for future functionality PRs.

Changed Modules:
tdisp/devicereport: Adds crate to parse raw structures returned from TDISP devices as part of the PCI specification.
openhcl/openhcl_tdisp: Adds an OpenHCL-facing facade crate that re-exports the TDISP protocol types from tdisp and tdisp_proto to avoid direct dependencies on those crates from OpenHCL code. Exposes the TdispVirtualDeviceInterface trait and provides make_* command builder functions for all command types.
vm/devices/pci/vpci_client: Updates the VPCI client to implement TdispVirtualDeviceInterface using the new protobuf-based command protocol.
vm/devices/pci/vpci_protocol: Adds TDISP command packet structure and constants to the VPCI VMBUS wire protocol, including the command header, message type, and maximum packet size used for VMBUS framing of TDISP payloads.
vm/devices/pci/vpci/device: Adds support for TDISP host side communication into the VMBUS implementation for OpenVMM+OpenHCL. This support is only used for Unit Testing. In Azure production scenarios, the host side is implemented by an external module.

Tests:
vm/devices/pci/vpci_client/src/tests.rs - Add test_tdisp_interface_get_device_interface_info unit test which takes the OpenHCL VPCI client through a basic TDISP end-to-end packet communication with a local vmbus host.
vm/devices/pci/vpci/src/device.rs - Add verify_tdisp_get_device_interface_info unit test which takes only the host side of the vmbus channel for a vpci client through a basic TDISP end-to-end packet communication.
x86_64::openvmm_openhcl_linux_x64_vpci_relay_tdisp_device - Add new Petri test which ensures that a VPCI device for a synthetic NVMe controller can perform basic VPCI TDISP ned-to-end packet communication.

@mfrohlich-msft mfrohlich-msft marked this pull request as ready for review February 24, 2026 00:33
@mfrohlich-msft mfrohlich-msft requested review from a team as code owners February 24, 2026 00:33
Copilot AI review requested due to automatic review settings February 24, 2026 00:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds TDISP (TEE Device Interface Security Protocol) support to OpenHCL's VPCI relay layer, enabling secure communication between the guest and host for TDISP-enabled devices. The implementation provides a client-side interface for OpenHCL to send TDISP commands over the VPCI VMBUS channel and handle responses from the host.

Changes:

  • Adds openhcl_tdisp facade crate to provide a clean interface for OpenHCL components to interact with TDISP devices without direct dependencies on protocol crates
  • Moves device report structures from protobuf definitions to native Rust structures using zerocopy for efficient binary parsing of raw PCI specification data
  • Implements TdispVirtualDeviceInterface trait on VpciDevice to enable TDISP command dispatch over VMBUS

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
vm/devices/tdisp_proto/src/tdisp.proto Removes device report protobuf messages (moved to native Rust structures)
vm/devices/tdisp_proto/src/lib.rs Adds extension traits for commands/responses and error code handling
vm/devices/tdisp_proto/src/errorcode.rs Adds TdispGuestOperationError enum with conversions from error codes
vm/devices/tdisp_proto/Cargo.toml Adds thiserror dependency for error handling
vm/devices/tdisp/src/lib.rs Re-exports TdispGuestOperationError, adds devicereport module
vm/devices/tdisp/src/devicereport.rs Adds native Rust structures for parsing TDI device reports using zerocopy
vm/devices/tdisp/Cargo.toml Adds bitfield-struct, zerocopy, static_assertions dependencies; removes thiserror
vm/devices/pci/vpci_protocol/src/lib.rs Adds TDISP command structures and MAX_VPCI_TDISP_COMMAND_SIZE constant
vm/devices/pci/vpci_client/src/lib.rs Implements TdispVirtualDeviceInterface trait with command serialization/deserialization
vm/devices/pci/vpci_client/Cargo.toml Adds openhcl_tdisp and tdisp dependencies
openhcl/openhcl_tdisp/src/lib.rs New facade crate with trait definition, re-exports, and command builder functions
openhcl/openhcl_tdisp/Cargo.toml New crate manifest
Cargo.toml Adds openhcl_tdisp workspace member
Cargo.lock Updates lock file with new dependency graph

@mfrohlich-msft mfrohlich-msft requested a review from a team as a code owner February 26, 2026 21:15
tracing::debug!("creating fault controller: tdisp_capable = {tdisp_capable}");

// The fault controller is repurposed for use in TDISP tests.
let tdisp_controller = if tdisp_capable {
Copy link
Contributor

@gurasinghMS gurasinghMS Feb 26, 2026

Choose a reason for hiding this comment

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

Is there any benefit to using a tdisp_capable: bool as the input to new() Instead of accepting
tdisp_controller: Option<TdispHostDeviceTargetEmulator> directly?

Is there any benefit to using a tdisp_capable: bool as the input to new? Accepting
tdisp_controller: Option<TdispHostDeviceTargetEmulator>
might make this cleaner. It would also allow tests to provide different implementations of the TdispHostDeviceTargetEmulator to the controller

Copy link
Contributor

@gurasinghMS gurasinghMS left a comment

Choose a reason for hiding this comment

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

My understanding of tdisp is quite limited, just wondering: What exactly is this test verifying in relation to tdisp? I am assuming that there are some components under the hood that behave differently when a Tdisp supporting device is found (but not sure what those components are really looking for)?

pci_fault_config: PciFaultConfig,
#[inspect(skip)]
fault_active: mesh::Cell<bool>,

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: remove empty line

fn supports_pci(&mut self) -> Option<&mut dyn PciConfigSpace> {
Some(self)
}

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe the idiomatic way to do this might look something like:

/// The NVMe fault controller is repurposed for use in TDISP tests.
   fn supports_tdisp(&mut self) -> Option<&mut dyn TdispHostDeviceTarget> {
       let supported = self.tdisp_controller.is_some();
       tracing::debug!(supported, "fault controller TDISP support in ChipsetDevice");

       self.tdisp_controller
           .as_mut()
           .map(|tdisp| tdisp as &mut dyn TdispHostDeviceTarget)
   }

.collect::<Vec<_>>();

// The NVMe controller should be present after the HCL performs its TDISP test.
assert_eq!(devices, vec![Ok(("00:00.0", "Class 0108: 1414:00a9"))]);
Copy link
Contributor

Choose a reason for hiding this comment

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

When petri is assigning devices, it doesn't deterministically connect the emulator backed drive to sda/sdb. This made some old tests flaky. Off the top of my head I am not sure if this would also impact the location in the pci heirarchy. Just to make sure we cover our bases: are you sure that the controller will always appear at 00:00.0? (If so, feel free to resolve this comment)

Reference:

let device_paths = get_device_paths(

Copy link
Contributor

Choose a reason for hiding this comment

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

P.S. could you also make these string values constants at the top of the test instead?

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.

3 participants