diff --git a/src/devices/vmcall_raw/src/stream.rs b/src/devices/vmcall_raw/src/stream.rs index da641ca1..30c99afa 100644 --- a/src/devices/vmcall_raw/src/stream.rs +++ b/src/devices/vmcall_raw/src/stream.rs @@ -4,7 +4,7 @@ use crate::transport::vmcall::{ vmcall_raw_transport_can_recv, vmcall_raw_transport_dequeue, vmcall_raw_transport_enqueue, - vmcall_raw_transport_init, VMCALL_MIG_CONTEXT_FLAGS, + vmcall_raw_transport_init, VMCALL_MIG_CONTEXT_FLAGS, VMCALL_RAW_SEND_PAYLOAD_MTU, }; use core::sync::atomic::AtomicBool; @@ -61,7 +61,17 @@ impl VmcallRaw { } pub async fn send(&mut self, buf: &[u8], _flags: u32) -> Result { - let _ = vmcall_raw_transport_enqueue(self, buf).await?; + // A single Service.MigTD.Send VMCALL can only carry one MTU-sized + // payload (the same cap the receive side advertises). Chunk here so + // callers that don't loop on partial writes (TLS, SPDM transport) + // keep working when the pre-session policy + issuer chain blob + // exceeds one VMCALL. + let mut sent = 0; + while sent < buf.len() { + let end = core::cmp::min(buf.len(), sent + VMCALL_RAW_SEND_PAYLOAD_MTU); + let _ = vmcall_raw_transport_enqueue(self, &buf[sent..end]).await?; + sent = end; + } Ok(buf.len()) } diff --git a/src/devices/vmcall_raw/src/transport/vmcall.rs b/src/devices/vmcall_raw/src/transport/vmcall.rs index 7835e6da..7081dcd7 100644 --- a/src/devices/vmcall_raw/src/transport/vmcall.rs +++ b/src/devices/vmcall_raw/src/transport/vmcall.rs @@ -18,7 +18,16 @@ use td_payload::arch::idt::InterruptStack; use td_payload::mm::shared::SharedMemory; use tdx_tdcall::tdx; -const MAX_VMCALL_RAW_STREAM_MTU: usize = 0x1000 * 16; +pub(crate) const MAX_VMCALL_RAW_STREAM_MTU: usize = 0x1000 * 16; +/// GHCI 1.5 buffer header overhead (8-byte status + 4-byte length) prepended +/// by `vmcall_raw_transport_enqueue` to each VMCALL payload. +pub(crate) const VMCALL_RAW_GHCI_HEADER_LEN: usize = 12; +/// Largest payload that can ride in a single `Service.MigTD.Send` VMCALL. +/// The VMM-side buffer for the migration data channel matches the MTU the +/// receive side advertises; sending more than this in one VMCALL fails with +/// TDX_VMCALL_STATUS != SUCCESS. +pub(crate) const VMCALL_RAW_SEND_PAYLOAD_MTU: usize = + MAX_VMCALL_RAW_STREAM_MTU - VMCALL_RAW_GHCI_HEADER_LEN; const VMCALL_VECTOR: u8 = 0x52; lazy_static! {