Coverage Report

Created: 2026-10-28 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MigTD/deps/td-shim/tdx-tdcall/src/lib.rs
Line
Count
Source
1
// Copyright (c) 2020-2025 Intel Corporation
2
//
3
// SPDX-License-Identifier: BSD-2-Clause-Patent
4
5
//! Guest-Side (TDCALL) Interface Helper Functions
6
//!
7
//! This crate implements the helper functions for the TDCALL interface functions defined in
8
//! Intel TDX Module specifiction and the TDVMCALL sub-functions defined in Intel TDX
9
//! Guest-Hypervisor Communication Interface specification. It also provides the constants
10
//! and data structures that are defined in the specifications.
11
//!
12
//! Please refer to following links for detail:
13
//! [Intel TDX Module v1.0 Spec](https://www.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf)
14
//! [Intel TDX Module v1.5 Spec](https://www.intel.com/content/dam/develop/external/us/en/documents/intel-tdx-module-1.5-abi-spec-348551001.pdf)
15
//! [Intel TDX Guest-Hypervisor Communication Interface Spec](https://cdrdv2.intel.com/v1/dl/getContent/726790)
16
//! [Intel TDX Guest-Hypervisor Communication Interface Spec v1.5](https://cdrdv2.intel.com/v1/dl/getContent/726792)
17
//!
18
//! A subset of TDCALL interface functions is defined in crate::tdx, and the TDG.MR.REPORT
19
//! leaf function and TDREPORT_STRUCT related definitions are defined in crate::tdreport
20
//! separately.
21
22
#![no_std]
23
24
use core::ffi::c_void;
25
26
#[cfg(feature = "use_tdx_emulation")]
27
pub const USE_TDX_EMULATION: bool = true;
28
#[cfg(not(feature = "use_tdx_emulation"))]
29
pub const USE_TDX_EMULATION: bool = false;
30
31
#[cfg(not(feature = "no-tdaccept"))]
32
pub const TDACCEPT_SUPPORT: bool = true;
33
#[cfg(feature = "no-tdaccept")]
34
pub const TDACCEPT_SUPPORT: bool = false;
35
36
pub mod asm;
37
pub mod tdreport;
38
pub mod tdx;
39
40
// Guest-Side (TDCALL) interface functions leaf numbers
41
const TDCALL_TDINFO: u64 = 1;
42
const TDCALL_TDEXTENDRTMR: u64 = 2;
43
const TDCALL_TDGETVEINFO: u64 = 3;
44
const TDCALL_TDREPORT: u64 = 4;
45
#[cfg(not(feature = "no-tdaccept"))]
46
const TDCALL_TDACCEPTPAGE: u64 = 6;
47
const TDCALL_VM_RD: u64 = 7;
48
const TDCALL_VM_WR: u64 = 8;
49
const TDCALL_VP_RD: u64 = 9;
50
const TDCALL_VP_WR: u64 = 10;
51
const TDCALL_SYS_RD: u64 = 11;
52
const TDCALL_SERVTD_RD: u64 = 18;
53
const TDCALL_SERVTD_WR: u64 = 20;
54
const TDCALL_VERIFYREPORT: u64 = 22;
55
const TDCALL_MEM_PAGE_ATTR_WR: u64 = 24;
56
const TDCALL_VP_ENTER: u64 = 25;
57
const TDCALL_VP_INVEPT: u64 = 26;
58
const TDCALL_VP_INVVPID: u64 = 27;
59
const TDCALL_SERVTD_REBIND_APPROVE: u64 = 33;
60
#[cfg(feature = "tdg_dbg")]
61
const TDCALL_TDG_DEBUG: u64 = 254;
62
63
// TDCALL completion status code
64
const TDCALL_STATUS_SUCCESS: u64 = 0;
65
66
// leaf-specific completion status code
67
pub const TDCALL_STATUS_PAGE_ALREADY_ACCEPTED: u64 = 0x00000B0A00000000;
68
pub const TDCALL_STATUS_PAGE_SIZE_MISMATCH: u64 = 0xC0000B0B00000001;
69
70
cfg_if::cfg_if! {
71
    if #[cfg(not(feature = "no-tdvmcall"))] {
72
        // GTDG.VP.VMCALL leaf sub-function numbers
73
        const TDVMCALL_CPUID: u64 = 0x0000a;
74
        const TDVMCALL_HALT: u64 = 0x0000c;
75
        const TDVMCALL_IO: u64 = 0x0001e;
76
        const TDVMCALL_RDMSR: u64 = 0x0001f;
77
        const TDVMCALL_WRMSR: u64 = 0x00020;
78
        const TDVMCALL_MMIO: u64 = 0x00030;
79
        const TDVMCALL_MAPGPA: u64 = 0x10001;
80
        const TDVMCALL_GETQUOTE: u64 = 0x10002;
81
        const TDVMCALL_REPORTFATALERROR: u64 = 0x10003;
82
        const TDVMCALL_SETUPEVENTNOTIFY: u64 = 0x10004;
83
        const TDVMCALL_SERVICE: u64 = 0x10005;
84
        const TDVMCALL_MIGTD: u64 = 0x10006;
85
86
        // TDVMCALL completion status code
87
        const TDVMCALL_STATUS_SUCCESS: u64 = 0;
88
        const TDVMCALL_STATUS_RETRY: u64 = 1;
89
90
        // TDVMCALL<MigTD> leaf function numbers
91
        const TDVMCALL_MIGTD_WAITFORREQUEST: u16 = 1;
92
        const TDVMCALL_MIGTD_REPORTSTATUS: u16 = 2;
93
        const TDVMCALL_MIGTD_SEND: u16= 3;
94
        const TDVMCALL_MIGTD_RECEIVE: u16 = 4;
95
    }
96
}
97
98
// A public wrapper for use of asm_td_vmcall, this function takes a mutable reference of a
99
// TdcallArgs structure to ensure the input is valid
100
//
101
// ## TDVMCALL ABI
102
// Defined in GHCI Spec section 'TDCALL [TDG.VP.VMCALL] leaf'
103
//
104
// ### Input Operands:
105
// * RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL)
106
// * RCX - A bitmap that controls which part of guest TD GPR is exposed to VMM.
107
// * R10 - Set to 0 indicates leaf-function used in R11 is defined in standard GHCI Spec.
108
// * R11 - TDG.VP.VMCALL sub-function is R10 is zero
109
// * RBX, RBP, RDI, RSI, R8-R10, R12-R15 - Used to pass values to VMM in sub-functions.
110
//
111
// ### Output Operands:
112
// * RAX - TDCALL instruction return code, always return Success(0).
113
// * R10 - TDG.VP.VMCALL sub-function return value
114
// * R11 - Correspond to each TDG.VP.VMCALL.
115
// * R8-R9, R12-R15, RBX, RBP, RDI, RSI - Correspond to each TDG.VP.VMCALL sub-function.
116
//
117
#[cfg(not(feature = "no-tdvmcall"))]
118
0
pub fn td_vmcall(args: &mut TdVmcallArgs) -> u64 {
119
0
    unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, 0) }
120
0
}
121
122
// An extended public wrapper for use of asm_td_vmcall.
123
//
124
// `do_sti` is a flag used to determine whether to execute `sti` instruction before `tdcall`
125
#[cfg(not(feature = "no-tdvmcall"))]
126
0
pub fn td_vmcall_ex(args: &mut TdVmcallArgs, do_sti: bool) -> u64 {
127
0
    unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, do_sti as u64) }
128
0
}
129
130
// An extended public wrapper for use of asm_td_vmcall_ex.
131
//
132
// `do_sti` is a flag used to determine whether to execute `sti` instruction before `tdcall`
133
#[cfg(not(feature = "no-tdvmcall"))]
134
0
pub fn td_vmcall_ex2(args: &mut TdVmcallArgsEx, do_sti: bool) -> u64 {
135
0
    unsafe { asm::asm_td_vmcall_ex(args as *mut TdVmcallArgsEx as *mut c_void, do_sti as u64) }
136
0
}
137
138
// Wrapper for use of asm_td_call, this function takes a mutable reference of a
139
// TdVmcallArgs structure to ensure the input is valid
140
//
141
// ## TDCALL ABI
142
// Defined in TDX Module 1.0 Spec section 'TDCALL Instruction (Common)'
143
//
144
// ### Input Operands:
145
//  * RAX - Leaf and version numbers.
146
//  * Other - Used by leaf functions as input values.
147
//
148
// ### Output Operands:
149
//  * RAX - Instruction return code.
150
//  * Other - Used by leaf functions as output values.
151
//
152
0
pub fn td_call(args: &mut TdcallArgs) -> u64 {
153
0
    unsafe { asm::asm_td_call(args as *mut TdcallArgs as *mut c_void) }
154
0
}
155
156
// Used to pass the values of input/output register when performing TDVMCALL
157
// instruction
158
#[repr(C)]
159
#[derive(Default)]
160
pub struct TdcallArgs {
161
    pub rax: u64,
162
    pub rcx: u64,
163
    pub rdx: u64,
164
    pub r8: u64,
165
    pub r9: u64,
166
    pub r10: u64,
167
    pub r11: u64,
168
    pub r12: u64,
169
    pub r13: u64,
170
    pub r14: u64,
171
}
172
173
// Used to pass the values of input/output register when performing TDVMCALL
174
// instruction
175
#[cfg(not(feature = "no-tdvmcall"))]
176
#[repr(C)]
177
#[derive(Default)]
178
pub struct TdVmcallArgs {
179
    // Input: Always 0 for  (standard VMCALL)
180
    // Output: Sub-function
181
    pub r10: u64,
182
    pub r11: u64,
183
    pub r12: u64,
184
    pub r13: u64,
185
    pub r14: u64,
186
    pub r15: u64,
187
}
188
189
// Used to pass the values of input/output register when performing TDVMCALL
190
// instruction
191
#[cfg(not(feature = "no-tdvmcall"))]
192
#[repr(C)]
193
#[derive(Default)]
194
pub struct TdVmcallArgsEx {
195
    // Input: Always 0 for  (standard VMCALL)
196
    // Output: Sub-function
197
    pub rdx: u64,
198
    pub rbx: u64,
199
    pub rsi: u64,
200
    pub rdi: u64,
201
    pub r8: u64,
202
    pub r9: u64,
203
    pub r10: u64,
204
    pub r11: u64,
205
    pub r12: u64,
206
    pub r13: u64,
207
    pub r14: u64,
208
    pub r15: u64,
209
}
210
211
/// TDCALL instruction return error code
212
///
213
/// Refer to Intel TDX Module 1.0 Specifiction section 'TDCALL Instruction (Common)'
214
#[derive(Debug, PartialEq)]
215
pub enum TdCallError {
216
    // Invalid parameters
217
    TdxExitInvalidParameters,
218
219
    // The operand is busy (e.g., it is locked in Exclusive mode)
220
    TdxExitReasonOperandBusy(u32),
221
222
    // Operand is invalid (e.g., illegal leaf number)
223
    TdxExitReasonOperandInvalid(u32),
224
225
    // Error code defined by individual leaf function
226
    LeafSpecific(u64),
227
}
228
229
// TDCALL Completion Status Codes (Returned in RAX) Definition
230
impl From<u64> for TdCallError {
231
0
    fn from(val: u64) -> Self {
232
0
        match val >> 32 {
233
0
            0x8000_0200 => Self::TdxExitReasonOperandBusy(val as u32),
234
0
            0xC000_0100 => Self::TdxExitReasonOperandInvalid(val as u32),
235
0
            _ => Self::LeafSpecific(val),
236
        }
237
0
    }
238
}
239
240
/// TDVMCALL sub-function return error code
241
///
242
/// Refer to Guest-Host-Communication-Interface(GHCI) for Intel TDX
243
/// table 'TDCALL[TDG.VP.VMCALL]- Sub-function Completion-Status Codes'
244
#[cfg(not(feature = "no-tdvmcall"))]
245
#[derive(Debug, PartialEq)]
246
pub enum TdVmcallError {
247
    // TDCALL[TDG.VP.VMCALL] sub-function invocation must be retried
248
    VmcallRetry,
249
250
    // Invalid operand to TDG.VP.VMCALL sub-function
251
    VmcallOperandInvalid,
252
253
    // GPA already mapped
254
    VmcallGpaInuse,
255
256
    // Operand (address) alignment error
257
    VmcallAlignError,
258
259
    Other,
260
}
261
262
#[cfg(not(feature = "no-tdvmcall"))]
263
impl From<u64> for TdVmcallError {
264
0
    fn from(val: u64) -> Self {
265
0
        match val {
266
0
            0x1 => TdVmcallError::VmcallRetry,
267
0
            0x8000_0000_0000_0000 => TdVmcallError::VmcallOperandInvalid,
268
0
            0x8000_0000_0000_0001 => TdVmcallError::VmcallGpaInuse,
269
0
            0x8000_0000_0000_0002 => TdVmcallError::VmcallAlignError,
270
0
            _ => TdVmcallError::Other,
271
        }
272
0
    }
273
}