openhcl_tdisp: Add support for TDISP interfaces for VPCI relay layer #2829
openhcl_tdisp: Add support for TDISP interfaces for VPCI relay layer #2829mfrohlich-msft wants to merge 20 commits intomicrosoft:mainfrom
Conversation
Add openhcl_tdisp dependency crate Add tdisp handlers to vpci protocol Handle case where packet is empty but host returns success
…arsed from C structs
There was a problem hiding this comment.
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_tdispfacade 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
TdispVirtualDeviceInterfacetrait onVpciDeviceto 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 |
e6501e5 to
268574a
Compare
…controller nvme device in openvmm
268574a to
6491888
Compare
| 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 { |
There was a problem hiding this comment.
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
gurasinghMS
left a comment
There was a problem hiding this comment.
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>, | ||
|
|
There was a problem hiding this comment.
nit: remove empty line
| fn supports_pci(&mut self) -> Option<&mut dyn PciConfigSpace> { | ||
| Some(self) | ||
| } | ||
|
|
There was a problem hiding this comment.
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"))]); |
There was a problem hiding this comment.
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:
There was a problem hiding this comment.
P.S. could you also make these string values constants at the top of the test instead?
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 implementTdispVirtualDeviceInterfaceusing 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- Addtest_tdisp_interface_get_device_interface_infounit 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- Addverify_tdisp_get_device_interface_infounit 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.